386 lines
8.0 KiB
Elixir
386 lines
8.0 KiB
Elixir
defmodule Odinsea.Constants.Game do
|
|
@moduledoc """
|
|
Game constants ported from Java GameConstants.
|
|
These define gameplay mechanics, limits, and rates.
|
|
"""
|
|
|
|
# Character limits
|
|
@max_level 250
|
|
@max_ap 999
|
|
@max_hp_mp 999_999
|
|
@base_max_hp 50
|
|
@base_max_mp 50
|
|
|
|
# Inventory limits
|
|
@max_inventory_slots 128
|
|
@equip_slots 96
|
|
@use_slots 96
|
|
@setup_slots 96
|
|
@etc_slots 96
|
|
@cash_slots 96
|
|
|
|
# Meso limits
|
|
@max_meso 9_999_999_999
|
|
@max_storage_meso 9_999_999_999
|
|
|
|
# Guild limits
|
|
@max_guild_name_length 12
|
|
@max_guild_members 100
|
|
|
|
# Party limits
|
|
@max_party_members 6
|
|
@max_expedition_members 30
|
|
|
|
# GMS specific flag
|
|
@gms true
|
|
|
|
@doc """
|
|
Returns the maximum character level.
|
|
"""
|
|
def max_level, do: @max_level
|
|
|
|
@doc """
|
|
Returns the maximum AP.
|
|
"""
|
|
def max_ap, do: @max_ap
|
|
|
|
@doc """
|
|
Returns the maximum HP/MP.
|
|
"""
|
|
def max_hp_mp, do: @max_hp_mp
|
|
|
|
@doc """
|
|
Returns the base max HP for new characters.
|
|
"""
|
|
def base_max_hp, do: @base_max_hp
|
|
|
|
@doc """
|
|
Returns the base max MP for new characters.
|
|
"""
|
|
def base_max_mp, do: @base_max_mp
|
|
|
|
@doc """
|
|
Returns the max inventory slots per type.
|
|
"""
|
|
def max_inventory_slots, do: @max_inventory_slots
|
|
|
|
def equip_slots, do: @equip_slots
|
|
def use_slots, do: @use_slots
|
|
def setup_slots, do: @setup_slots
|
|
def etc_slots, do: @etc_slots
|
|
def cash_slots, do: @cash_slots
|
|
|
|
@doc """
|
|
Returns the max meso a character can hold.
|
|
"""
|
|
def max_meso, do: @max_meso
|
|
|
|
@doc """
|
|
Returns the max meso in storage.
|
|
"""
|
|
def max_storage_meso, do: @max_storage_meso
|
|
|
|
@doc """
|
|
Returns true if this is a GMS server.
|
|
"""
|
|
def gms?, do: @gms
|
|
|
|
@doc """
|
|
Returns the rates from configuration.
|
|
"""
|
|
def rates do
|
|
Application.get_env(:odinsea, :rates, [])
|
|
end
|
|
|
|
@doc """
|
|
Returns the EXP rate.
|
|
"""
|
|
def exp_rate do
|
|
rates()[:exp] || 1
|
|
end
|
|
|
|
@doc """
|
|
Returns the meso rate.
|
|
"""
|
|
def meso_rate do
|
|
rates()[:meso] || 1
|
|
end
|
|
|
|
@doc """
|
|
Returns the drop rate.
|
|
"""
|
|
def drop_rate do
|
|
rates()[:drop] || 1
|
|
end
|
|
|
|
# Job classification helpers
|
|
|
|
@doc """
|
|
Returns true if the job is a beginner job.
|
|
"""
|
|
def beginner?(job), do: div(job, 1000) == 0 && rem(job, 100) == 0
|
|
|
|
@doc """
|
|
Returns true if the job is a warrior class.
|
|
"""
|
|
def warrior?(job), do: div(job, 100) == 1
|
|
|
|
@doc """
|
|
Returns true if the job is a magician class.
|
|
"""
|
|
def magician?(job), do: div(job, 100) == 2
|
|
|
|
@doc """
|
|
Returns true if the job is a bowman class.
|
|
"""
|
|
def bowman?(job), do: div(job, 100) == 3
|
|
|
|
@doc """
|
|
Returns true if the job is a thief class.
|
|
"""
|
|
def thief?(job), do: div(job, 100) == 4
|
|
|
|
@doc """
|
|
Returns true if the job is a pirate class.
|
|
"""
|
|
def pirate?(job), do: div(job, 100) == 5 || div(job, 100) == 51 || div(job, 100) == 52
|
|
|
|
@doc """
|
|
Returns true if the job is a resistance class.
|
|
"""
|
|
def resistance?(job), do: div(job, 1000) == 3
|
|
|
|
@doc """
|
|
Returns true if the job is a cygnus class.
|
|
"""
|
|
def cygnus?(job), do: div(job, 1000) == 1
|
|
|
|
@doc """
|
|
Returns true if the job is an aran.
|
|
"""
|
|
def aran?(job), do: div(job, 100) == 21
|
|
|
|
@doc """
|
|
Returns true if the job is an evan.
|
|
"""
|
|
def evan?(job), do: div(job, 100) == 22 || job == 2001
|
|
|
|
@doc """
|
|
Returns the job name for a given job ID.
|
|
"""
|
|
def job_name(job) do
|
|
case job do
|
|
0 -> "Beginner"
|
|
100 -> "Warrior"
|
|
110 -> "Fighter"
|
|
120 -> "Page"
|
|
130 -> "Spearman"
|
|
111 -> "Crusader"
|
|
121 -> "Knight"
|
|
131 -> "Dragon Knight"
|
|
112 -> "Hero"
|
|
122 -> "Paladin"
|
|
132 -> "Dark Knight"
|
|
200 -> "Magician"
|
|
210 -> "Wizard (F/P)"
|
|
220 -> "Wizard (I/L)"
|
|
230 -> "Cleric"
|
|
211 -> "Mage (F/P)"
|
|
221 -> "Mage (I/L)"
|
|
231 -> "Bishop"
|
|
212 -> "Arch Mage (F/P)"
|
|
222 -> "Arch Mage (I/L)"
|
|
232 -> "Arch Mage"
|
|
300 -> "Bowman"
|
|
310 -> "Hunter"
|
|
320 -> "Crossbowman"
|
|
311 -> "Ranger"
|
|
321 -> "Sniper"
|
|
312 -> "Bowmaster"
|
|
322 -> "Marksman"
|
|
400 -> "Thief"
|
|
410 -> "Assassin"
|
|
420 -> "Bandit"
|
|
411 -> "Hermit"
|
|
421 -> "Chief Bandit"
|
|
412 -> "Night Lord"
|
|
422 -> "Shadower"
|
|
500 -> "Pirate"
|
|
510 -> "Brawler"
|
|
520 -> "Gunslinger"
|
|
511 -> "Marauder"
|
|
521 -> "Outlaw"
|
|
512 -> "Buccaneer"
|
|
522 -> "Corsair"
|
|
1000 -> "Noblesse"
|
|
1100 -> "Dawn Warrior"
|
|
1200 -> "Blaze Wizard"
|
|
1300 -> "Wind Archer"
|
|
1400 -> "Night Walker"
|
|
1500 -> "Thunder Breaker"
|
|
2000 -> "Legend"
|
|
2100 -> "Aran"
|
|
2001 -> "Evan"
|
|
2002 -> "Mercedes"
|
|
_ -> "Unknown"
|
|
end
|
|
end
|
|
|
|
# =============================================================================
|
|
# Skill & Attack Constants (for Anti-Cheat)
|
|
# =============================================================================
|
|
|
|
@doc """
|
|
Returns the attack delay for a skill (in ticks).
|
|
Used for speed hack detection.
|
|
"""
|
|
def get_attack_delay(skill_id) do
|
|
if skill_id == 0 do
|
|
# Normal attack delay
|
|
300
|
|
else
|
|
# Get from skill data or use default
|
|
get_skill_delay(skill_id) || 300
|
|
end
|
|
end
|
|
|
|
@doc """
|
|
Returns the skill damage percentage.
|
|
"""
|
|
def get_skill_damage(skill_id) do
|
|
# Default skill damage, would be loaded from WZ in production
|
|
case skill_id do
|
|
0 -> 100
|
|
# Common skills
|
|
1000 -> 40
|
|
1009 -> 3000
|
|
1020 -> 1
|
|
# Warrior
|
|
1001004 -> 150
|
|
1001005 -> 200
|
|
1101006 -> 180
|
|
# Mage
|
|
2001008 -> 120
|
|
2101004 -> 130
|
|
2201004 -> 130
|
|
# Bowman
|
|
3101005 -> 150
|
|
3201005 -> 150
|
|
# Thief
|
|
4001334 -> 130
|
|
4101005 -> 140
|
|
4201005 -> 140
|
|
# Pirate
|
|
5001002 -> 160
|
|
5101004 -> 150
|
|
5201004 -> 150
|
|
# Aran
|
|
21000002 -> 180
|
|
21100001 -> 190
|
|
_ -> 100
|
|
end
|
|
end
|
|
|
|
@doc """
|
|
Returns the attack range for a skill.
|
|
"""
|
|
def get_attack_range(skill_id) do
|
|
case skill_id do
|
|
0 -> 100
|
|
# Ranged skills
|
|
3101005 -> 500
|
|
3201005 -> 500
|
|
4001334 -> 250
|
|
4101005 -> 250
|
|
4121007 -> 300
|
|
4201005 -> 150
|
|
4221007 -> 600
|
|
# Melee skills
|
|
_ -> 150
|
|
end
|
|
end
|
|
|
|
@doc """
|
|
Returns true if skill is a Mu Lung Dojo skill.
|
|
"""
|
|
def is_mulung_skill?(skill_id) do
|
|
skill_id >= 10001000 && skill_id < 10002000
|
|
end
|
|
|
|
@doc """
|
|
Returns true if skill is a Pyramid skill.
|
|
"""
|
|
def is_pyramid_skill?(skill_id) do
|
|
skill_id >= 1020 && skill_id <= 1022
|
|
end
|
|
|
|
@doc """
|
|
Returns true if skill has no delay.
|
|
"""
|
|
def is_no_delay_skill?(skill_id) do
|
|
# Skills that bypass attack delay checks
|
|
skill_id in [3101005, 1009, 1020]
|
|
end
|
|
|
|
@doc """
|
|
Returns true if skill is a magic charge skill.
|
|
"""
|
|
def is_magic_charge_skill?(skill_id) do
|
|
skill_id in [2121001, 2221001, 2321001]
|
|
end
|
|
|
|
@doc """
|
|
Returns true if skill is an event skill.
|
|
"""
|
|
def is_event_skill?(skill_id) do
|
|
# Skills only usable in specific event maps
|
|
skill_id >= 90001000 && skill_id < 90002000
|
|
end
|
|
|
|
@doc """
|
|
Returns the linked Aran skill (for skill linking).
|
|
"""
|
|
def get_linked_aran_skill(skill_id) do
|
|
# Handle Aran skill linking
|
|
if div(skill_id, 10000) == 21 do
|
|
# Convert Aran skills to regular warrior equivalents for linking
|
|
base = rem(skill_id, 10000)
|
|
cond do
|
|
base == 1005 -> 1101005
|
|
base == 1004 -> 1101006
|
|
true -> skill_id
|
|
end
|
|
else
|
|
skill_id
|
|
end
|
|
end
|
|
|
|
# =============================================================================
|
|
# Private Helpers
|
|
# =============================================================================
|
|
|
|
defp get_skill_delay(skill_id) do
|
|
case skill_id do
|
|
0 -> 300
|
|
1000 -> 600
|
|
1004 -> 600
|
|
1005 -> 900
|
|
1001004 -> 960
|
|
1001005 -> 1260
|
|
1101006 -> 1050
|
|
2001008 -> 810
|
|
2101004 -> 810
|
|
2201004 -> 810
|
|
3101005 -> 840
|
|
3201005 -> 840
|
|
4001334 -> 600
|
|
4101005 -> 720
|
|
4201005 -> 720
|
|
5001002 -> 600
|
|
5101004 -> 660
|
|
5201004 -> 660
|
|
_ -> nil
|
|
end
|
|
end
|
|
end
|