- Joined
- Jan 20, 2019
- Messages
- 10
Just as I was struggling to write my own!
/*
vJass ShieldEngine 1.2.0
by Marchombre
Requirements:
- GUI Unit Event (by Bribe)
- Damage Engine 5.A.0.0 (by Bribe)
- CustomBar 1.0 (by dhk_undead_lord / aka Anachron)
*/
/*
Apply shield in the following order:
1/ Shield that can only take specific damage (only spell/attack) before shields that can absorb all
2/ Shield that nullify one instance of damage before those blocking amount of damage
3/ Order by timeLeft
*/
/*
================================================
JASS API DESCRIPTION
================================================
*/
/*
These are the functions you can use to interact with the engine:
================================================
SHIELD CREATION
================================================
ShieldEngine.CreateShield
|-- Parameters:
unit source,
unit target,
string name,
string sfxPath,
string attachPoint,
integer shieldProcType,
integer shieldType,
integer shieldHpType,
boolean isStackable,
boolean isTimed,
real duration,
real HP,
boolean breakAtZero,
boolean canRegen,
real timeBeforeRegen,
real regenTime
|-- Returns: nothing
ShieldEngine.CreateTimedShield
|-- Parameters:
unit source,
unit target,
string name,
real duration,
real HP
|-- Returns: nothing
ShieldEngine.CreateInstanceShield
|-- Parameters:
unit source,
unit target,
string name,
real HP
|-- Returns: nothing
================================================
SHIELD DESTRUCTION
================================================
There are two ways of destroying a shield manually. Methods with Remove will do it silently. Methods with destroy will fire a BreakEvent.
ShieldEngine.RemoveShieldByName
|-- Parameters:
unit u,
string name
|-- Returns: nothing
ShieldEngine.RemoveAllShields
|-- Parameters:
unit u
|-- Returns: nothing
ShieldEngine.RemoveShieldsByType
|-- Parameters:
unit u,
integer hpType
|-- Returns: nothing
ShieldEngine.DestroyShieldByName
|-- Parameters:
unit u,
string name
|-- Returns: nothing
ShieldEngine.DestroyShieldsByType
|-- Parameters:
unit u,
integer hpType
|-- Returns: nothing
ShieldEngine.DestroyAllShields
|-- Parameters:
unit u
|-- Returns: nothing
================================================
UNIT INFORMATION
================================================
ShieldEngine.IsUnitShielded
|-- Parameters:
unit u
|-- Returns: boolean
ShieldEngine.UnitHasShield
|-- Parameters:
unit u,
string name
|-- Returns: boolean
ShieldEngine.UnitHasActiveShield
|-- Parameters:
unit u
|-- Returns: boolean
ShieldEngine.UnitHasActiveShieldOfType
|-- Parameters:
unit u,
integer shieldHpType
|-- Returns: boolean
*/
/*
================================================
GUI API DESCRIPTION
================================================
*/
/*
================================================
EVENTS TRIGGER VARIABLES
================================================
udg_PreShieldCreationEvent
udg_ShieldCreatedEvent
udg_ShieldAbsorbEvent
udg_ShieldExpriredEvent
udg_ShieldBreakEvent
udg_ShieldRefreshedEvent
udg_ShieldStackedEvent
================================================
EVENTS GETTERS
================================================
// This variables should be used as readonly in GUI
udg_ShieldName
udg_ShieldAbsorbedDamage
udg_ShieldAbsorbedDamageSource
udg_ShieldProcType
udg_ShieldHpType
udg_ShieldBaseMaxHP
udg_ShieldPrvMaxHP
udg_ShieldBaseDuration
udg_ShieldPrvDuration
================================================
EVENTS VARIABLES
================================================
// This Variables can be read and/or modified during events
udg_ShieldSource
udg_ShieldWielder
udg_ShieldIsStackable
udg_ShieldIsTimed
udg_ShieldDuration
udg_ShieldMaxHP
udg_ShieldCurrentHP
udg_ShieldBreakAtZero
udg_ShieldCanRegen
udg_ShieldTimeBeforeRegen
udg_ShieldRegenTime
================================================
GUI CONSTANTS
================================================
// This variables should be used as readonly in GUI
udg_SHIELD_PROC_PREREDIC
udg_SHIELD_PROC_POSTREDUC
udg_SHIELD_TYPE_HP_BASED
udg_SHIELD_TYPE_INSTANCE
udg_SHIELD_HP_TYPE_ALL
udg_SHIELD_HP_TYPE_SPELL
udg_SHIELD_HP_TYPE_ATTACK
================================================
GUI API TRIGGERS
================================================
// This variables are used in GUI triggers to call API
udg_NextShieldSource
udg_NextShieldTarget
udg_NextShieldName
udg_NextShieldSfxPath
udg_NextShieldSfxAttachPoint
udg_NextShieldProcType
udg_NextShieldType
udg_NextShieldHpType
udg_NextShieldIsStackable
udg_NextShieldIsTimed
udg_NextShieldDuration
udg_NextShieldHP
udg_NextShieldBreakAtZero
udg_NextShieldCanRegen
udg_NextShieldTimeBeforeRegen
udg_NextShieldRegenTime
*/
library ShieldEngine requires DamageEngine, ARGB, CustomBar
globals
/*
================================================
CONFIG VARIABLES
================================================
*/
//
private constant real SHIELD_TICK_INTERVAL = 0.1 // Interval (in second) at which duration is checked and regen is applied.
private constant integer MAX_PRESHIELD_CREATION_EVENTS = 4
/*
Shield aesthetic
*/
private constant string SHIELD_DEFAULT_SFX_PATH = "Abilities\\Spells\\Human\\ManaShield\\ManaShieldCaster.mdl"
private constant string SHIELD_DEFAULT_ATTACH_POINT = "origin"
// Shield Bar colors config is done in ShieldWieder.OnInit (can't be done in globals)
// SHIELD_HP_TYPE_ALL => Green by default
private ARGB SHIELD_COLOR_LEFT
private ARGB SHIELD_COLOR_RIGHT
// SHIELD_HP_TYPE_SPELL => Purple by default
private ARGB SPELL_SHIELD_COLOR_LEFT
private ARGB SPELL_SHIELD_COLOR_RIGHT
// SHIELD_HP_TYPE_ATTACK => Brown by default
private ARGB ATTACK_SHIELD_COLOR_LEFT
private ARGB ATTACK_SHIELD_COLOR_RIGHT
/*
================================================
SHOULD NOT TOUCH THESE CONSTANTS
================================================
*/
private constant integer SHIELD_PROC_PREREDUC = 0 // Shield absorb damage before reductions like armor are applied.
private constant integer SHIELD_PROC_POSTREDUC = 1 // Shield absorb damage after reductions are applied.
private constant integer SHIELD_TYPE_HP_BASED = 0 // Shield that expire after set amount of damage.
private constant integer SHIELD_TYPE_INSTANCE = 1 // Shield that expires after a number of damage instance
private constant integer SHIELD_HP_TYPE_ALL = 0 // Absorb all type of damage
private constant integer SHIELD_HP_TYPE_SPELL = 1 // Absorb only spell damage
private constant integer SHIELD_HP_TYPE_ATTACK = 2 // Absorb only attack damage
// Used for Firing events
private constant integer SHIELD_EVENT_CREATED = 0
private constant integer SHIELD_EVENT_ABSORB = 1
private constant integer SHIELD_EVENT_BREAK = 2
private constant integer SHIELD_EVENT_EXPIRE = 3
private constant integer SHIELD_EVENT_REFRESHED = 4
private constant integer SHIELD_EVENT_STACKED = 5
/*
================================================
GUI VARIABLES
================================================
*/
/*
*/
endglobals
public function interface iChange takes CustomBar cb returns nothing
struct Shield
/*
Per instance variables
*/
public string name // Name of Shield, allows search/stack etc.
public unit source // Unit that casted the shield
public unit wielder // Unit that received the shield
private string sfxPath // Path to the model of visual effect
public effect visualEffect // Visual Effect attached to the unit
private string attachPoint // Visual Effect attach point to the wielder
public integer shieldProcType // When does the shield apply
public integer shieldType // How the shield block damage
public integer shieldHpType // What type of damage does the shield absorb
public boolean isStackable // Can this shield stack with itself
public boolean isTimed // Is the shield limited in duration
public real duration // If timed: number of seconds before expiration.
public real timeLeft // If timed: how much time is left before expiration.
public real maxHP // If shieldType = SHIELD_TYPE_HP_BASED: Amount of damage the shield can absorb. If shieldType = SHIELD_TYPE_INSTANCE: how many instance of damage does the shield absorb
public real currentHP // Remaining HP
public boolean breakAtZero // Does the shield break when its HPs reach 0
public real lastAbsorbedDamage // Store the last amount of damage blocked
public unit lastAbsorbedDamageSource // Store the unit who dealt last damage
public boolean canRegen // Can the shield regenerate itself
public real timeBeforeRegen // How long without taking damage before shield regen (in seconds)
public real regenTime // How long should it take for a full regen (in seconds)
public real regenPerTick // How much HP regen per tick
// Following are to keep track of modifications during Events
public real baseMaxHP // Initial Hp Amount when shield was casted
public real prvMaxHP // Hp amount at the end of last step
public real baseDuration // Initial duration when shield was casted
public real prvDuration // Duration at the end of last step
public Shield next
public Shield prev
public static method create takes /*
*/ unit source, /*
*/ unit target, /*
*/ string name, /*
*/ string sfxPath, /*
*/ string attachPoint, /*
*/ integer shieldProcType, /*
*/ integer shieldType, /*
*/ integer shieldHpType, /*
*/ boolean isStackable, /*
*/ boolean isTimed, /*
*/ real duration, /*
*/ real HP, /*
*/ boolean breakAtZero, /*
*/ boolean canRegen, /*
*/ real timeBeforeRegen, /*
*/ real regenTime /*
*/ returns Shield
local Shield this = Shield.allocate()
set this.source = source
set this.wielder = target
set this.name = name
set this.sfxPath = sfxPath
set this.attachPoint = attachPoint
set this.visualEffect = null
set this.shieldProcType = shieldProcType
set this.shieldType = shieldType
set this.shieldHpType = shieldHpType
set this.isStackable = isStackable
set this.isTimed = isTimed
set this.duration = duration
set this.timeLeft = this.duration
// Set times to a very high amount that will not change to make it easier when sorting shields by duration
if not this.isTimed then
set this.duration = 1000000.00
set this.timeLeft = 1000000.00
endif
set this.maxHP = HP
set this.currentHP = HP
set this.breakAtZero = breakAtZero
set this.canRegen = canRegen
set this.timeBeforeRegen = timeBeforeRegen
set this.regenTime = regenTime
if this.canRegen then
set this.regenPerTick = this.maxHP / (this.regenTime / SHIELD_TICK_INTERVAL)
else
set this.regenPerTick = 0.00
endif
// Following are to keep track of modifications during Events
set this.baseMaxHP = this.maxHP
set this.prvMaxHP = this.maxHP
set this.baseDuration = this.duration
set this.prvDuration = this.duration
set this.next = 0
set this.next = 0
return this
endmethod
public method destroy takes nothing returns nothing
call DestroyEffect(this.visualEffect)
call this.deallocate()
endmethod
public method CreateVisualEffet takes nothing returns nothing
if this.visualEffect == null then
set this.visualEffect = AddSpecialEffectTarget(this.sfxPath, this.wielder, this.attachPoint)
endif
endmethod
public method Refresh takes real duration, real HP returns nothing
local real prevMaxHP
local real prevCurrentHP
local ShieldWielder wielder = ShieldEngine.GetUnitWielder(this.wielder)
set this.duration = RMaxBJ(this.duration, duration)
set this.timeLeft = RMinBJ(this.duration, this.timeLeft + duration)
set prevMaxHP = this.maxHP
set prevCurrentHP = this.currentHP
set this.maxHP = RMaxBJ(this.maxHP, HP)
set this.currentHP = RMinBJ(this.maxHP, this.currentHP + HP)
if this.shieldHpType == SHIELD_HP_TYPE_ALL then
set wielder.totalMaxShield = wielder.totalMaxShield + (this.maxHP - prevMaxHP)
set wielder.totalCurrentShield = wielder.totalCurrentShield + (this.currentHP - prevCurrentHP)
elseif this.shieldHpType == SHIELD_HP_TYPE_SPELL then
set wielder.totalMaxSpellShield = wielder.totalMaxSpellShield + (this.maxHP - prevMaxHP)
set wielder.totalCurrentSpellShield = wielder.totalCurrentSpellShield + (this.currentHP - prevCurrentHP)
elseif this.shieldHpType == SHIELD_HP_TYPE_ATTACK then
set wielder.totalMaxAttackShield = wielder.totalMaxAttackShield + (this.maxHP - prevMaxHP)
set wielder.totalCurrentAttackShield = wielder.totalCurrentAttackShield + (this.currentHP - prevCurrentHP)
endif
call ShieldEvent.FireEvent(SHIELD_EVENT_REFRESHED, this)
endmethod
public method Stack takes real duration, real HP returns nothing
local ShieldWielder wielder = ShieldEngine.GetUnitWielder(this.wielder)
set this.duration = RMaxBJ(this.duration, duration)
set this.timeLeft = RMinBJ(this.duration, this.timeLeft + duration)
set this.maxHP = this.maxHP + HP
set this.currentHP = this.currentHP + HP
if this.shieldHpType == SHIELD_HP_TYPE_ALL then
set wielder.totalMaxShield = wielder.totalMaxShield + HP
set wielder.totalCurrentShield = wielder.totalCurrentShield + HP
elseif this.shieldHpType == SHIELD_HP_TYPE_SPELL then
set wielder.totalMaxSpellShield = wielder.totalMaxSpellShield + HP
set wielder.totalCurrentSpellShield = wielder.totalCurrentSpellShield + HP
elseif this.shieldHpType == SHIELD_HP_TYPE_ATTACK then
set wielder.totalMaxAttackShield = wielder.totalMaxAttackShield + HP
set wielder.totalCurrentAttackShield = wielder.totalCurrentAttackShield + HP
endif
call ShieldEvent.FireEvent(SHIELD_EVENT_STACKED, this)
endmethod
endstruct
struct ShieldWielder
/*
Per instance variables
*/
public unit wielder
private CustomBar shieldBar
private CustomBar spellShieldBar
private CustomBar attackShieldBar
public Shield firstPreReduc
public Shield lastPreReduc
public Shield firstPreReducSpell
public Shield lastPreReducSpell
public Shield firstPreReducAttack
public Shield lastPreReducAttack
public Shield firstPostReduc
public Shield lastPostReduc
public Shield firstPostReducSpell
public Shield lastPostReducSpell
public Shield firstPostReducAttack
public Shield lastPostReducAttack
public real lastDamageTaken
public real totalMaxShield
public real totalCurrentShield
public real totalMaxSpellShield
public real totalCurrentSpellShield
public real totalMaxAttackShield
public real totalCurrentAttackShield
public ShieldWielder prev
public ShieldWielder next
public static method create takes unit wielder returns ShieldWielder
local ShieldWielder this = ShieldWielder.allocate()
set this.wielder = wielder
set this.shieldBar = 0
set this.spellShieldBar = 0
set this.attackShieldBar = 0
set this.firstPreReduc = 0
set this.lastPreReduc = 0
set this.firstPreReducSpell = 0
set this.lastPreReducSpell = 0
set this.firstPreReducAttack = 0
set this.lastPreReducAttack = 0
set this.firstPostReduc = 0
set this.lastPostReduc = 0
set this.firstPostReducSpell = 0
set this.lastPostReducSpell = 0
set this.firstPostReducAttack = 0
set this.lastPostReducAttack = 0
set this.lastDamageTaken = 0.00
set this.totalMaxShield = 0.00
set this.totalCurrentShield = 0.00
set this.totalMaxSpellShield = 0.00
set this.totalCurrentSpellShield = 0.00
set this.totalMaxAttackShield = 0.00
set this.totalCurrentAttackShield = 0.00
set this.prev = 0
set this.next = 0
return this
endmethod
public method destroy takes nothing returns nothing
call this.deallocate()
endmethod
private static method UpdateShieldBar takes CustomBar cb returns nothing
local ShieldWielder wielder = ShieldEngine.GetUnitWielder(cb.target)
set cb.txtBar.percentage = 100.0 * wielder.totalCurrentShield / wielder.totalMaxShield
endmethod
private static method UpdateSpellShieldBar takes CustomBar cb returns nothing
local ShieldWielder wielder = ShieldEngine.GetUnitWielder(cb.target)
set cb.txtBar.percentage = 100.0 * wielder.totalCurrentSpellShield / wielder.totalMaxSpellShield
endmethod
private static method UpdateAttackShieldBar takes CustomBar cb returns nothing
local ShieldWielder wielder = ShieldEngine.GetUnitWielder(cb.target)
set cb.txtBar.percentage = 100.0 * wielder.totalCurrentAttackShield / wielder.totalMaxAttackShield
endmethod
private static method ShowBarCheck takes player owner, player cur returns boolean
return IsPlayerAlly(owner, cur) or owner == cur
endmethod
private method CreateShieldBar takes integer shieldHpType returns nothing
local CustomBar cb
local iChange updateFunction
local real offsetX
local real offsetY
local ARGB colorLeft
local ARGB colorRight
if shieldHpType == SHIELD_HP_TYPE_SPELL then
set cb = this.spellShieldBar
set updateFunction = ShieldWielder.UpdateSpellShieldBar
set offsetX = -90.0
set offsetY = -70.0
set colorLeft = SPELL_SHIELD_COLOR_LEFT
set colorRight = SPELL_SHIELD_COLOR_RIGHT
elseif shieldHpType == SHIELD_HP_TYPE_ATTACK then
set cb = this.attackShieldBar
set updateFunction = ShieldWielder.UpdateAttackShieldBar
set offsetX = -90.0
set offsetY = -40.0
set colorLeft = ATTACK_SHIELD_COLOR_LEFT
set colorRight = ATTACK_SHIELD_COLOR_RIGHT
else
set cb = this.shieldBar
set updateFunction = ShieldWielder.UpdateShieldBar
set offsetX = -90.0
set offsetY = -10.0
set colorLeft = SHIELD_COLOR_LEFT
set colorRight = SHIELD_COLOR_RIGHT
endif
// create new bar only if there isn't already one
if cb == 0 then
set cb = CustomBar.create(this.wielder, updateFunction)
set cb.txtTag.offsetX = offsetX
set cb.txtTag.offsetY = offsetY
call cb.txtBar.addGradient(colorLeft, colorRight, 1, 25)
call this.shieldBar.Show(bj_FORCE_ALL_PLAYERS, ShieldWielder.ShowBarCheck)
call this.shieldBar.showCB()
if shieldHpType == SHIELD_HP_TYPE_SPELL then
set this.spellShieldBar = cb
elseif shieldHpType == SHIELD_HP_TYPE_ATTACK then
set this.attackShieldBar = cb
else
set this.shieldBar = cb
endif
endif
endmethod
public method AdjustBarAfterDamage takes integer shieldHpType, real dmgAmount returns nothing
if shieldHpType == SHIELD_HP_TYPE_ALL then
set this.totalCurrentShield = this.totalCurrentShield - dmgAmount
elseif shieldHpType == SHIELD_HP_TYPE_SPELL then
set this.totalCurrentSpellShield = this.totalCurrentSpellShield - dmgAmount
elseif shieldHpType == SHIELD_HP_TYPE_ATTACK then
set this.totalCurrentAttackShield = this.totalCurrentAttackShield - dmgAmount
endif
endmethod
private method AdjustShieldBars takes string how, Shield shield returns nothing
local CustomBar cb
if shield.shieldHpType == SHIELD_HP_TYPE_SPELL then
if how =="add" then
set this.totalMaxSpellShield = this.totalMaxSpellShield + shield.maxHP
set this.totalCurrentSpellShield = this.totalCurrentSpellShield + shield.currentHP
if this.spellShieldBar == 0 then
call this.CreateShieldBar(shield.shieldHpType)
endif
else
set this.totalMaxSpellShield = this.totalMaxSpellShield - shield.maxHP
set this.totalCurrentSpellShield = this.totalCurrentSpellShield - shield.currentHP
if this.totalMaxSpellShield <= 0.00 then
call this.spellShieldBar.destroy()
set this.spellShieldBar = 0
endif
endif
elseif shield.shieldHpType == SHIELD_HP_TYPE_ATTACK then
if how =="add" then
set this.totalMaxAttackShield = this.totalMaxAttackShield + shield.maxHP
set this.totalCurrentAttackShield = this.totalCurrentAttackShield + shield.currentHP
if this.attackShieldBar <= 0 then
call this.CreateShieldBar(shield.shieldHpType)
endif
else
set this.totalMaxAttackShield = this.totalMaxAttackShield - shield.maxHP
set this.totalCurrentAttackShield = this.totalCurrentAttackShield - shield.currentHP
if this.totalMaxAttackShield <= 0.00 then
call this.attackShieldBar.destroy()
set this.attackShieldBar = 0
endif
endif
else
if how =="add" then
set this.totalMaxShield = this.totalMaxShield + shield.maxHP
set this.totalCurrentShield = this.totalCurrentShield + shield.currentHP
if this.shieldBar == 0 then
call this.CreateShieldBar(shield.shieldHpType)
endif
else
set this.totalMaxShield = this.totalMaxShield - shield.maxHP
set this.totalCurrentShield = this.totalCurrentShield - shield.currentHP
if this.totalMaxShield <= 0.00 then
call this.shieldBar.destroy()
set this.shieldBar = 0
endif
endif
endif
endmethod
private method AddFirstShield takes Shield shield returns nothing
if shield.shieldProcType == SHIELD_PROC_PREREDUC and shield.shieldHpType == SHIELD_HP_TYPE_ALL then
set this.firstPreReduc = shield
set this.lastPreReduc = shield
elseif shield.shieldProcType == SHIELD_PROC_PREREDUC and shield.shieldHpType == SHIELD_HP_TYPE_SPELL then
set this.firstPreReducSpell = shield
set this.lastPreReducSpell = shield
elseif shield.shieldProcType == SHIELD_PROC_PREREDUC and shield.shieldHpType == SHIELD_HP_TYPE_ATTACK then
set this.firstPreReducAttack = shield
set this.lastPreReducAttack = shield
elseif shield.shieldProcType == SHIELD_PROC_POSTREDUC and shield.shieldHpType == SHIELD_HP_TYPE_ALL then
set this.firstPostReduc = shield
set this.lastPostReduc = shield
elseif shield.shieldProcType == SHIELD_PROC_POSTREDUC and shield.shieldHpType == SHIELD_HP_TYPE_SPELL then
set this.firstPostReducSpell = shield
set this.lastPostReducSpell = shield
elseif shield.shieldProcType == SHIELD_PROC_POSTREDUC and shield.shieldHpType == SHIELD_HP_TYPE_ATTACK then
set this.firstPostReducAttack = shield
set this.lastPostReducAttack = shield
endif
endmethod
public method AddShield takes Shield shield returns nothing
local Shield current
local Shield last
local Shield array listOfFirst
local integer array listOfProcType
local integer array listOfHpType
local integer i
set listOfFirst[0] = this.firstPreReduc
set listOfFirst[1] = this.firstPostReduc
set listOfFirst[2] = this.firstPreReducAttack
set listOfFirst[3] = this.firstPostReducAttack
set listOfFirst[4] = this.firstPreReducSpell
set listOfFirst[5] = this.firstPostReducSpell
set listOfProcType[0] = SHIELD_PROC_PREREDUC
set listOfProcType[1] = SHIELD_PROC_POSTREDUC
set listOfProcType[2] = SHIELD_PROC_PREREDUC
set listOfProcType[3] = SHIELD_PROC_POSTREDUC
set listOfProcType[4] = SHIELD_PROC_PREREDUC
set listOfProcType[5] = SHIELD_PROC_POSTREDUC
set listOfHpType[0] = SHIELD_HP_TYPE_ALL
set listOfHpType[1] = SHIELD_HP_TYPE_ALL
set listOfHpType[2] = SHIELD_HP_TYPE_ATTACK
set listOfHpType[3] = SHIELD_HP_TYPE_ATTACK
set listOfHpType[4] = SHIELD_HP_TYPE_SPELL
set listOfHpType[5] = SHIELD_HP_TYPE_SPELL
call shield.CreateVisualEffet()
call this.AdjustShieldBars("add", shield)
set i = 0
loop
exitwhen i > 5
set current = listOfFirst[i]
// check if the correct list is empty
if current == 0 and shield.shieldProcType == listOfProcType[i] and shield.shieldHpType == listOfHpType[i] then
call this.AddFirstShield(shield)
return
endif
loop
exitwhen current == 0 or shield.shieldProcType != listOfProcType[i] or shield.shieldHpType != listOfHpType[i]
if shield.shieldType == current.shieldType then
if shield.timeLeft < current.timeLeft then
set shield.prev = current.prev
set current.prev.next = shield
set shield.next = current
set current.prev = shield
return
endif
elseif shield.shieldType == SHIELD_TYPE_INSTANCE and current.shieldType == SHIELD_TYPE_HP_BASED then
set shield.prev = current.prev
set current.prev.next = shield
set shield.next = current
set current.prev = shield
return
endif
set last = current
set current = current.next
endloop
// check if it should be inserted at the end of this list
if shield.shieldProcType == listOfProcType[i] and shield.shieldHpType == listOfHpType[i] then
set last.next = shield
endif
set i = i +1
endloop
endmethod
public method RemoveShield takes Shield shield returns nothing
if shield == this.firstPreReduc then
set this.firstPreReduc = shield.next
elseif shield == this.firstPostReduc then
set this.firstPostReduc = shield.next
elseif shield == this.firstPreReducAttack then
set this.firstPreReducAttack = shield.next
elseif shield == this.firstPostReducAttack then
set this.firstPostReducAttack = shield.next
elseif shield == this.firstPreReducSpell then
set this.firstPreReducSpell = shield.next
elseif shield == this.firstPostReducSpell then
set this.firstPostReducSpell = shield.next
endif
if shield == this.lastPreReduc then
set this.lastPreReduc = shield.prev
elseif shield == this.lastPostReduc then
set this.lastPostReduc = shield.prev
elseif shield == this.lastPreReducAttack then
set this.lastPreReducAttack = shield.prev
elseif shield == this.lastPostReducAttack then
set this.lastPostReducAttack = shield.prev
elseif shield == this.lastPreReducSpell then
set this.lastPreReducSpell = shield.prev
elseif shield == this.lastPostReducSpell then
set this.lastPostReduc = shield.prev
endif
if shield.prev != 0 then
set shield.prev.next = shield.next
endif
if shield.next != 0 then
set shield.next.prev = shield.prev
endif
call this.AdjustShieldBars("remove", shield)
call ShieldEngine.CheckRemoveWielder(this)
endmethod
public method FindShieldByNameAndTypes takes string name, integer shieldProcType, integer shieldType, integer shieldHpType returns Shield
local Shield shield = 0
if shieldHpType == SHIELD_HP_TYPE_ALL then
if shieldProcType == SHIELD_PROC_PREREDUC then
set shield = this.firstPreReduc
else
set shield = this.firstPostReduc
endif
elseif shieldHpType == SHIELD_HP_TYPE_SPELL then
if shieldProcType == SHIELD_PROC_PREREDUC then
set shield = this.firstPreReducSpell
else
set shield = this.firstPostReducSpell
endif
elseif shieldHpType == SHIELD_HP_TYPE_ATTACK then
if shieldProcType == SHIELD_PROC_PREREDUC then
set shield = this.firstPreReducAttack
else
set shield = this.firstPostReducAttack
endif
endif
loop
exitwhen shield == 0
if shield.name == name and shield.shieldType == shieldType then
return shield
endif
set shield = shield.next
endloop
return 0
endmethod
public method RemoveShieldsByType takes integer hpType returns nothing
local Shield shield
if hpType == SHIELD_HP_TYPE_ALL then
set shield = this.firstPreReduc
elseif hpType == SHIELD_HP_TYPE_ATTACK then
set shield = this.firstPreReducAttack
elseif hpType == SHIELD_HP_TYPE_SPELL then
set shield = this.firstPreReducSpell
endif
loop
exitwhen shield == 0
call this.RemoveShield(shield)
set shield = shield.next
endloop
if hpType == SHIELD_HP_TYPE_ALL then
set shield = this.firstPostReduc
elseif hpType == SHIELD_HP_TYPE_ATTACK then
set shield = this.firstPostReducAttack
elseif hpType == SHIELD_HP_TYPE_SPELL then
set shield = this.firstPostReducSpell
endif
loop
exitwhen shield == 0
call this.RemoveShield(shield)
set shield = shield.next
endloop
endmethod
public method DestroyShieldsByType takes integer hpType returns nothing
local Shield shield
if hpType == SHIELD_HP_TYPE_ALL then
set shield = this.firstPreReduc
elseif hpType == SHIELD_HP_TYPE_ATTACK then
set shield = this.firstPreReducAttack
elseif hpType == SHIELD_HP_TYPE_SPELL then
set shield = this.firstPreReducSpell
endif
loop
exitwhen shield == 0
call this.RemoveShield(shield)
call ShieldEvent.FireEvent(SHIELD_EVENT_BREAK, shield)
set shield = shield.next
endloop
if hpType == SHIELD_HP_TYPE_ALL then
set shield = this.firstPostReduc
elseif hpType == SHIELD_HP_TYPE_ATTACK then
set shield = this.firstPostReducAttack
elseif hpType == SHIELD_HP_TYPE_SPELL then
set shield = this.firstPostReducSpell
endif
loop
exitwhen shield == 0
call this.RemoveShield(shield)
call ShieldEvent.FireEvent(SHIELD_EVENT_BREAK, shield)
set shield = shield.next
endloop
endmethod
public method RemoveShieldByName takes string name returns nothing
local Shield array listOfFirst
local Shield shield
local integer i = 0
set listOfFirst[0] = this.firstPreReduc
set listOfFirst[1] = this.firstPostReduc
set listOfFirst[2] = this.firstPreReducAttack
set listOfFirst[3] = this.firstPostReducAttack
set listOfFirst[4] = this.firstPreReducSpell
set listOfFirst[5] = this.firstPostReducSpell
loop
exitwhen i > 5
set shield = listOfFirst[i]
loop
exitwhen shield == 0
if shield.name == name then
call this.RemoveShield(shield)
endif
set shield = shield.next
endloop
set i = i +1
endloop
endmethod
public method DestroyShieldByName takes string name returns nothing
local Shield array listOfFirst
local Shield shield
local integer i = 0
set listOfFirst[0] = this.firstPreReduc
set listOfFirst[1] = this.firstPostReduc
set listOfFirst[2] = this.firstPreReducAttack
set listOfFirst[3] = this.firstPostReducAttack
set listOfFirst[4] = this.firstPreReducSpell
set listOfFirst[5] = this.firstPostReducSpell
loop
exitwhen i > 5
set shield = listOfFirst[i]
loop
exitwhen shield == 0
if shield.name == name then
call this.RemoveShield(shield)
call ShieldEvent.FireEvent(SHIELD_EVENT_BREAK, shield)
endif
set shield = shield.next
endloop
set i = i +1
endloop
endmethod
public method HasShield takes string name returns boolean
local Shield array listOfFirst
local Shield shield
local integer i = 0
set listOfFirst[0] = this.firstPreReduc
set listOfFirst[1] = this.firstPostReduc
set listOfFirst[2] = this.firstPreReducAttack
set listOfFirst[3] = this.firstPostReducAttack
set listOfFirst[4] = this.firstPreReducSpell
set listOfFirst[5] = this.firstPostReducSpell
loop
exitwhen i > 5
set shield = listOfFirst[i]
loop
exitwhen shield == 0
if shield.name == name then
return true
endif
set shield = shield.next
endloop
set i = i +1
endloop
return false
endmethod
private static method onInit takes nothing returns nothing
// Shield Bar color, gradient from left to right. Parameters: Alpha, red, green, blue
// SHIELD_HP_TYPE_ALL => Green by default
set SHIELD_COLOR_LEFT = ARGB.create(255, 15, 75, 15)
set SHIELD_COLOR_RIGHT = ARGB.create(255, 15, 220, 15)
// SHIELD_HP_TYPE_SPELL => Purple by default
set SPELL_SHIELD_COLOR_LEFT = ARGB.create(255, 75, 10, 75)
set SPELL_SHIELD_COLOR_RIGHT = ARGB.create(255, 220, 30, 220)
// SHIELD_HP_TYPE_ATTACK => Brown by default
set ATTACK_SHIELD_COLOR_LEFT = ARGB.create(255, 220, 150, 25)
set ATTACK_SHIELD_COLOR_RIGHT = ARGB.create(255, 150, 75, 25)
endmethod
endstruct
struct ShieldEvent
/*
Per instance variables
*/
private integer eventType
private Shield shield
private ShieldEvent next
/*
Shared variables
*/
private static ShieldEvent first
private static ShieldEvent last
public static method create takes integer eventType, Shield shield returns ShieldEvent
local ShieldEvent this = ShieldEvent.allocate()
set this.eventType = eventType
set this.shield = shield
set this.next = 0
return this
endmethod
private method destroy takes nothing returns nothing
call this.deallocate()
endmethod
private static method resetEventVariables takes nothing returns nothing
set udg_ShieldName = null
set udg_ShieldSource = null
set udg_ShieldWielder = null
set udg_ShieldProcType = -1
set udg_ShieldType = -1
set udg_ShieldHpType = -1
set udg_ShieldIsStackable = false
set udg_ShieldIsTimed = false
set udg_ShieldDuration = 0.00
set udg_ShieldTimeLeft = 0.00
set udg_ShieldMaxHP = 0.00
set udg_ShieldCurrentHP = 0.00
set udg_ShieldBreakAtZero = false
set udg_ShieldAbsorbedDamage = 0.00
set udg_ShieldCanRegen = false
set udg_ShieldTimeBeforeRegen = 0.00
set udg_ShieldRegenTime = 0.00
set udg_ShieldBaseMaxHP = 0.00
set udg_ShieldPrvMaxHP = 0.00
set udg_ShieldBaseDuration = 0.00
set udg_ShieldPrvDuration = 0.00
endmethod
private method setEventVariables takes nothing returns nothing
set udg_ShieldName = this.shield.name
set udg_ShieldSource = this.shield.source
set udg_ShieldWielder = this.shield.wielder
set udg_ShieldProcType = this.shield.shieldProcType
set udg_ShieldType = this.shield.shieldType
set udg_ShieldHpType = this.shield.shieldHpType
set udg_ShieldIsStackable = this.shield.isStackable
set udg_ShieldIsTimed = this.shield.isTimed
set udg_ShieldDuration = this.shield.duration
set udg_ShieldTimeLeft = this.shield.timeLeft
set udg_ShieldMaxHP = this.shield.maxHP
set udg_ShieldCurrentHP = this.shield.currentHP
set udg_ShieldBreakAtZero = this.shield.breakAtZero
set udg_ShieldAbsorbedDamage = this.shield.lastAbsorbedDamage
set udg_ShieldAbsorbedDamageSource = this.shield.lastAbsorbedDamageSource
set udg_ShieldCanRegen = this.shield.canRegen
set udg_ShieldTimeBeforeRegen = this.shield.timeBeforeRegen
set udg_ShieldRegenTime = this.shield.regenTime
set udg_ShieldBaseMaxHP = this.shield.baseMaxHP
set udg_ShieldPrvMaxHP = this.shield.prvMaxHP
set udg_ShieldBaseDuration = this.shield.baseDuration
set udg_ShieldPrvDuration = this.shield.prvDuration
endmethod
private method getEventVariables takes nothing returns nothing
set this.shield.source = udg_ShieldSource
set this.shield.wielder = udg_ShieldWielder
set this.shield.isStackable = udg_ShieldIsStackable
set this.shield.isTimed = udg_ShieldIsTimed
set this.shield.duration = udg_ShieldDuration
set this.shield.timeLeft = udg_ShieldTimeLeft
set this.shield.maxHP = udg_ShieldMaxHP
set this.shield.currentHP = udg_ShieldCurrentHP
set this.shield.breakAtZero = udg_ShieldBreakAtZero
set this.shield.canRegen = udg_ShieldCanRegen
set this.shield.timeBeforeRegen = udg_ShieldTimeBeforeRegen
set this.shield.regenTime = udg_ShieldRegenTime
if this.shield.canRegen then
set this.shield.regenPerTick = this.shield.maxHP / (this.shield.regenTime / SHIELD_TICK_INTERVAL)
else
set this.shield.regenPerTick = 0.00
endif
// Stores this step result for reference in next step if needed.
set this.shield.prvMaxHP = udg_ShieldMaxHP
set this.shield.prvDuration = udg_ShieldDuration
endmethod
public static method FireEvent takes integer eventType, Shield shield returns nothing
local ShieldEvent shieldEvent = ShieldEvent.create(eventType, shield)
if first == 0 then
set first = shieldEvent
set last = shieldEvent
call ShieldEvent.Run()
else
set last.next = shieldEvent
set last = last.next
endif
endmethod
private static method Run takes nothing returns nothing
local ShieldEvent shEvent
local real ev
local ShieldWielder wielder
loop
exitwhen first == 0
set shEvent = first
set wielder = ShieldEngine.GetUnitWielder(shEvent.shield.wielder)
if shEvent.eventType == SHIELD_EVENT_CREATED then
set ev = 1.00
loop
exitwhen ev > MAX_PRESHIELD_CREATION_EVENTS
// Set GUI vars
call shEvent.setEventVariables()
// Fire PreCreation event
set udg_PreShieldCreationEvent = 0.00
set udg_PreShieldCreationEvent = ev
set udg_PreShieldCreationEvent = 0.00
// Update fields in case event was caught and variables changed.
call shEvent.getEventVariables()
set ev = ev + 1.00
endloop
if (not shEvent.shield.isTimed or shEvent.shield.timeLeft > 0.00) /*
*/ and (not shEvent.shield.breakAtZero or shEvent.shield.currentHP > 0.00) /*
*/ then
// Attach shield to wielder
call wielder.AddShield(shEvent.shield)
// Set GUI vars
call shEvent.setEventVariables()
// Fire ShieldCreated event
set udg_ShieldCreatedEvent = 0.00
set udg_ShieldCreatedEvent = 1.00
set udg_ShieldCreatedEvent = 0.00
endif
elseif shEvent.eventType == SHIELD_EVENT_ABSORB then
// Set GUI vars
call shEvent.setEventVariables()
set udg_ShieldAbsorbEvent = 0.00
set udg_ShieldAbsorbEvent = 1.00
set udg_ShieldAbsorbEvent = 0.00
// Update fields in case event was caught and variables changed.
call shEvent.getEventVariables()
elseif shEvent.eventType == SHIELD_EVENT_EXPIRE then
// Set GUI vars
call shEvent.setEventVariables()
set udg_ShieldExpiredEvent = 0.00
set udg_ShieldExpiredEvent = 1.00
set udg_ShieldExpiredEvent = 0.00
call shEvent.shield.destroy()
elseif shEvent.eventType == SHIELD_EVENT_BREAK then
// Set GUI vars
call shEvent.setEventVariables()
set udg_ShieldBreakEvent = 0.00
set udg_ShieldBreakEvent = 1.00
set udg_ShieldBreakEvent = 0.00
call shEvent.shield.destroy()
elseif shEvent.eventType == SHIELD_EVENT_REFRESHED then
// Set GUI vars
call shEvent.setEventVariables()
set udg_ShieldRefreshedEvent = 0.00
set udg_ShieldRefreshedEvent = 1.00
set udg_ShieldRefreshedEvent = 0.00
// Update fields in case event was caught and variables changed.
call shEvent.getEventVariables()
elseif shEvent.eventType == SHIELD_EVENT_STACKED then
// Set GUI vars
call shEvent.setEventVariables()
set udg_ShieldStackedEvent = 0.00
set udg_ShieldStackedEvent = 1.00
set udg_ShieldStackedEvent = 0.00
// Update fields in case event was caught and variables changed.
call shEvent.getEventVariables()
endif
// Resets variables
call resetEventVariables()
// Set the next ShieldEvent that will be run
set first = shEvent.next
// Free resources
call shEvent.destroy()
endloop
endmethod
private static method onInit takes nothing returns nothing
set first = 0
set last = 0
endmethod
endstruct
struct ShieldEngine
/*
Shared variables
*/
private static timer clock
private static timer tickTimer
private static trigger preReducTrigger
private static trigger postReducTrigger
private static trigger tickTrigger
private static trigger unregisterTrigger
private static boolean array isInSystem
private static ShieldWielder array unitToWielder
private static ShieldWielder firstWielder
private static ShieldWielder lastWielder
private static method ApplyShields takes integer procType returns nothing
local Shield shield //= 0
local real blockedDmg
local unit dmgTarget = udg_DamageEventTarget
local integer uId = GetUnitUserData(dmgTarget)
local ShieldWielder wielder = unitToWielder[uId]
local boolean isDmgSpell = udg_IsDamageSpell
local boolean isDmgAtt = udg_IsDamageAttack
set wielder.lastDamageTaken = TimerGetElapsed(clock)
/*
Loop through shields, applying one by one until either no shield left or no damage left
Shields order criterias
1/ Shield that can only take specific damage (only spell/attack) before shields that can absorb all
2/ Shield that nullify one instance of damage before those blocking amount of damage
3/ Order by timeLeft
*/
if procType == SHIELD_PROC_PREREDUC then
if isDmgSpell then
set shield = wielder.firstPreReducSpell
elseif isDmgAtt then
set shield = wielder.firstPreReducAttack
endif
elseif procType == SHIELD_PROC_POSTREDUC then
if isDmgSpell then
set shield = wielder.firstPostReducSpell
elseif isDmgAtt then
set shield = wielder.firstPostReducAttack
endif
endif
// Loop through shields against specific damage
loop
exitwhen shield == 0 or udg_DamageEventAmount == 0.00
if shield.shieldType == SHIELD_TYPE_INSTANCE and shield.currentHP >= 1.00 then
set shield.lastAbsorbedDamage = udg_DamageEventAmount
set shield.lastAbsorbedDamageSource = udg_DamageEventSource
set udg_DamageEventAmount = 0.00
set shield.currentHP = shield.currentHP - 1.00
call wielder.AdjustBarAfterDamage(shield.shieldHpType, 1.00)
call ShieldEvent.FireEvent(SHIELD_EVENT_ABSORB, shield)
if shield.currentHP == 0 and shield.breakAtZero then
call wielder.RemoveShield(shield)
call ShieldEvent.FireEvent(SHIELD_EVENT_BREAK, shield)
endif
elseif shield.shieldType == SHIELD_TYPE_HP_BASED and shield.currentHP >= 0.00 then
if shield.currentHP > udg_DamageEventAmount then
set shield.currentHP = shield.currentHP - udg_DamageEventAmount
call wielder.AdjustBarAfterDamage(shield.shieldHpType, udg_DamageEventAmount)
set shield.lastAbsorbedDamage = udg_DamageEventAmount
set shield.lastAbsorbedDamageSource = udg_DamageEventSource
set udg_DamageEventAmount = 0.00
call ShieldEvent.FireEvent(SHIELD_EVENT_ABSORB, shield)
else
set udg_DamageEventAmount = udg_DamageEventAmount - shield.currentHP
call wielder.AdjustBarAfterDamage(shield.shieldHpType, shield.currentHP)
set shield.lastAbsorbedDamage = shield.currentHP
set shield.lastAbsorbedDamageSource = udg_DamageEventSource
set shield.currentHP = 0.00
call ShieldEvent.FireEvent(SHIELD_EVENT_ABSORB, shield)
if shield.breakAtZero then
call wielder.RemoveShield(shield)
call ShieldEvent.FireEvent(SHIELD_EVENT_BREAK, shield)
endif
endif
endif
set shield = shield.next
endloop
if procType == SHIELD_PROC_PREREDUC then
set shield = wielder.firstPreReduc
elseif procType == SHIELD_PROC_POSTREDUC then
set shield = wielder.firstPostReduc
endif
// Loop through shields against all type of damage
loop
exitwhen shield == 0 or udg_DamageEventAmount == 0.00
if shield.shieldType == SHIELD_TYPE_INSTANCE and shield.currentHP >= 1.00 then
set shield.lastAbsorbedDamage = udg_DamageEventAmount
set shield.lastAbsorbedDamageSource = udg_DamageEventSource
set udg_DamageEventAmount = 0.00
set shield.currentHP = shield.currentHP - 1.00
call wielder.AdjustBarAfterDamage(shield.shieldHpType, 1.00)
call ShieldEvent.FireEvent(SHIELD_EVENT_ABSORB, shield)
if shield.currentHP == 0 and shield.breakAtZero then
call wielder.RemoveShield(shield)
call ShieldEvent.FireEvent(SHIELD_EVENT_BREAK, shield)
endif
elseif shield.shieldType == SHIELD_TYPE_HP_BASED and shield.currentHP >= 0.00 then
if shield.currentHP > udg_DamageEventAmount then
set shield.currentHP = shield.currentHP - udg_DamageEventAmount
call wielder.AdjustBarAfterDamage(shield.shieldHpType, udg_DamageEventAmount)
set shield.lastAbsorbedDamage = udg_DamageEventAmount
set shield.lastAbsorbedDamageSource = udg_DamageEventSource
set udg_DamageEventAmount = 0.00
call ShieldEvent.FireEvent(SHIELD_EVENT_ABSORB, shield)
else
set udg_DamageEventAmount = udg_DamageEventAmount - shield.currentHP
call wielder.AdjustBarAfterDamage(shield.shieldHpType, shield.currentHP)
set shield.lastAbsorbedDamage = shield.currentHP
set shield.lastAbsorbedDamageSource = udg_DamageEventSource
set shield.currentHP = 0.00
call ShieldEvent.FireEvent(SHIELD_EVENT_ABSORB, shield)
if shield.breakAtZero then
call wielder.RemoveShield(shield)
call ShieldEvent.FireEvent(SHIELD_EVENT_BREAK, shield)
endif
endif
endif
set shield = shield.next
endloop
endmethod
private static method ApplyShieldPreReduc takes nothing returns nothing
call ShieldEngine.ApplyShields(SHIELD_PROC_PREREDUC)
endmethod
private static method ApplyShieldPostReduc takes nothing returns nothing
call ShieldEngine.ApplyShields(SHIELD_PROC_POSTREDUC)
endmethod
private static method ShieldTickLoop takes nothing returns nothing
local ShieldWielder wielder = firstWielder
local Shield shield
local Shield array listOfFirst
local integer i
// Update every shield of every shield wielder
loop
exitwhen wielder == 0
set listOfFirst[0] = wielder.firstPreReduc
set listOfFirst[1] = wielder.firstPostReduc
set listOfFirst[2] = wielder.firstPreReducAttack
set listOfFirst[3] = wielder.firstPostReducAttack
set listOfFirst[4] = wielder.firstPreReducSpell
set listOfFirst[5] = wielder.firstPostReducSpell
set i = 0
loop
exitwhen i > 5
set shield = listOfFirst[i]
loop
exitwhen shield == 0
if shield.canRegen and shield.currentHP != shield.maxHP and (TimerGetElapsed(clock) - wielder.lastDamageTaken > shield.timeBeforeRegen) then
set shield.currentHP = RMinBJ(shield.maxHP, shield.currentHP + shield.regenPerTick)
if shield.shieldHpType == SHIELD_HP_TYPE_ALL then
set wielder.totalCurrentShield = wielder.totalCurrentShield + shield.regenPerTick
elseif shield.shieldType == SHIELD_HP_TYPE_SPELL then
set wielder.totalCurrentSpellShield = wielder.totalCurrentSpellShield + shield.regenPerTick
elseif shield.shieldType == SHIELD_HP_TYPE_ATTACK then
set wielder.totalCurrentAttackShield = wielder.totalCurrentAttackShield + shield.regenPerTick
endif
endif
if shield.isTimed then
set shield.timeLeft = shield.timeLeft - SHIELD_TICK_INTERVAL
if shield.timeLeft <= 0.00 then
call wielder.RemoveShield(shield)
call ShieldEvent.FireEvent(SHIELD_EVENT_EXPIRE, shield)
endif
endif
set shield = shield.next
endloop
set i = i +1
endloop
set wielder = wielder.next
endloop
endmethod
public static method GetUnitWielder takes unit u returns ShieldWielder
local integer uId = GetUnitUserData(u)
if isInSystem[uId] then
return unitToWielder[uId]
endif
return 0
endmethod
private static method IsUnitInSytem takes nothing returns boolean
local integer uId = GetUnitUserData(udg_DamageEventTarget)
return isInSystem[uId]
endmethod
private static method onInit takes nothing returns nothing
/*
================================================
TRIGGERS
================================================
*/
set clock = CreateTimer()
set tickTimer = CreateTimer()
set preReducTrigger = CreateTrigger()
set postReducTrigger = CreateTrigger()
set tickTrigger = CreateTrigger()
set unregisterTrigger = CreateTrigger()
call StartTimerBJ(clock, true, 99999.00)
call StartTimerBJ(tickTimer, true, SHIELD_TICK_INTERVAL)
// Check shields before damage reduction
call TriggerRegisterVariableEvent(preReducTrigger, "udg_PreDamageEvent", EQUAL, 1.00)
call TriggerAddAction(preReducTrigger, function ShieldEngine.ApplyShieldPreReduc)
call TriggerAddCondition(preReducTrigger, function ShieldEngine.IsUnitInSytem)
// Check shields after damage reduction
call TriggerRegisterVariableEvent(postReducTrigger, "udg_ArmorDamageEvent", EQUAL, 1.00)
call TriggerAddAction(postReducTrigger, function ShieldEngine.ApplyShieldPostReduc)
call TriggerAddCondition(preReducTrigger, function ShieldEngine.IsUnitInSytem)
// Loop Trigger for duration and regeneration
call TriggerRegisterTimerExpireEvent(tickTrigger, tickTimer)
call TriggerAddAction(tickTrigger, function ShieldEngine.ShieldTickLoop)
// Remove a unit from system if it is unindex by UnitEvent
call TriggerRegisterVariableEvent(unregisterTrigger, "udg_UnitIndexEvent", EQUAL, 2.00)
call TriggerRegisterVariableEvent(unregisterTrigger, "udg_DeathEvent", EQUAL, 0.50)
call TriggerRegisterVariableEvent(unregisterTrigger, "udg_DeathEvent", EQUAL, 1.00)
call TriggerRegisterVariableEvent(unregisterTrigger, "udg_DeathEvent", EQUAL, 3.00)
call TriggerAddAction(unregisterTrigger, function ShieldEngine.RemoveUnitFromSystem)
// Disable triggers until a unit is registered
call DisableTrigger(preReducTrigger)
call DisableTrigger(postReducTrigger)
call DisableTrigger(tickTrigger)
/*
================================================
Struct members init
================================================
*/
set firstWielder = 0
set lastWielder = 0
/*
================================================
GUI VARIABLES
================================================
*/
set udg_SHIELD_PROC_PREREDUC = SHIELD_PROC_PREREDUC
set udg_SHIELD_PROC_POSTREDUC = SHIELD_PROC_POSTREDUC
set udg_SHIELD_TYPE_HP_BASED = SHIELD_TYPE_HP_BASED
set udg_SHIELD_TYPE_INSTANCE = SHIELD_TYPE_INSTANCE
set udg_SHIELD_HP_TYPE_ALL = SHIELD_HP_TYPE_ALL
set udg_SHIELD_HP_TYPE_SPELL = SHIELD_HP_TYPE_SPELL
set udg_SHIELD_HP_TYPE_ATTACK = SHIELD_HP_TYPE_ATTACK
endmethod
public static method RemoveUnitFromSystem takes nothing returns nothing
local integer uId = udg_UDex
local ShieldWielder wielder
if isInSystem[uId] then
set wielder = unitToWielder[uId]
call ShieldEngine.RemoveAllShields(wielder.wielder)
endif
endmethod
public static method CheckRemoveWielder takes ShieldWielder wielder returns nothing
if wielder.totalMaxShield == 0.00 /*
*/ and wielder.totalMaxSpellShield == 0.00 /*
*/ and wielder.totalMaxAttackShield == 0.00 /*
*/ then
if wielder == firstWielder then
set firstWielder = wielder.next
set isInSystem[GetUnitUserData(wielder.wielder)] = false
call wielder.destroy()
if firstWielder == 0 then
call DisableTrigger(preReducTrigger)
call DisableTrigger(postReducTrigger)
call DisableTrigger(tickTrigger)
endif
else
set wielder.prev.next = wielder.next
set wielder.next.prev = wielder.prev
set isInSystem[GetUnitUserData(wielder.wielder)] = false
call wielder.destroy()
endif
endif
endmethod
/*
================================================
SYSTEM API
================================================
*/
// Tells if a unit is shielded
public static method IsUnitShielded takes unit u returns boolean
local integer uId = GetUnitUserData(u)
return isInSystem[uId]
endmethod
// Tells if a unit is shielded AND if current total shield is greater than 0.
public static method UnitHasActiveShield takes unit u returns boolean
local ShieldWielder wielder = ShieldEngine.GetUnitWielder(u)
return ShieldEngine.UnitHasActiveShieldOfType(u, SHIELD_HP_TYPE_ALL) /*
*/ or ShieldEngine.UnitHasActiveShieldOfType(u, SHIELD_HP_TYPE_ATTACK) /*
*/ or ShieldEngine.UnitHasActiveShieldOfType(u, SHIELD_HP_TYPE_SPELL)
endmethod
public static method UnitHasActiveShieldOfType takes unit u, integer shieldHpType returns boolean
local ShieldWielder wielder = ShieldEngine.GetUnitWielder(u)
if wielder == 0 then
return false
endif
if shieldHpType == SHIELD_HP_TYPE_ALL then
return wielder.totalCurrentShield >= 1.0
elseif shieldHpType == SHIELD_HP_TYPE_ATTACK then
return wielder.totalCurrentAttackShield >= 1.0
else
return wielder.totalCurrentSpellShield >= 1.0
endif
endmethod
// Tells if unit has a specific shield
public static method UnitHasShield takes unit u, string name returns boolean
local ShieldWielder wielder = ShieldEngine.GetUnitWielder(u)
return wielder.HasShield(name)
endmethod
/*
The following methods remove/destroy shields.
Removing: No Event if fired, shield disappear without any trace.
Destroying: Shield Break Event is fired when destroying a shield.
*/
public static method RemoveShieldByName takes unit u, string name returns nothing
local ShieldWielder wielder = ShieldEngine.GetUnitWielder(u)
call wielder.RemoveShieldByName(name)
endmethod
public static method DestroyShieldByName takes unit u, string name returns nothing
local ShieldWielder wielder = ShieldEngine.GetUnitWielder(u)
call wielder.DestroyShieldByName(name)
endmethod
public static method RemoveShieldsByType takes unit u, integer hpType returns nothing
local ShieldWielder wielder = ShieldEngine.GetUnitWielder(u)
call wielder.RemoveShieldsByType(hpType)
endmethod
public static method RemoveAllShields takes unit u returns nothing
local ShieldWielder wielder = ShieldEngine.GetUnitWielder(u)
call wielder.RemoveShieldsByType(SHIELD_HP_TYPE_ALL)
call wielder.RemoveShieldsByType(SHIELD_HP_TYPE_SPELL)
call wielder.RemoveShieldsByType(SHIELD_HP_TYPE_ATTACK)
endmethod
public static method DestroyShieldsByType takes unit u, integer hpType returns nothing
local ShieldWielder wielder = ShieldEngine.GetUnitWielder(u)
call wielder.DestroyShieldsByType(hpType)
endmethod
public static method DestroyAllShields takes unit u returns nothing
local ShieldWielder wielder = ShieldEngine.GetUnitWielder(u)
call wielder.DestroyShieldsByType(SHIELD_HP_TYPE_ALL)
call wielder.DestroyShieldsByType(SHIELD_HP_TYPE_SPELL)
call wielder.DestroyShieldsByType(SHIELD_HP_TYPE_ATTACK)
endmethod
/*
================================================
ENTRY POINT
================================================
*/
public static method CreateShield takes /*
*/ unit source, /*
*/ unit target, /*
*/ string name, /*
*/ string sfxPath, /*
*/ string attachPoint, /*
*/ integer shieldProcType, /*
*/ integer shieldType, /*
*/ integer shieldHpType, /*
*/ boolean isStackable, /*
*/ boolean isTimed, /*
*/ real duration, /*
*/ real HP, /*
*/ boolean breakAtZero, /*
*/ boolean canRegen, /*
*/ real timeBeforeRegen, /*
*/ real regenTime /*
*/ returns nothing
local integer uId = GetUnitUserData(target)
local ShieldWielder wielder
local Shield shield
if isInSystem[uId] then
set wielder = unitToWielder[uId]
else
set wielder = ShieldWielder.create(target)
set unitToWielder[uId] = wielder
set isInSystem[uId] = true
if firstWielder == 0 then
set firstWielder = wielder
set lastWielder = wielder
call EnableTrigger(preReducTrigger)
call EnableTrigger(postReducTrigger)
call EnableTrigger(tickTrigger)
else
set wielder.prev = lastWielder
set lastWielder.next = wielder
set lastWielder = lastWielder.next
endif
endif
// Check if shield with same name and types exist
set shield = wielder.FindShieldByNameAndTypes(name, shieldProcType, shieldType, shieldHpType)
// If didn't exist, create new one
if shield == 0 then
set shield = Shield.create(source, target, name, sfxPath, attachPoint, shieldProcType, shieldType, shieldHpType, isStackable, isTimed, duration, HP, breakAtZero, canRegen, timeBeforeRegen, regenTime)
call ShieldEvent.FireEvent(SHIELD_EVENT_CREATED, shield)
else
// if both previous shield and new are stackable, then stack, else refresh
if shield.isStackable and isStackable then
call shield.Stack(duration, HP)
else
call shield.Refresh(duration, HP)
endif
endif
endmethod
/*
================================================
SIMPLIFIED FUNCTIONS
================================================
*/
public static method CreateTimedShield takes unit source, unit target, string name, real duration, real HP returns nothing
call ShieldEngine.CreateShield(source, target, name, SHIELD_DEFAULT_SFX_PATH, SHIELD_DEFAULT_ATTACH_POINT, SHIELD_PROC_POSTREDUC, SHIELD_TYPE_HP_BASED, SHIELD_HP_TYPE_ALL, false, true, duration, HP, true, false, 0.0, 0.0)
endmethod
public static method CreateInstanceShield takes unit source, unit target, string name, real HP returns nothing
call ShieldEngine.CreateShield(source, target, name, SHIELD_DEFAULT_SFX_PATH, SHIELD_DEFAULT_ATTACH_POINT, SHIELD_PROC_PREREDUC, SHIELD_TYPE_INSTANCE, SHIELD_HP_TYPE_ALL, false, false, 0.0, HP, true, false, 0.0, 0.0)
endmethod
endstruct
endlibrary