library ArmorAltering
globals
// The higher the test damage - the more accurate results it gives. When it's set to "10" - it will think that a unit with
// 2 armor has "1.96" armor (or something like that)
private constant real TEST_DAMAGE = 50000.00
// The value you have set for the armor rating in the Gameplay constants. DO NOT SET IT TO 0 (neither there, neither here)!
// The 2 values must be the same for this system to work.
private constant real ARMOR_COEFICIENT = 0.06
private constant integer ITERATIONS = 20
// If a unit's armor is higher than the damage, dealt to it - it gets healed instead.
private constant boolean NEGATIVE_DAMAGE_HEALS = false
endglobals
function Ln takes real x, real min, real max returns real
local real mid
local integer i = ITERATIONS
loop
set mid = ( min + max )/2
exitwhen(i <= 0)
set i = i - 1
if (Pow(bj_E,mid) > x) then
set max = mid
else
set min = mid
endif
endloop
return mid
endfunction
function Log takes real v, real x,real min, real max returns real
local real mid
local integer i=ITERATIONS
loop
set mid=(min+max)/2
exitwhen(i<=0)
set i=i-1
if (Pow(v,mid) > x) then
if v >= 1 then
set max = mid
else
set min = mid
endif
else
if v >= 1 then
set min = mid
else
set max = mid
endif
endif
endloop
return mid
endfunction
function Lg takes real x, real min, real max returns real
local real mid
local integer i=ITERATIONS
loop
set mid=(min+max)/2
exitwhen(i<=0)
set i=i-1
if (Pow(10,mid) > x) then
set max = mid
else
set min = mid
endif
endloop
return mid
endfunction
struct DamageAndArmor
real damage
real armor
static method create takes unit u, real init_dam returns DamageAndArmor
local DamageAndArmor DnA = DamageAndArmor.allocate()
// Remembers the unit's original health.
local real health = GetWidgetLife(u)
local real max_hp
local real armor_rating
// Gives the unit extra health, so it can survive the damage, that it's about to take.
call UnitAddAbility(u, udg_DamageBlockingAbility)
set max_hp = GetUnitState(u, UNIT_STATE_MAX_LIFE)
// Heals the unit to max hp (with the bonus).
call SetWidgetLife(u, max_hp)
// Disables the damage event trigger to avoid a loop until the unit dies.
call DisableTrigger(udg_DamageEventTrigger)
// Damage the unit.
call UnitDamageTarget( udg_DamageEventSource, u, TEST_DAMAGE, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS )
// Re-enables the damage event trigger.
call EnableTrigger(udg_DamageEventTrigger)
// Gets the unit's armor rating (which is different than the unit's armor), based on the damage the unit has actually taken.
set armor_rating = TEST_DAMAGE/(max_hp - GetWidgetLife(u))
// Calculates the original damage the unit was supposed to take.
set DnA.damage = init_dam*armor_rating
debug call BJDebugMsg(R2S(armor_rating))
// Calculates the unit's armor.
if armor_rating >= 1 then
set DnA.armor = (armor_rating - 1)/ARMOR_COEFICIENT
else
set DnA.armor = -Log(1 - ARMOR_COEFICIENT, 2 - (1/armor_rating), 0, 20)
if DnA.armor + I2R(R2I(DnA.armor)) < -0.95 then
set DnA.armor = I2R(R2I(DnA.armor - 1))
endif
endif
// Heals the unit to its max HP (with the bonus healt), so it wouldn't die when the bonus is removed.
call SetWidgetLife( u , max_hp )
// Removes bonus health.
call UnitRemoveAbility( u , udg_DamageBlockingAbility )
// Returns unit's original health.
call SetWidgetLife( u , health )
set u = null
return DnA
endmethod
endstruct
private function Armor_altering takes nothing returns boolean
local DamageAndArmor Base
if not udg_IsDamageSpell then
set Base = DamageAndArmor.create(udg_DamageEventTarget, udg_DamageEventAmount)
debug call BJDebugMsg("armor = "+R2S(Base.armor)+", base damage = "+R2S(Base.damage))
// Sets the damage dealt to the unit to be 'the base damage, dealt to it - its armor'.
static if NEGATIVE_DAMAGE_HEALS then
set udg_DamageEventAmount = Base.damage - Base.armor
if Base.damage >= Base.armor then
set udg_DamageEventType = udg_DamageTypeReduced
else
set udg_DamageEventType = udg_DamageTypeHeal
endif
else
if Base.damage > Base.armor then
set udg_DamageEventAmount = Base.damage - Base.armor
set udg_DamageEventType = udg_DamageTypeReduced
else
set udg_DamageEventAmount = 0
set udg_DamageEventType = udg_DamageTypeBlocked
endif
endif
call DamageAndArmor.destroy(Base)
endif
return false
endfunction
//===========================================================================
function InitTrig_Armor_altering takes nothing returns nothing
set gg_trg_Armor_altering = CreateTrigger( )
call TriggerRegisterVariableEvent( gg_trg_Armor_altering, "udg_DamageModifierEvent", EQUAL, 1.00 )
call TriggerAddCondition( gg_trg_Armor_altering, Condition(function Armor_altering) )
endfunction
endlibrary