scope BlessedShield initializer Init // requires AIDS, Damage, TimerUtils
//+-----------------------------------------------------------------------------------------------+
//| BLESSED SHIELD v1.00 by dudeim
//| ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ ¯¯¯¯¯¯
//| Description
//| ¯¯¯¯¯¯¯¯¯¯¯
//| Passive effect that causes the hero to recieve charges when health drops below
//| 50%. Charges will reduce future damage. (Whatever).
//|
//| Requires
//| ¯¯¯¯¯¯¯¯
//| - AIDS by Jesus4Lyf
//| - Damage by Jesus4Lyf
//| (Event by Jesus4Lyf, as a requirement from Damage)
//| - TimerUtils by Vexorian
//|
//| Credits
//| ¯¯¯¯¯¯¯
//| Romek for helping - blah.
//| Bribe for helping - blah.
//|
//| How to import
//| ¯¯¯¯¯¯¯¯¯¯¯¯¯
//| Copy this trigger into your map.
//| Copy the "Systems" folder into your map.
//| Go to AIDS and Damage, follow their implementation steps regarding the object ability.
//| OR
//| Copy the abilities from this map to your map. Be sure they keep the saw Rawcode.
//|
//+-----------------------------------------------------------------------------------------------+
globals
//************************************************************************************************
//* CONFIGURABLES SECTION *
//************************************************************************************************
private constant integer AID = 'A000' // Rawcodes should take priority, be at the top.
private constant integer BOOK_ID = 'A001' // Rawcode of the spellbook, contains the aura which provides the visual buff.
// Should be made into a function that takes a level. But anyways:
private constant real LIFE_PERCENT = 50.00 // The unit's health must match this or below for the ability to
private constant real ACTIVATE_PERCENT = 100.00 // Chance that you will gain a charge.
private constant real DMG_REDUCTION = 100.00 // Percent that the damage is reduced by.
private constant integer CHARGES = 5 // How many instances are blocked.
private constant integer KEEP_CHARGE_PERCENT = 0 // There is a 0% chance the unit will not lose a charge.
private constant integer MAX_CHARGES = 5 // How many charges can you keep? Useless I think?
private constant real CHARGE_REDUCTION = 0 // You lose 10% damage reduction for each charge loss.
// 4 charges = 90% reduction
// 3 charges = 80% reduction
private constant boolean STACK = false // If you already have charges and you take damage,
// will the charges stack or be set to max.
private constant string BLOCK_SFX = "Abilities\\Spells\\Human\\DivineShield\\DivineShieldTarget.mdl"
private constant string BLOCK_SFX_LOC = "origin"
private constant real COOLDOWN = 0.00
endglobals
//************************************************************************************************
//* THE ABILITY BEGINS HERE - DO NOT TOUCH *
//************************************************************************************************
globals
private unit tempUnit = null // global unit used for filter
private real sys_PERCENT = LIFE_PERCENT * 0.01 // Just so you don't need to calculate on every damage instance.
endglobals
// USE AIDS LIKE IT IS MEANT TO !
private struct UnitData extends array
//! runtextmacro AIDS()
boolean inCooldown
integer charges
timer timer
private static method AIDS_filter takes unit u returns boolean
return GetUnitAbilityLevel( u, 'Aloc' ) == 0
endmethod
private method AIDS_onCreate takes nothing returns nothing
set this.inCooldown = false
set this.charges = 0
set this.timer = null
endmethod
endstruct
private function BlockDamage takes nothing returns boolean
local UnitData data = UnitData[GetTriggerUnit()]
local integer remainingCharges
local real reduction
if data.charges > 0 then
set remainingCharges = CHARGES - data.charges
call DestroyEffect(AddSpecialEffectTarget( BLOCK_SFX, data.unit, BLOCK_SFX_LOC) )
if CHARGE_REDUCTION > 0 then
set reduction = DMG_REDUCTION - (remainingCharges * CHARGE_REDUCTION)
else
set reduction = DMG_REDUCTION
endif
// 0% chance that you will not lose a charge.
if KEEP_CHARGE_PERCENT < GetRandomInt( 0, 100 ) then
set data.charges = data.charges - 1
endif
if data.charges == 0 then
call UnitRemoveAbility( data.unit, BOOK_ID )
endif
call Damage_Block( GetEventDamage() * (reduction / 100 ) )
endif
return false
endfunction
// "callback" function. Where cooldown is placed.
private function ResetCooldown takes nothing returns nothing
local UnitData data = GetTimerData( GetExpiredTimer() )
set data.inCooldown = false
call ReleaseTimer( data.timer )
endfunction
// Cleaned up a lot in here.
private function ActivateAbility takes nothing returns nothing
local UnitData data = UnitData[GetTriggerUnit()]
if ACTIVATE_PERCENT >= GetRandomInt( 0, 100 ) and data.inCooldown == false then
set data.inCooldown = true
if data.charges == 0 then
call UnitAddAbility( data.unit, BOOK_ID )
endif
// STACK is a constant boolean. So we use a static if.
static if STACK then
// If max charges allowed is greater than 0.
set data.charges = data.charges + CHARGES
else
set data.charges = CHARGES
endif
if data.timer == null then
set data.timer = NewTimer()
endif
call SetTimerData( data.timer, data )
call TimerStart( data.timer, COOLDOWN, false, function ResetCooldown )
endif
endfunction
// GetTriggerUnit() was used more than once. Set a global unit (local will leak and will look messy if a local
// boolean is used) to it. lifePercent could be inlined, but it looks cleaner without doing so.
private function AbilityCheckCondition takes nothing returns boolean
local real lifePercent
set tempUnit = GetTriggerUnit()
set lifePercent = GetUnitState( tempUnit, UNIT_STATE_LIFE ) / GetUnitState( tempUnit, UNIT_STATE_MAX_LIFE )
return GetUnitAbilityLevel(tempUnit, AID) > 0 and lifePercent <= sys_PERCENT
endfunction
private function Init takes nothing returns nothing
// We don't need t and t2, we can just do it like so.
local trigger t = CreateTrigger()
local integer i = 0
call Damage_RegisterEvent( t )
call TriggerAddCondition(t, function AbilityCheckCondition )
call TriggerAddAction(t, function ActivateAbility )
set t = CreateTrigger()
call Damage_RegisterEvent(t)
call TriggerAddCondition(t, function BlockDamage)
// Spellbook ID is disabled onInit rather than while the spell takes place.
loop
call SetPlayerAbilityAvailable( Player(i), BOOK_ID, false )
set i = i + 1
exitwhen i == bj_MAX_PLAYER_SLOTS
endloop
endfunction
endscope