kimi gone wild
This commit is contained in:
741
lib/odinsea/game/stat_effect.ex
Normal file
741
lib/odinsea/game/stat_effect.ex
Normal file
@@ -0,0 +1,741 @@
|
||||
defmodule Odinsea.Game.StatEffect do
|
||||
@moduledoc """
|
||||
StatEffect struct for skill and item effects.
|
||||
|
||||
Ported from Java: server/MapleStatEffect.java
|
||||
|
||||
StatEffects define what happens when a skill or item is used:
|
||||
- Stat changes (WATK, WDEF, MATK, MDEF, etc.)
|
||||
- HP/MP changes
|
||||
- Buffs and debuffs
|
||||
- Monster status effects
|
||||
- Cooldowns and durations
|
||||
"""
|
||||
|
||||
alias Odinsea.Game.MonsterStatus
|
||||
|
||||
defstruct [
|
||||
# Basic info
|
||||
:source_id,
|
||||
:level,
|
||||
:is_skill,
|
||||
:duration,
|
||||
:over_time,
|
||||
|
||||
# HP/MP
|
||||
:hp,
|
||||
:mp,
|
||||
:hp_r,
|
||||
:mp_r,
|
||||
:mhp_r,
|
||||
:mmp_r,
|
||||
|
||||
# Combat stats
|
||||
:watk,
|
||||
:wdef,
|
||||
:matk,
|
||||
:mdef,
|
||||
:acc,
|
||||
:avoid,
|
||||
:hands,
|
||||
:speed,
|
||||
:jump,
|
||||
:mastery,
|
||||
|
||||
# Damage modifiers
|
||||
:damage,
|
||||
:pdd_r,
|
||||
:mdd_r,
|
||||
:dam_r,
|
||||
:bd_r,
|
||||
:ignore_mob,
|
||||
:critical_damage_min,
|
||||
:critical_damage_max,
|
||||
:asr_r,
|
||||
:er,
|
||||
|
||||
# Skill-specific
|
||||
:prop,
|
||||
:mob_count,
|
||||
:attack_count,
|
||||
:bullet_count,
|
||||
:cooldown,
|
||||
:interval,
|
||||
|
||||
# MP/HP consumption
|
||||
:mp_con,
|
||||
:hp_con,
|
||||
:force_con,
|
||||
:mp_con_reduce,
|
||||
|
||||
# Movement
|
||||
:move_to,
|
||||
|
||||
# Morph
|
||||
:morph_id,
|
||||
|
||||
# Summon
|
||||
:summon_movement_type,
|
||||
|
||||
# DoT (Damage over Time)
|
||||
:dot,
|
||||
:dot_time,
|
||||
|
||||
# Special effects
|
||||
:thaw,
|
||||
:self_destruction,
|
||||
:pvp_damage,
|
||||
:inc_pvp_damage,
|
||||
|
||||
# Independent stats (angel buffs)
|
||||
:indie_pad,
|
||||
:indie_mad,
|
||||
:indie_mhp,
|
||||
:indie_mmp,
|
||||
:indie_speed,
|
||||
:indie_jump,
|
||||
:indie_acc,
|
||||
:indie_eva,
|
||||
:indie_pdd,
|
||||
:indie_mdd,
|
||||
:indie_all_stat,
|
||||
|
||||
# Base stats
|
||||
:str,
|
||||
:dex,
|
||||
:int,
|
||||
:luk,
|
||||
:str_x,
|
||||
:dex_x,
|
||||
:int_x,
|
||||
:luk_x,
|
||||
|
||||
# Enhanced stats
|
||||
:ehp,
|
||||
:emp,
|
||||
:ewatk,
|
||||
:ewdef,
|
||||
:emdef,
|
||||
|
||||
# Misc
|
||||
:pad_x,
|
||||
:mad_x,
|
||||
:meso_r,
|
||||
:exp_r,
|
||||
|
||||
# Item consumption
|
||||
:item_con,
|
||||
:item_con_no,
|
||||
:bullet_consume,
|
||||
:money_con,
|
||||
|
||||
# Position/Range
|
||||
:lt,
|
||||
:rb,
|
||||
:range,
|
||||
|
||||
# Buff stats (map of CharacterTemporaryStat => value)
|
||||
:stat_ups,
|
||||
|
||||
# Monster status effects
|
||||
:monster_status,
|
||||
|
||||
# Cure debuffs
|
||||
:cure_debuffs,
|
||||
|
||||
# Other
|
||||
:expinc,
|
||||
:exp_buff,
|
||||
:itemup,
|
||||
:mesoup,
|
||||
:cashup,
|
||||
:berserk,
|
||||
:berserk2,
|
||||
:booster,
|
||||
:illusion,
|
||||
:life_id,
|
||||
:inflation,
|
||||
:imhp,
|
||||
:immp,
|
||||
:use_level,
|
||||
:char_color,
|
||||
:recipe,
|
||||
:recipe_use_count,
|
||||
:recipe_valid_day,
|
||||
:req_skill_level,
|
||||
:slot_count,
|
||||
:preventslip,
|
||||
:immortal,
|
||||
:type,
|
||||
:bs,
|
||||
:cr,
|
||||
:t,
|
||||
:u,
|
||||
:v,
|
||||
:w,
|
||||
:x,
|
||||
:y,
|
||||
:z,
|
||||
:mob_skill,
|
||||
:mob_skill_level,
|
||||
:familiar_target,
|
||||
:fatigue_change,
|
||||
:available_maps,
|
||||
:reward_meso,
|
||||
:reward_items,
|
||||
:pets_can_consume,
|
||||
:familiars,
|
||||
:random_pickup,
|
||||
:traits,
|
||||
:party_buff
|
||||
]
|
||||
|
||||
@type point :: {integer(), integer()}
|
||||
|
||||
@type t :: %__MODULE__{
|
||||
source_id: integer(),
|
||||
level: integer(),
|
||||
is_skill: boolean(),
|
||||
duration: integer(),
|
||||
over_time: boolean(),
|
||||
hp: integer(),
|
||||
mp: integer(),
|
||||
hp_r: float(),
|
||||
mp_r: float(),
|
||||
mhp_r: integer(),
|
||||
mmp_r: integer(),
|
||||
watk: integer(),
|
||||
wdef: integer(),
|
||||
matk: integer(),
|
||||
mdef: integer(),
|
||||
acc: integer(),
|
||||
avoid: integer(),
|
||||
hands: integer(),
|
||||
speed: integer(),
|
||||
jump: integer(),
|
||||
mastery: integer(),
|
||||
damage: integer(),
|
||||
pdd_r: integer(),
|
||||
mdd_r: integer(),
|
||||
dam_r: integer(),
|
||||
bd_r: integer(),
|
||||
ignore_mob: integer(),
|
||||
critical_damage_min: integer(),
|
||||
critical_damage_max: integer(),
|
||||
asr_r: integer(),
|
||||
er: integer(),
|
||||
prop: integer(),
|
||||
mob_count: integer(),
|
||||
attack_count: integer(),
|
||||
bullet_count: integer(),
|
||||
cooldown: integer(),
|
||||
interval: integer(),
|
||||
mp_con: integer(),
|
||||
hp_con: integer(),
|
||||
force_con: integer(),
|
||||
mp_con_reduce: integer(),
|
||||
move_to: integer(),
|
||||
morph_id: integer(),
|
||||
summon_movement_type: atom() | nil,
|
||||
dot: integer(),
|
||||
dot_time: integer(),
|
||||
thaw: integer(),
|
||||
self_destruction: integer(),
|
||||
pvp_damage: integer(),
|
||||
inc_pvp_damage: integer(),
|
||||
indie_pad: integer(),
|
||||
indie_mad: integer(),
|
||||
indie_mhp: integer(),
|
||||
indie_mmp: integer(),
|
||||
indie_speed: integer(),
|
||||
indie_jump: integer(),
|
||||
indie_acc: integer(),
|
||||
indie_eva: integer(),
|
||||
indie_pdd: integer(),
|
||||
indie_mdd: integer(),
|
||||
indie_all_stat: integer(),
|
||||
str: integer(),
|
||||
dex: integer(),
|
||||
int: integer(),
|
||||
luk: integer(),
|
||||
str_x: integer(),
|
||||
dex_x: integer(),
|
||||
int_x: integer(),
|
||||
luk_x: integer(),
|
||||
ehp: integer(),
|
||||
emp: integer(),
|
||||
ewatk: integer(),
|
||||
ewdef: integer(),
|
||||
emdef: integer(),
|
||||
pad_x: integer(),
|
||||
mad_x: integer(),
|
||||
meso_r: integer(),
|
||||
exp_r: integer(),
|
||||
item_con: integer(),
|
||||
item_con_no: integer(),
|
||||
bullet_consume: integer(),
|
||||
money_con: integer(),
|
||||
lt: point() | nil,
|
||||
rb: point() | nil,
|
||||
range: integer(),
|
||||
stat_ups: map(),
|
||||
monster_status: map(),
|
||||
cure_debuffs: [atom()],
|
||||
expinc: integer(),
|
||||
exp_buff: integer(),
|
||||
itemup: integer(),
|
||||
mesoup: integer(),
|
||||
cashup: integer(),
|
||||
berserk: integer(),
|
||||
berserk2: integer(),
|
||||
booster: integer(),
|
||||
illusion: integer(),
|
||||
life_id: integer(),
|
||||
inflation: integer(),
|
||||
imhp: integer(),
|
||||
immp: integer(),
|
||||
use_level: integer(),
|
||||
char_color: integer(),
|
||||
recipe: integer(),
|
||||
recipe_use_count: integer(),
|
||||
recipe_valid_day: integer(),
|
||||
req_skill_level: integer(),
|
||||
slot_count: integer(),
|
||||
preventslip: integer(),
|
||||
immortal: integer(),
|
||||
type: integer(),
|
||||
bs: integer(),
|
||||
cr: integer(),
|
||||
t: integer(),
|
||||
u: integer(),
|
||||
v: integer(),
|
||||
w: integer(),
|
||||
x: integer(),
|
||||
y: integer(),
|
||||
z: integer(),
|
||||
mob_skill: integer(),
|
||||
mob_skill_level: integer(),
|
||||
familiar_target: integer(),
|
||||
fatigue_change: integer(),
|
||||
available_maps: [{integer(), integer()}],
|
||||
reward_meso: integer(),
|
||||
reward_items: [{integer(), integer(), integer()}],
|
||||
pets_can_consume: [integer()],
|
||||
familiars: [integer()],
|
||||
random_pickup: [integer()],
|
||||
traits: map(),
|
||||
party_buff: boolean()
|
||||
}
|
||||
|
||||
@doc """
|
||||
Creates a new StatEffect with default values.
|
||||
"""
|
||||
@spec new(integer(), integer(), boolean()) :: t()
|
||||
def new(source_id, level, is_skill) do
|
||||
%__MODULE__{
|
||||
source_id: source_id,
|
||||
level: level,
|
||||
is_skill: is_skill,
|
||||
duration: -1,
|
||||
over_time: false,
|
||||
hp: 0,
|
||||
mp: 0,
|
||||
hp_r: 0.0,
|
||||
mp_r: 0.0,
|
||||
mhp_r: 0,
|
||||
mmp_r: 0,
|
||||
watk: 0,
|
||||
wdef: 0,
|
||||
matk: 0,
|
||||
mdef: 0,
|
||||
acc: 0,
|
||||
avoid: 0,
|
||||
hands: 0,
|
||||
speed: 0,
|
||||
jump: 0,
|
||||
mastery: 0,
|
||||
damage: 100,
|
||||
pdd_r: 0,
|
||||
mdd_r: 0,
|
||||
dam_r: 0,
|
||||
bd_r: 0,
|
||||
ignore_mob: 0,
|
||||
critical_damage_min: 0,
|
||||
critical_damage_max: 0,
|
||||
asr_r: 0,
|
||||
er: 0,
|
||||
prop: 100,
|
||||
mob_count: 1,
|
||||
attack_count: 1,
|
||||
bullet_count: 1,
|
||||
cooldown: 0,
|
||||
interval: 0,
|
||||
mp_con: 0,
|
||||
hp_con: 0,
|
||||
force_con: 0,
|
||||
mp_con_reduce: 0,
|
||||
move_to: -1,
|
||||
morph_id: 0,
|
||||
summon_movement_type: nil,
|
||||
dot: 0,
|
||||
dot_time: 0,
|
||||
thaw: 0,
|
||||
self_destruction: 0,
|
||||
pvp_damage: 0,
|
||||
inc_pvp_damage: 0,
|
||||
indie_pad: 0,
|
||||
indie_mad: 0,
|
||||
indie_mhp: 0,
|
||||
indie_mmp: 0,
|
||||
indie_speed: 0,
|
||||
indie_jump: 0,
|
||||
indie_acc: 0,
|
||||
indie_eva: 0,
|
||||
indie_pdd: 0,
|
||||
indie_mdd: 0,
|
||||
indie_all_stat: 0,
|
||||
str: 0,
|
||||
dex: 0,
|
||||
int: 0,
|
||||
luk: 0,
|
||||
str_x: 0,
|
||||
dex_x: 0,
|
||||
int_x: 0,
|
||||
luk_x: 0,
|
||||
ehp: 0,
|
||||
emp: 0,
|
||||
ewatk: 0,
|
||||
ewdef: 0,
|
||||
emdef: 0,
|
||||
pad_x: 0,
|
||||
mad_x: 0,
|
||||
meso_r: 0,
|
||||
exp_r: 0,
|
||||
item_con: 0,
|
||||
item_con_no: 0,
|
||||
bullet_consume: 0,
|
||||
money_con: 0,
|
||||
lt: nil,
|
||||
rb: nil,
|
||||
range: 0,
|
||||
stat_ups: %{},
|
||||
monster_status: %{},
|
||||
cure_debuffs: [],
|
||||
expinc: 0,
|
||||
exp_buff: 0,
|
||||
itemup: 0,
|
||||
mesoup: 0,
|
||||
cashup: 0,
|
||||
berserk: 0,
|
||||
berserk2: 0,
|
||||
booster: 0,
|
||||
illusion: 0,
|
||||
life_id: 0,
|
||||
inflation: 0,
|
||||
imhp: 0,
|
||||
immp: 0,
|
||||
use_level: 0,
|
||||
char_color: 0,
|
||||
recipe: 0,
|
||||
recipe_use_count: 0,
|
||||
recipe_valid_day: 0,
|
||||
req_skill_level: 0,
|
||||
slot_count: 0,
|
||||
preventslip: 0,
|
||||
immortal: 0,
|
||||
type: 0,
|
||||
bs: 0,
|
||||
cr: 0,
|
||||
t: 0,
|
||||
u: 0,
|
||||
v: 0,
|
||||
w: 0,
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0,
|
||||
mob_skill: 0,
|
||||
mob_skill_level: 0,
|
||||
familiar_target: 0,
|
||||
fatigue_change: 0,
|
||||
available_maps: [],
|
||||
reward_meso: 0,
|
||||
reward_items: [],
|
||||
pets_can_consume: [],
|
||||
familiars: [],
|
||||
random_pickup: [],
|
||||
traits: %{},
|
||||
party_buff: true
|
||||
}
|
||||
end
|
||||
|
||||
@doc """
|
||||
Checks if this effect has a cooldown.
|
||||
"""
|
||||
@spec has_cooldown?(t()) :: boolean()
|
||||
def has_cooldown?(effect) do
|
||||
effect.cooldown > 0
|
||||
end
|
||||
|
||||
@doc """
|
||||
Checks if this is a heal effect.
|
||||
"""
|
||||
@spec is_heal?(t()) :: boolean()
|
||||
def is_heal?(effect) do
|
||||
effect.source_id in [2_301_002, 9_101_002, 9_101_004]
|
||||
end
|
||||
|
||||
@doc """
|
||||
Checks if this is a resurrection effect.
|
||||
"""
|
||||
@spec is_resurrection?(t()) :: boolean()
|
||||
def is_resurrection?(effect) do
|
||||
effect.source_id == 2_321_006
|
||||
end
|
||||
|
||||
@doc """
|
||||
Checks if this is a dispel effect.
|
||||
"""
|
||||
@spec is_dispel?(t()) :: boolean()
|
||||
def is_dispel?(effect) do
|
||||
effect.source_id == 2_311_001
|
||||
end
|
||||
|
||||
@doc """
|
||||
Checks if this is a hero's will effect.
|
||||
"""
|
||||
@spec is_hero_will?(t()) :: boolean()
|
||||
def is_hero_will?(effect) do
|
||||
effect.source_id in [1_121_004, 1_221_004, 1_321_004, 2_122_004, 2_222_004,
|
||||
2_322_004, 3_122_004, 4_122_004, 4_222_004, 5_122_004,
|
||||
5_222_004, 2_217_004, 4_341_000, 3_221_007, 3_321_007]
|
||||
end
|
||||
|
||||
@doc """
|
||||
Checks if this is a time leap effect.
|
||||
"""
|
||||
@spec is_time_leap?(t()) :: boolean()
|
||||
def is_time_leap?(effect) do
|
||||
effect.source_id == 5_121_010
|
||||
end
|
||||
|
||||
@doc """
|
||||
Checks if this is a mist effect.
|
||||
"""
|
||||
@spec is_mist?(t()) :: boolean()
|
||||
def is_mist?(effect) do
|
||||
effect.source_id in [2_111_003, 2_211_003, 1_211_005]
|
||||
end
|
||||
|
||||
@doc """
|
||||
Checks if this is a magic door effect.
|
||||
"""
|
||||
@spec is_magic_door?(t()) :: boolean()
|
||||
def is_magic_door?(effect) do
|
||||
effect.source_id == 2_311_002
|
||||
end
|
||||
|
||||
@doc """
|
||||
Checks if this is a poison effect.
|
||||
"""
|
||||
@spec is_poison?(t()) :: boolean()
|
||||
def is_poison?(effect) do
|
||||
effect.dot > 0 and effect.dot_time > 0
|
||||
end
|
||||
|
||||
@doc """
|
||||
Checks if this is a morph effect.
|
||||
"""
|
||||
@spec is_morph?(t()) :: boolean()
|
||||
def is_morph?(effect) do
|
||||
effect.morph_id > 0
|
||||
end
|
||||
|
||||
@doc """
|
||||
Checks if this is a final attack effect.
|
||||
"""
|
||||
@spec is_final_attack?(t()) :: boolean()
|
||||
def is_final_attack?(effect) do
|
||||
effect.source_id in [1_100_002, 1_200_002, 1_300_002, 3_100_001, 3_200_001,
|
||||
1_110_002, 1_310_002, 2_111_007, 2_221_007, 2_311_007,
|
||||
3_211_010, 3_310_009, 2_215_004, 2_218_004, 1_120_013,
|
||||
3_120_008, 2_310_006, 2_312_012]
|
||||
end
|
||||
|
||||
@doc """
|
||||
Checks if this is an energy charge effect.
|
||||
"""
|
||||
@spec is_energy_charge?(t()) :: boolean()
|
||||
def is_energy_charge?(effect) do
|
||||
effect.source_id in [5_110_001, 1_510_004]
|
||||
end
|
||||
|
||||
@doc """
|
||||
Checks if this effect makes the player invisible.
|
||||
"""
|
||||
@spec is_hide?(t()) :: boolean()
|
||||
def is_hide?(effect) do
|
||||
effect.source_id in [9_101_004, 9_001_004, 4_330_001]
|
||||
end
|
||||
|
||||
@doc """
|
||||
Checks if this is a shadow partner effect.
|
||||
"""
|
||||
@spec is_shadow_partner?(t()) :: boolean()
|
||||
def is_shadow_partner?(effect) do
|
||||
effect.source_id in [4_111_002, 1_411_000, 4_331_002, 4_211_008]
|
||||
end
|
||||
|
||||
@doc """
|
||||
Checks if this is a combo recharge effect.
|
||||
"""
|
||||
@spec is_combo_recharge?(t()) :: boolean()
|
||||
def is_combo_recharge?(effect) do
|
||||
effect.source_id == 2_111_009
|
||||
end
|
||||
|
||||
@doc """
|
||||
Checks if this is a spirit claw effect.
|
||||
"""
|
||||
@spec is_spirit_claw?(t()) :: boolean()
|
||||
def is_spirit_claw?(effect) do
|
||||
effect.source_id == 4_121_006
|
||||
end
|
||||
|
||||
@doc """
|
||||
Checks if this is a Mech door effect.
|
||||
"""
|
||||
@spec is_mech_door?(t()) :: boolean()
|
||||
def is_mech_door?(effect) do
|
||||
effect.source_id == 3_511_005
|
||||
end
|
||||
|
||||
@doc """
|
||||
Checks if this is a mist eruption effect.
|
||||
"""
|
||||
@spec is_mist_eruption?(t()) :: boolean()
|
||||
def is_mist_eruption?(effect) do
|
||||
effect.source_id == 2_121_005
|
||||
end
|
||||
|
||||
@doc """
|
||||
Checks if this effect affects monsters.
|
||||
"""
|
||||
@spec is_monster_buff?(t()) :: boolean()
|
||||
def is_monster_buff?(effect) do
|
||||
count = stat_size(effect.monster_status)
|
||||
count > 0
|
||||
end
|
||||
|
||||
@doc """
|
||||
Checks if this is a party buff.
|
||||
"""
|
||||
@spec is_party_buff?(t()) :: boolean()
|
||||
def is_party_buff?(effect) do
|
||||
effect.party_buff
|
||||
end
|
||||
|
||||
@doc """
|
||||
Calculates the bounding box for this effect based on position.
|
||||
"""
|
||||
@spec calculate_bounding_box(t(), {integer(), integer()}, boolean()) ::
|
||||
{{integer(), integer()}, {integer(), integer()}} | nil
|
||||
def calculate_bounding_box(effect, {x, y}, facing_left) do
|
||||
case {effect.lt, effect.rb} do
|
||||
{nil, nil} ->
|
||||
# Default bounding box
|
||||
width = 200 + effect.range
|
||||
height = 100 + effect.range
|
||||
|
||||
if facing_left do
|
||||
{{x - width, y - div(height, 2)}, {x, y + div(height, 2)}}
|
||||
else
|
||||
{{x, y - div(height, 2)}, {x + width, y + div(height, 2)}}
|
||||
end
|
||||
|
||||
{{lt_x, lt_y}, {rb_x, rb_y}} ->
|
||||
if facing_left do
|
||||
{{x + lt_x - effect.range, y + lt_y}, {x + rb_x, y + rb_y}}
|
||||
else
|
||||
{{x - rb_x + effect.range, y + lt_y}, {x - lt_x, y + rb_y}}
|
||||
end
|
||||
|
||||
_ ->
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Makes a chance result check based on the effect's prop value.
|
||||
"""
|
||||
@spec make_chance_result?(t()) :: boolean()
|
||||
def make_chance_result?(effect) do
|
||||
effect.prop >= 100 or :rand.uniform(100) < effect.prop
|
||||
end
|
||||
|
||||
@doc """
|
||||
Gets the summon movement type if this effect summons something.
|
||||
"""
|
||||
@spec get_summon_movement_type(t()) :: atom() | nil
|
||||
def get_summon_movement_type(effect) do
|
||||
effect.summon_movement_type
|
||||
end
|
||||
|
||||
@doc """
|
||||
Gets the total stat change for a specific stat.
|
||||
"""
|
||||
@spec get_stat_change(t(), atom()) :: integer()
|
||||
def get_stat_change(effect, stat) do
|
||||
case stat do
|
||||
:str -> effect.str
|
||||
:dex -> effect.dex
|
||||
:int -> effect.int
|
||||
:luk -> effect.luk
|
||||
:max_hp -> effect.mhp_r
|
||||
:max_mp -> effect.mmp_r
|
||||
:watk -> effect.watk
|
||||
:wdef -> effect.wdef
|
||||
:matk -> effect.matk
|
||||
:mdef -> effect.mdef
|
||||
:acc -> effect.acc
|
||||
:avoid -> effect.avoid
|
||||
:speed -> effect.speed
|
||||
:jump -> effect.jump
|
||||
_ -> 0
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Applies this effect to HP calculation.
|
||||
Returns the HP change (can be negative).
|
||||
"""
|
||||
@spec calc_hp_change(t(), integer(), boolean()) :: integer()
|
||||
def calc_hp_change(effect, max_hp, _primary) do
|
||||
hp_change = effect.hp
|
||||
|
||||
# Apply HP% recovery/consumption
|
||||
hp_change = hp_change + trunc(max_hp * effect.hp_r)
|
||||
|
||||
# Cap recovery to max HP
|
||||
min(hp_change, max_hp)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Applies this effect to MP calculation.
|
||||
Returns the MP change (can be negative).
|
||||
"""
|
||||
@spec calc_mp_change(t(), integer(), boolean()) :: integer()
|
||||
def calc_mp_change(effect, max_mp, _primary) do
|
||||
mp_change = effect.mp
|
||||
|
||||
# Apply MP% recovery/consumption
|
||||
mp_change = mp_change + trunc(max_mp * effect.mp_r)
|
||||
|
||||
# Cap recovery to max MP
|
||||
min(mp_change, max_mp)
|
||||
end
|
||||
|
||||
# Helper for map size
|
||||
defp stat_size(nil), do: 0
|
||||
defp stat_size(map) when is_map(map), do: stat_size(Map.keys(map))
|
||||
defp stat_size(list) when is_list(list), do: length(list)
|
||||
end
|
||||
Reference in New Issue
Block a user