- Joined
- Aug 1, 2013
- Messages
- 4,658
Hi all.
I was working on a new Damage System so I could have full possibilities with stuff related to damage.
I created a damage structure that resulted in this:
(I use regular real variables to simulate events because it can be used in GUI as well.)
(When the system works 100%, I will place the ApplyDamage's code at it's return addresses like I should.
The 0.9 on fatal damage is because the units still die when a value like 0.5 is used, but I dont want to do 1 because that would display 2 health in WC3.)
After a while, someone suggested to make it detect damage as well so I tried adding some stuff.
The more I came to think of nice stuff, the better the system became.
Right now, I think that the system is pretty much finished but there might be a few things that could be better than what they are currently.
So if anyone has any comments on the coding, please tell them.
So after a while, this is the current completed version of the damage system together with a JASS Variable list:
I have also made a Combat text extension so you can easily visually see the damage:
There are also a few spells that show you how the system should be used.
Originally, the system was not intended to do the detection of damage so there is a template for physical spell damage for example:
Also, the paladin is invulnerable for fatal damage (damage that would reduce health below 0).
And the Paladin takes recoil damage on his basic attacks equal to 30% of the damage dealt:
(The GetDamageTypeFactor() etc, are the functions that slow down this system dramatically.
I made those to get as close as possible to the original damage which could be very crucial in some spells. (just for perfection)
But as you might understand, it is actually required for detection of damage.)
I forgot to do the credits:
- to lookin_for_help for the idea of the reversed spell damage and making artillery damage explode units.
- to Nestharus and edo494 for helping with the concept and structure.
- to Bribe for his Unit Indexer.
I hope that I have said everything that I wanted to say... I actually start to forget things when things get so complicated as this.
Map attached in comment.
I was working on a new Damage System so I could have full possibilities with stuff related to damage.
I created a damage structure that resulted in this:
(I use regular real variables to simulate events because it can be used in GUI as well.)
JASS:
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Damage Structure
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
library adeEngine
function ApplyDamage takes unit source, unit target, real amount, attacktype at, damagetype dt returns nothing
call UnitRemoveAbility(target, udg_ADE_ABILITY_REVERT_SPELL_DMG)
call DisableTrigger(udg_ADE_Trigger_On_Damage)
call UnitDamageTarget(source, target, amount, true, false, at, dt, WEAPON_TYPE_WHOKNOWS)
call EnableTrigger(udg_ADE_Trigger_On_Damage)
call UnitAddAbility(target, udg_ADE_ABILITY_REVERT_SPELL_DMG)
endfunction
function ADE_CreateNewIndex takes nothing returns integer
set udg_ADE_NewIndex = 0
loop
exitwhen not udg_ADE_Param_Index_Exists[udg_ADE_NewIndex]
set udg_ADE_NewIndex = udg_ADE_NewIndex + 1
endloop
set udg_ADE_Param_Index_Exists[udg_ADE_NewIndex] = true
set udg_ADE_Param_Source[udg_ADE_NewIndex] = null
set udg_ADE_Param_Target[udg_ADE_NewIndex] = null
set udg_ADE_Param_Amount[udg_ADE_NewIndex] = 0
set udg_ADE_Param_Modifier[udg_ADE_NewIndex] = 1
set udg_ADE_Param_ActualAmount[udg_ADE_NewIndex] = 0
set udg_ADE_Param_Blocked[udg_ADE_NewIndex] = false
set udg_ADE_Param_PreventFatalDamage[udg_ADE_NewIndex] = false
set udg_ADE_Param_AttackType[udg_ADE_NewIndex] = 0
set udg_ADE_Param_DamageType[udg_ADE_NewIndex] = 0
set udg_ADE_Param_HitType[udg_ADE_NewIndex] = 0
set udg_ADE_Event_Damage_Created = 1
set udg_ADE_Event_Damage_Created = 0
return udg_ADE_NewIndex
endfunction
function ADE_InvokeDamage takes integer index returns boolean
local integer oldIndex = udg_ADE_Index
local boolean result = false
local real health
local real factor
set udg_ADE_Index = index
set udg_ADE_Event_OnDamage_Before = 1
set udg_ADE_Event_OnDamage_Before = 0
set udg_ADE_Param_Amount[udg_ADE_Index] = udg_ADE_Param_Amount[udg_ADE_Index] * udg_ADE_Param_Modifier[udg_ADE_Index]
if udg_ADE_Param_Blocked[udg_ADE_Index] then
set udg_ADE_Event_Attack_Blocked = 1
set udg_ADE_Event_Attack_Blocked = 0
else
set health = GetWidgetLife(udg_ADE_Param_Target[udg_ADE_Index])
set factor = GetAttackAndDamageTypeFactor(udg_ADE_Param_Target[udg_ADE_Index], ConvertAttackType(udg_ADE_Param_AttackType[udg_ADE_Index]), ConvertDamageType(udg_ADE_Param_DamageType[udg_ADE_Index]))
if health <= udg_ADE_Param_Amount[udg_ADE_Index] * factor then
set udg_ADE_Event_Fatal_Damage = 1
set udg_ADE_Event_Fatal_Damage = 0
if udg_ADE_Param_PreventFatalDamage[udg_ADE_Index] then
set udg_ADE_Param_Amount[udg_ADE_Index] = (health-0.9) / factor
endif
endif
if not udg_ADE_Param_Blocked[udg_ADE_Index] then
call ApplyDamage(udg_ADE_Param_Source[udg_ADE_Index], udg_ADE_Param_Target[udg_ADE_Index], udg_ADE_Param_Amount[udg_ADE_Index], ConvertAttackType(udg_ADE_Param_AttackType[udg_ADE_Index]), ConvertDamageType(udg_ADE_Param_DamageType[udg_ADE_Index]))
set udg_ADE_Param_ActualAmount[udg_ADE_Index] = health - GetWidgetLife(udg_ADE_Param_Target[udg_ADE_Index])
set udg_ADE_Event_OnDamage_After = 1
set udg_ADE_Event_OnDamage_After = 0
set result = true
else
set udg_ADE_Event_Attack_Blocked = 1
set udg_ADE_Event_Attack_Blocked = 0
endif
endif
set udg_ADE_Event_Damage_Ended = 1
set udg_ADE_Event_Damage_Ended = 0
set udg_ADE_Param_Index_Exists[udg_ADE_Index] = false
set udg_ADE_Param_Source[udg_ADE_Index] = null
set udg_ADE_Param_Target[udg_ADE_Index] = null
set udg_ADE_Param_Amount[udg_ADE_Index] = 0
set udg_ADE_Param_Modifier[udg_ADE_Index] = 1
set udg_ADE_Param_ActualAmount[udg_ADE_Index] = 0
set udg_ADE_Param_Blocked[udg_ADE_Index] = false
set udg_ADE_Param_PreventFatalDamage[udg_ADE_Index] = false
set udg_ADE_Param_AttackType[udg_ADE_Index] = 0
set udg_ADE_Param_DamageType[udg_ADE_Index] = 0
set udg_ADE_Param_HitType[udg_ADE_Index] = 0
set udg_ADE_Index = oldIndex
return result
endfunction
endlibrary
The 0.9 on fatal damage is because the units still die when a value like 0.5 is used, but I dont want to do 1 because that would display 2 health in WC3.)
After a while, someone suggested to make it detect damage as well so I tried adding some stuff.
The more I came to think of nice stuff, the better the system became.
Right now, I think that the system is pretty much finished but there might be a few things that could be better than what they are currently.
So if anyone has any comments on the coding, please tell them.
So after a while, this is the current completed version of the damage system together with a JASS Variable list:
JASS:
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Damage Structure
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
library adeEngine
globals
real udg_ADE_MinimumHealth = 0.415
boolean udg_ADE_TookFatalDamage = false
boolean array udg_ADE_Param_IsDetected
endglobals
function GetSpellDamageFactor takes unit whichUnit returns real
local real damage
local real oldHealth = GetWidgetLife(whichUnit)
call UnitAddAbility(whichUnit, udg_ADE_ABILITY_CHEAT_DEATH)
call SetWidgetLife(whichUnit, 250000)
call DisableTrigger(udg_ADE_Trigger_On_Damage)
set udg_ADE_PreventCodedDamage = true
call UnitDamageTarget(whichUnit, whichUnit, 100, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_UNIVERSAL, null)
set udg_ADE_PreventCodedDamage = false
call EnableTrigger(udg_ADE_Trigger_On_Damage)
set damage = 250000 - GetWidgetLife(whichUnit)
call UnitRemoveAbility(whichUnit, udg_ADE_ABILITY_CHEAT_DEATH)
call SetWidgetLife(whichUnit, oldHealth)
return damage / 100
endfunction
function ApplyDamage takes unit source, unit target, real amount, attacktype at, damagetype dt returns nothing
call UnitRemoveAbility(target, udg_ADE_ABILITY_REVERT_SPELL_DMG)
call DisableTrigger(udg_ADE_Trigger_On_Damage)
set udg_ADE_PreventCodedDamage = true
call UnitDamageTarget(source, target, amount, true, false, at, dt, null)
set udg_ADE_PreventCodedDamage = false
call EnableTrigger(udg_ADE_Trigger_On_Damage)
call UnitAddAbility(target, udg_ADE_ABILITY_REVERT_SPELL_DMG)
endfunction
function GetDamageTypeFactor takes unit whichUnit, damagetype whichDamageType returns real
local real damage
local real oldHealth = GetWidgetLife(whichUnit)
call UnitAddAbility(whichUnit, udg_ADE_ABILITY_CHEAT_DEATH)
call SetWidgetLife(whichUnit, 250000)
call ApplyDamage(whichUnit, whichUnit, 100, udg_ATTACK_TYPE_100, whichDamageType)
set damage = 250000 - GetWidgetLife(whichUnit)
call UnitRemoveAbility(whichUnit, udg_ADE_ABILITY_CHEAT_DEATH)
call SetWidgetLife(whichUnit, oldHealth)
return damage / 100
endfunction
function GetAttackTypeFactor takes unit whichUnit, attacktype whichAttackType returns real
local real damage
local real oldHealth = GetWidgetLife(whichUnit)
call UnitAddAbility(whichUnit, udg_ADE_ABILITY_CHEAT_DEATH)
call SetWidgetLife(whichUnit, 250000)
call ApplyDamage(whichUnit, whichUnit, 100, whichAttackType, DAMAGE_TYPE_UNIVERSAL)
set damage = 250000 - GetWidgetLife(whichUnit)
call UnitRemoveAbility(whichUnit, udg_ADE_ABILITY_CHEAT_DEATH)
call SetWidgetLife(whichUnit, oldHealth)
return damage / 100
endfunction
function GetAttackAndDamageTypeFactor takes unit whichUnit, attacktype whichAttackType, damagetype whichDamageType returns real
local real damage
local real oldHealth = GetWidgetLife(whichUnit)
call UnitAddAbility(whichUnit, udg_ADE_ABILITY_CHEAT_DEATH)
call SetWidgetLife(whichUnit, 250000)
call ApplyDamage(whichUnit, whichUnit, 100, whichAttackType, whichDamageType)
set damage = 250000 - GetWidgetLife(whichUnit)
call UnitRemoveAbility(whichUnit, udg_ADE_ABILITY_CHEAT_DEATH)
call SetWidgetLife(whichUnit, oldHealth)
return damage / 100
endfunction
function ADE_CreateNewIndex takes nothing returns integer
set udg_ADE_NewIndex = 0
loop
exitwhen not udg_ADE_Param_Index_Exists[udg_ADE_NewIndex]
set udg_ADE_NewIndex = udg_ADE_NewIndex + 1
endloop
set udg_ADE_Param_Index_Exists[udg_ADE_NewIndex] = true
set udg_ADE_Param_Source[udg_ADE_NewIndex] = null
set udg_ADE_Param_Target[udg_ADE_NewIndex] = null
set udg_ADE_Param_Amount[udg_ADE_NewIndex] = 0
set udg_ADE_Param_Modifier[udg_ADE_NewIndex] = 1
set udg_ADE_Param_ActualAmount[udg_ADE_NewIndex] = 0
set udg_ADE_Param_Blocked[udg_ADE_NewIndex] = false
set udg_ADE_Param_PreventFatalDamage[udg_ADE_NewIndex] = false
set udg_ADE_Param_AttackType[udg_ADE_NewIndex] = 0
set udg_ADE_Param_DamageType[udg_ADE_NewIndex] = 0
set udg_ADE_Param_HitType[udg_ADE_NewIndex] = 0
set udg_ADE_Param_IsDetected[udg_ADE_NewIndex] = false
set udg_ADE_Event_Damage_Created = 1
set udg_ADE_Event_Damage_Created = 0
return udg_ADE_NewIndex
endfunction
function ADE_InvokeDamage takes integer index returns boolean
local integer oldIndex = udg_ADE_Index
local boolean result = false
local real health
local real mana
local real factor
local boolean fatalDamage = false
local unit oldSource = udg_ADE_Param_Source[udg_ADE_Index]
set udg_ADE_Index = index
set udg_ADE_Event_OnDamage_Before = 1
set udg_ADE_Event_OnDamage_Before = 0
set udg_ADE_Param_Amount[udg_ADE_Index] = udg_ADE_Param_Amount[udg_ADE_Index] * udg_ADE_Param_Modifier[udg_ADE_Index]
if udg_ADE_Param_Blocked[udg_ADE_Index] then
set udg_ADE_Event_Attack_Blocked = 1
set udg_ADE_Event_Attack_Blocked = 0
else
set health = GetWidgetLife(udg_ADE_Param_Target[udg_ADE_Index])
set factor = GetAttackAndDamageTypeFactor(udg_ADE_Param_Target[udg_ADE_Index], ConvertAttackType(udg_ADE_Param_AttackType[udg_ADE_Index]), ConvertDamageType(udg_ADE_Param_DamageType[udg_ADE_Index]))
set fatalDamage = health <= udg_ADE_Param_Amount[udg_ADE_Index] * factor
if fatalDamage then
set udg_ADE_Event_Fatal_Damage = 1
set udg_ADE_Event_Fatal_Damage = 0
if udg_ADE_Param_PreventFatalDamage[udg_ADE_Index] then
set udg_ADE_Param_Amount[udg_ADE_Index] = (health-0.9) / factor
set fatalDamage = false
endif
endif
if not udg_ADE_Param_Blocked[udg_ADE_Index] then
if fatalDamage and udg_ADE_Param_IsDetected[udg_ADE_Index] and udg_ADE_Param_Source[udg_ADE_Index] == oldSource then
call SetWidgetLife(udg_ADE_Param_Target[udg_ADE_Index], udg_ADE_MinimumHealth)
set udg_ADE_Param_ActualAmount[udg_ADE_Index] = health
else
set fatalDamage = false
set health = GetWidgetLife(udg_ADE_Param_Target[udg_ADE_Index])
set mana = GetUnitState(udg_ADE_Param_Target[udg_ADE_Index], UNIT_STATE_MANA)
call ApplyDamage(udg_ADE_Param_Source[udg_ADE_Index], udg_ADE_Param_Target[udg_ADE_Index], udg_ADE_Param_Amount[udg_ADE_Index], ConvertAttackType(udg_ADE_Param_AttackType[udg_ADE_Index]), ConvertDamageType(udg_ADE_Param_DamageType[udg_ADE_Index]))
set udg_ADE_Param_ActualAmount[udg_ADE_Index] = (health - GetWidgetLife(udg_ADE_Param_Target[udg_ADE_Index])) + (mana - GetUnitState(udg_ADE_Param_Target[udg_ADE_Index], UNIT_STATE_MANA))
endif
set oldSource = null
set udg_ADE_Event_OnDamage_After = 1
set udg_ADE_Event_OnDamage_After = 0
set result = true
else
set fatalDamage = false
set udg_ADE_Event_Attack_Blocked = 1
set udg_ADE_Event_Attack_Blocked = 0
endif
endif
set udg_ADE_Event_Damage_Ended = 1
set udg_ADE_Event_Damage_Ended = 0
set udg_ADE_TookFatalDamage = fatalDamage
set udg_ADE_Param_Index_Exists[udg_ADE_Index] = false
set udg_ADE_Param_Source[udg_ADE_Index] = null
set udg_ADE_Param_Target[udg_ADE_Index] = null
set udg_ADE_Param_Amount[udg_ADE_Index] = 0
set udg_ADE_Param_Modifier[udg_ADE_Index] = 1
set udg_ADE_Param_ActualAmount[udg_ADE_Index] = 0
set udg_ADE_Param_Blocked[udg_ADE_Index] = false
set udg_ADE_Param_PreventFatalDamage[udg_ADE_Index] = false
set udg_ADE_Param_AttackType[udg_ADE_Index] = 0
set udg_ADE_Param_DamageType[udg_ADE_Index] = 0
set udg_ADE_Param_HitType[udg_ADE_Index] = 0
set udg_ADE_Index = oldIndex
return result
endfunction
endlibrary
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Damage Detection
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
globals
trigger udg_ADE_Trigger_On_Damage = null
real udg_ADE_Reset_Interval = 60.
boolean udg_ADE_DontCheckForCheatDeath = false
boolean udg_ADE_PreventCodedDamage = false
integer udg_ADE_AbortNextDamage = 0
timer array udg_ADE_TimerArray
unit array udg_ADE_UnitArray
real array udg_ADE_HealthArray
endglobals
function ADE_Remove_Standard_Damage takes nothing returns nothing
local integer id = GetTimerData(GetExpiredTimer())
local integer unitId = GetUnitUserData(udg_ADE_UnitArray[id])
set udg_ADE_DontCheckForCheatDeath = true
call UnitRemoveAbility(udg_ADE_UnitArray[id], udg_ADE_ABILITY_CHEAT_DEATH)
call SetWidgetLife(udg_ADE_UnitArray[id], udg_ADE_HealthArray[id])
set udg_ADE_DontCheckForCheatDeath = false
call ReleaseIndexedTimer(udg_ADE_TimerArray[unitId])
set udg_ADE_TimerArray[unitId] = null
set udg_ADE_UnitArray[id] = null
set udg_ADE_HealthArray[id] = 0.
endfunction
function ADE_Taking_Damage takes nothing returns boolean
local unit target
local integer newIndex
local real amount
local integer id
local integer targetId
local timer t
set amount = GetEventDamage()
if amount == 0. then
return false
endif
set target = GetTriggerUnit()
set targetId = GetUnitUserData(target)
if udg_ADE_TimerArray[targetId] != null then
set t = udg_ADE_TimerArray[targetId]
set udg_ADE_TimerArray[targetId] = null
set id = GetTimerData(t)
call UnitRemoveAbility(target, udg_ADE_ABILITY_CHEAT_DEATH)
call SetWidgetLife(target, udg_ADE_HealthArray[id])
else
set t = NewIndexedTimer()
set id = GetTimerData(t)
endif
if udg_ADE_AbortNextDamage > 0 then
set udg_ADE_AbortNextDamage = udg_ADE_AbortNextDamage -1
else
if amount < 0. then
//Spell Damage
set amount = -amount
set newIndex = ADE_CreateNewIndex()
set udg_ADE_Param_Source[newIndex] = GetEventDamageSource()
set udg_ADE_Param_Target[newIndex] = target
set udg_ADE_Param_Amount[newIndex] = amount / -GetSpellDamageFactor(target)
set udg_ADE_Param_AttackType[newIndex] = udg_ATTACK_TYPE_NORMAL
set udg_ADE_Param_DamageType[newIndex] = udg_DAMAGE_TYPE_MAGIC
set udg_ADE_Param_HitType[newIndex] = udg_HIT_TYPE_SPELLDAMAGE
call ADE_InvokeDamage(newIndex)
else
//Basic attack
set newIndex = ADE_CreateNewIndex()
set udg_ADE_Param_Source[newIndex] = GetEventDamageSource()
set udg_ADE_Param_Target[newIndex] = target
set udg_ADE_Param_Amount[newIndex] = amount / GetDamageTypeFactor(target, DAMAGE_TYPE_NORMAL)
set udg_ADE_Param_AttackType[newIndex] = udg_ATTACK_TYPE_CHAOS
set udg_ADE_Param_DamageType[newIndex] = udg_DAMAGE_TYPE_NORMAL
set udg_ADE_Param_HitType[newIndex] = udg_HIT_TYPE_BASICATTACK
set udg_ADE_Param_IsDetected[newIndex] = true
call ADE_InvokeDamage(newIndex)
endif
endif
if udg_ADE_TookFatalDamage then
call ReleaseIndexedTimer(t)
set t = null
set udg_ADE_TimerArray[targetId] = null
set udg_ADE_UnitArray[id] = null
set udg_ADE_HealthArray[id] = 0.
else
set udg_ADE_TimerArray[targetId] = t
set t = null
call TimerStart(udg_ADE_TimerArray[targetId], 0, false, function ADE_Remove_Standard_Damage)
set udg_ADE_DontCheckForCheatDeath = true
set udg_ADE_UnitArray[id] = target
set udg_ADE_HealthArray[id] = GetWidgetLife(target)
call UnitAddAbility(target, udg_ADE_ABILITY_CHEAT_DEATH)
call SetWidgetLife(target, GetWidgetLife(target) + amount)
set udg_ADE_DontCheckForCheatDeath = false
endif
set target = null
return false
endfunction
function ADE_Add_Unit takes nothing returns boolean
local unit whichUnit = GetFilterUnit()
call TriggerRegisterUnitEvent(udg_ADE_Trigger_On_Damage, whichUnit, EVENT_UNIT_DAMAGED)
call UnitAddAbility(whichUnit, udg_ADE_ABILITY_REVERT_SPELL_DMG)
set whichUnit = null
return false
endfunction
function ADE_Init_Damage_System takes nothing returns nothing
local group g = CreateGroup()
local unit FoG
call DestroyTrigger(udg_ADE_Trigger_On_Damage)
set udg_ADE_Trigger_On_Damage = CreateTrigger()
call GroupEnumUnitsInRect(g, GetWorldBounds(), null)
loop
set FoG = FirstOfGroup(g)
exitwhen FoG == null
call GroupRemoveUnit(g, FoG)
call TriggerRegisterUnitEvent(udg_ADE_Trigger_On_Damage, FoG, EVENT_UNIT_DAMAGED)
call UnitAddAbility(FoG, udg_ADE_ABILITY_REVERT_SPELL_DMG)
endloop
call DestroyGroup(g)
set g = null
call TriggerAddCondition(udg_ADE_Trigger_On_Damage, Filter(function ADE_Taking_Damage))
call DestroyTimer(GetExpiredTimer())
endfunction
function ADE_System_Initialize takes nothing returns nothing
local region rectRegion = CreateRegion()
local trigger t = CreateTrigger()
call TimerStart(CreateTimer(), udg_ADE_Reset_Interval, true, function ADE_Init_Damage_System)
call ADE_Init_Damage_System()
set t = CreateTrigger()
call RegionAddRect(rectRegion, GetWorldBounds())
call TriggerRegisterEnterRegion(t, rectRegion, Filter(function ADE_Add_Unit))
set rectRegion = null
set t = null
call DestroyTimer(GetExpiredTimer())
endfunction
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//===========================================================================================================================
//===========================================================================================================================
//===========================================================================================================================
function InitTrig_ADE_System takes nothing returns nothing
set udg_ATTACK_TYPE_NORMAL = 0
set udg_ATTACK_TYPE_MELEE = 1
set udg_ATTACK_TYPE_PIERCE = 2
set udg_ATTACK_TYPE_SIEGE = 3
set udg_ATTACK_TYPE_MAGIC = 4
set udg_ATTACK_TYPE_CHAOS = 5
set udg_ATTACK_TYPE_HERO = 6
set udg_ATTACK_TYPE_DOOM = 7
set udg_DAMAGE_TYPE_UNKNOWN = 0
set udg_DAMAGE_TYPE_NORMAL = 4
set udg_DAMAGE_TYPE_ENHANCED = 5
set udg_DAMAGE_TYPE_FIRE = 8
set udg_DAMAGE_TYPE_COLD = 9
set udg_DAMAGE_TYPE_LIGHTNING = 10
set udg_DAMAGE_TYPE_POISON = 11
set udg_DAMAGE_TYPE_DISEASE = 12
set udg_DAMAGE_TYPE_DIVINE = 13
set udg_DAMAGE_TYPE_MAGIC = 14
set udg_DAMAGE_TYPE_SONIC = 15
set udg_DAMAGE_TYPE_ACID = 16
set udg_DAMAGE_TYPE_FORCE = 17
set udg_DAMAGE_TYPE_DEATH = 18
set udg_DAMAGE_TYPE_MIND = 19
set udg_DAMAGE_TYPE_PLANT = 20
set udg_DAMAGE_TYPE_DEFENSIVE = 21
set udg_DAMAGE_TYPE_DEMOLITION = 22
set udg_DAMAGE_TYPE_SLOW_POISON = 23
set udg_DAMAGE_TYPE_SPIRIT_LINK = 24
set udg_DAMAGE_TYPE_SHADOW_STRIKE = 25
set udg_DAMAGE_TYPE_UNIVERSAL = 26
set udg_HIT_TYPE_BASICATTACK = 1
set udg_HIT_TYPE_SPELLDAMAGE = 2
set udg_HIT_TYPE_PUREDAMAGE = 3
set udg_ADE_Index = 0
set udg_ADE_Param_CodedHitType = udg_HIT_TYPE_SPELLDAMAGE
call TimerStart(CreateTimer(), 0, false, function ADE_System_Initialize)
endfunction
JASS:
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Native Hooks
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
globals
unit array udg_ADE_CodedPointDamage_Source
real array udg_ADE_CodedPointDamage_Radius
real array udg_ADE_CodedPointDamage_X
real array udg_ADE_CodedPointDamage_Y
real array udg_ADE_CodedPointDamage_Amount
integer array udg_ADE_CodedPointDamage_AttackType
integer array udg_ADE_CodedPointDamage_DamageType
integer array udg_ADE_CodedPointDamage_HitType
endglobals
function ADE_RemoveCheatDeath takes unit whichUnit returns nothing
local integer unitId = GetUnitUserData(whichUnit)
local integer id
if udg_ADE_TimerArray[unitId] != null then
if UnitRemoveAbility(whichUnit, udg_ADE_ABILITY_CHEAT_DEATH) then
set id = GetTimerData(udg_ADE_TimerArray[unitId])
set udg_ADE_DontCheckForCheatDeath = true
call SetWidgetLife(whichUnit, udg_ADE_HealthArray[id])
set udg_ADE_DontCheckForCheatDeath = false
call ReleaseIndexedTimer(udg_ADE_TimerArray[unitId])
set udg_ADE_UnitArray[id] = null
set udg_ADE_HealthArray[id] = 0.
set udg_ADE_TimerArray[unitId] = null
endif
endif
endfunction
//Set life hooks.
function ADE_SetWidgetLife takes widget whichWidget, real newLife returns nothing
if not udg_ADE_DontCheckForCheatDeath then
call ADE_RemoveCheatDeath(Handle2Unit(whichWidget))
endif
return
endfunction
hook SetWidgetLife ADE_SetWidgetLife
function ADE_SetUnitLifePercentBJ takes unit whichUnit, real percent returns nothing
call ADE_RemoveCheatDeath(whichUnit)
endfunction
hook SetUnitLifePercentBJ ADE_SetUnitLifePercentBJ
function ADE_SetUnitLifeBJ takes unit whichUnit, real newValue returns nothing
call ADE_RemoveCheatDeath(whichUnit)
endfunction
hook SetUnitLifeBJ ADE_SetUnitLifeBJ
//Get life hooks.
function ADE_GetWidgetLife takes widget whichWidget returns real
if not udg_ADE_DontCheckForCheatDeath then
call ADE_RemoveCheatDeath(Handle2Unit(whichWidget))
endif
return 0.
endfunction
hook GetWidgetLife ADE_GetWidgetLife
function ADE_GetUnitLifePercent takes unit whichUnit returns real
call ADE_RemoveCheatDeath(whichUnit)
return 0.
endfunction
hook GetUnitLifePercent ADE_GetUnitLifePercent
//Unit state hooks.
function ADE_GetUnitStateSwap takes unitstate whichState, unit whichUnit returns real
if whichState == UNIT_STATE_MAX_LIFE or whichState == UNIT_STATE_LIFE then
call ADE_RemoveCheatDeath(whichUnit)
endif
return 0.
endfunction
hook GetUnitStateSwap ADE_GetUnitStateSwap
//Damage hooks.
function ADE_ApplyCodedDamage_Target takes unit whichUnit, widget target, real amount, boolean attack, boolean ranged, attacktype attackType, damagetype damageType, weapontype weaponType returns boolean
local integer nextIndex
if udg_ADE_PreventCodedDamage then
return false
endif
set nextIndex = ADE_CreateNewIndex()
set udg_ADE_Param_Source[nextIndex] = whichUnit
set udg_ADE_Param_Target[nextIndex] = Handle2Unit(target)
set udg_ADE_Param_Amount[nextIndex] = amount
set udg_ADE_Param_AttackType[nextIndex] = ConvertAttackTypeReverse(attackType)
set udg_ADE_Param_DamageType[nextIndex] = ConvertDamageTypeReverse(damageType)
set udg_ADE_Param_HitType[nextIndex] = udg_ADE_Param_CodedHitType
call ADE_InvokeDamage(nextIndex)
set udg_ADE_Param_CodedHitType = udg_HIT_TYPE_SPELLDAMAGE
set udg_ADE_AbortNextDamage = udg_ADE_AbortNextDamage +1
return false
endfunction
hook UnitDamageTarget ADE_ApplyCodedDamage_Target
function ADE_ApplyCodedDamage_TargetBJ takes unit whichUnit, unit target, real amount, attacktype attackType, damagetype damageType returns boolean
local integer nextIndex
set nextIndex = ADE_CreateNewIndex()
set udg_ADE_Param_Source[nextIndex] = whichUnit
set udg_ADE_Param_Target[nextIndex] = Handle2Unit(target)
set udg_ADE_Param_Amount[nextIndex] = amount
set udg_ADE_Param_AttackType[nextIndex] = ConvertAttackTypeReverse(attackType)
set udg_ADE_Param_DamageType[nextIndex] = ConvertDamageTypeReverse(damageType)
set udg_ADE_Param_HitType[nextIndex] = udg_ADE_Param_CodedHitType
call ADE_InvokeDamage(nextIndex)
set udg_ADE_Param_CodedHitType = udg_HIT_TYPE_SPELLDAMAGE
set udg_ADE_AbortNextDamage = udg_ADE_AbortNextDamage +1
return false
endfunction
hook UnitDamageTargetBJ ADE_ApplyCodedDamage_TargetBJ
function ADE_ApplyCodedDamage_PointCallback takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer id = GetTimerData(t)
local group g = CreateGroup()
local unit FoG
local integer nextIndex
local integer amount = 0
call GroupEnumUnitsInRange(g, udg_ADE_CodedPointDamage_X[id], udg_ADE_CodedPointDamage_Y[id], udg_ADE_CodedPointDamage_Radius[id], null)
loop
set FoG = FirstOfGroup(g)
exitwhen FoG == null
call GroupRemoveUnit(g, FoG)
set nextIndex = ADE_CreateNewIndex()
set udg_ADE_Param_Source[nextIndex] = udg_ADE_CodedPointDamage_Source[id]
set udg_ADE_Param_Target[nextIndex] = FoG
set udg_ADE_Param_Amount[nextIndex] = udg_ADE_CodedPointDamage_Amount[id]
set udg_ADE_Param_AttackType[nextIndex] = udg_ADE_CodedPointDamage_AttackType[id]
set udg_ADE_Param_DamageType[nextIndex] = udg_ADE_CodedPointDamage_DamageType[id]
set udg_ADE_Param_HitType[nextIndex] = udg_ADE_CodedPointDamage_HitType[id]
call ADE_InvokeDamage(nextIndex)
set amount = amount + 1
endloop
call DestroyGroup(g)
set g = null
set udg_ADE_CodedPointDamage_Source[id] = null
set udg_ADE_Param_CodedHitType = udg_HIT_TYPE_SPELLDAMAGE
set udg_ADE_AbortNextDamage = udg_ADE_AbortNextDamage + amount
call ReleaseIndexedTimer(t)
set t = null
endfunction
function ADE_ApplyCodedDamage_Point takes unit whichUnit, real delay, real radius, real x, real y, real amount, boolean attack, boolean ranged, attacktype attackType, damagetype damageType, weapontype weaponType returns boolean
local timer t = NewIndexedTimer()
local integer id = GetTimerData(t)
call TimerStart(t, delay, false, function ADE_ApplyCodedDamage_PointCallback)
set udg_ADE_CodedPointDamage_Source[id] = whichUnit
set udg_ADE_CodedPointDamage_Radius[id] = radius
set udg_ADE_CodedPointDamage_X[id] = x
set udg_ADE_CodedPointDamage_Y[id] = y
set udg_ADE_CodedPointDamage_Amount[id] = amount
set udg_ADE_CodedPointDamage_AttackType[id] = ConvertAttackTypeReverse(attackType)
set udg_ADE_CodedPointDamage_DamageType[id] = ConvertDamageTypeReverse(damageType)
set udg_ADE_CodedPointDamage_HitType[id] = udg_ADE_Param_CodedHitType
set udg_ADE_Param_CodedHitType = udg_HIT_TYPE_SPELLDAMAGE
set t = null
return false
endfunction
hook UnitDamagePoint ADE_ApplyCodedDamage_Point
function ADE_ApplyCodedDamage_PointLoc takes unit whichUnit, real delay, real radius, location loc, real amount, attacktype attackType, damagetype damageType returns boolean
local timer t = NewIndexedTimer()
local integer id = GetTimerData(t)
call TimerStart(t, delay, false, function ADE_ApplyCodedDamage_PointCallback)
set udg_ADE_CodedPointDamage_Source[id] = whichUnit
set udg_ADE_CodedPointDamage_Radius[id] = radius
set udg_ADE_CodedPointDamage_X[id] = GetLocationX(loc)
set udg_ADE_CodedPointDamage_Y[id] = GetLocationY(loc)
set udg_ADE_CodedPointDamage_Amount[id] = amount
set udg_ADE_CodedPointDamage_AttackType[id] = ConvertAttackTypeReverse(attackType)
set udg_ADE_CodedPointDamage_DamageType[id] = ConvertDamageTypeReverse(damageType)
set udg_ADE_CodedPointDamage_HitType[id] = udg_ADE_Param_CodedHitType
set udg_ADE_Param_CodedHitType = udg_HIT_TYPE_SPELLDAMAGE
set t = null
return false
endfunction
hook UnitDamagePointLoc ADE_ApplyCodedDamage_PointLoc
I have also made a Combat text extension so you can easily visually see the damage:
JASS:
globals
integer array udg_ADE_CombatText_Color_Blue
integer array udg_ADE_CombatText_Color_Green
integer array udg_ADE_CombatText_Color_Red
string array udg_ADE_CombatText_String
endglobals
library combatText
function CreateCombatText takes string text, real size, real x, real y, integer red, integer green, integer blue returns nothing
local texttag tt = CreateTextTag()
local real angle = GetRandomReal(0, 90) + GetRandomReal(0, 90)
call SetTextTagText(tt, text, size)
call SetTextTagPos(tt, x, y, 40)
call SetTextTagColor(tt, red, green, blue, 255)
call SetTextTagVelocity(tt, 0.071 * Cos(angle * bj_DEGTORAD), 0.071 * Sin(angle * bj_DEGTORAD))
call SetTextTagPermanent(tt, false)
call SetTextTagLifespan(tt, 1.3)
call SetTextTagFadepoint(tt, 0.9)
set tt = null
endfunction
endlibrary
function ADE_CreateCombatText takes nothing returns boolean
local real size
if udg_ADE_Param_Blocked[udg_ADE_Index] then
set size = 0.0192
if udg_ADE_CombatText_String[udg_ADE_Index] == null then
set udg_ADE_CombatText_String[udg_ADE_Index] = "blocked"
endif
if udg_ADE_CombatText_Color_Red[udg_ADE_Index] > 255 then
set udg_ADE_CombatText_Color_Red[udg_ADE_Index] = 155
set udg_ADE_CombatText_Color_Green[udg_ADE_Index] = 155
set udg_ADE_CombatText_Color_Blue[udg_ADE_Index] = 155
endif
else
set size = 0.0158 + 0.00006 * udg_ADE_Param_ActualAmount[udg_ADE_Index]
set udg_ADE_CombatText_String[udg_ADE_Index] = I2S(R2I(udg_ADE_Param_ActualAmount[udg_ADE_Index]))
if udg_ADE_CombatText_Color_Red[udg_ADE_Index] > 255 then
//three of my favorite colors:
if udg_ADE_Param_DamageType[udg_ADE_Index] == udg_DAMAGE_TYPE_NORMAL then
set udg_ADE_CombatText_Color_Red[udg_ADE_Index] = 255
set udg_ADE_CombatText_Color_Green[udg_ADE_Index] = 128
set udg_ADE_CombatText_Color_Blue[udg_ADE_Index] = 0
elseif udg_ADE_Param_DamageType[udg_ADE_Index] == udg_DAMAGE_TYPE_MAGIC then
set udg_ADE_CombatText_Color_Red[udg_ADE_Index] = 255
set udg_ADE_CombatText_Color_Green[udg_ADE_Index] = 0
set udg_ADE_CombatText_Color_Blue[udg_ADE_Index] = 255
elseif udg_ADE_Param_DamageType[udg_ADE_Index] == udg_DAMAGE_TYPE_UNIVERSAL then
set udg_ADE_CombatText_Color_Red[udg_ADE_Index] = 255
set udg_ADE_CombatText_Color_Green[udg_ADE_Index] = 255
set udg_ADE_CombatText_Color_Blue[udg_ADE_Index] = 255
endif
endif
endif
if size > 0.345 then
set size = 0.345
endif
call CreateCombatText(udg_ADE_CombatText_String[udg_ADE_Index], size, GetWidgetX(udg_ADE_Param_Target[udg_ADE_Index]), GetWidgetY(udg_ADE_Param_Target[udg_ADE_Index]), udg_ADE_CombatText_Color_Red[udg_ADE_Index], udg_ADE_CombatText_Color_Green[udg_ADE_Index], udg_ADE_CombatText_Color_Blue[udg_ADE_Index])
return false
endfunction
function ADE_InitCombatText takes nothing returns boolean
set udg_ADE_CombatText_String[udg_ADE_NewIndex] = null
set udg_ADE_CombatText_Color_Red[udg_ADE_NewIndex] = 256
set udg_ADE_CombatText_Color_Green[udg_ADE_NewIndex] = 256
set udg_ADE_CombatText_Color_Blue[udg_ADE_NewIndex] = 256
return false
endfunction
//===========================================================================
function InitTrig_ADE_Combat_Text_Extension takes nothing returns nothing
local trigger t
set t = CreateTrigger()
call TriggerRegisterVariableEvent(t, "udg_ADE_Event_Damage_Ended", EQUAL, 0)
call TriggerAddCondition(t, Filter(function ADE_CreateCombatText))
set t = CreateTrigger()
call TriggerRegisterVariableEvent(t, "udg_ADE_Event_Damage_Created", EQUAL, 0)
call TriggerAddCondition(t, Filter(function ADE_InitCombatText))
set t = null
endfunction
There are also a few spells that show you how the system should be used.
Originally, the system was not intended to do the detection of damage so there is a template for physical spell damage for example:
-
MySpell
-
Events
-
Conditions
-
Actions
-
-------- PHYSICAL SPELL DAMAGE TEMPLATE --------
-
Custom script: call ADE_CreateNewIndex()
-
Set ADE_Param_Amount[ADE_NewIndex] = 100.00
-
Set ADE_Param_AttackType[ADE_NewIndex] = ATTACK_TYPE_MELEE
-
Set ADE_Param_DamageType[ADE_NewIndex] = DAMAGE_TYPE_NORMAL
-
Set ADE_Param_HitType[ADE_NewIndex] = HIT_TYPE_SPELLDAMAGE
-
Set ADE_Param_Source[ADE_NewIndex] = (Triggering unit)
-
Set ADE_Param_Target[ADE_NewIndex] = (Target unit of ability being cast)
-
Custom script: call ADE_InvokeDamage(udg_ADE_NewIndex)
-
-
-
Unit - Cause (Triggering unit) to damage (Target unit of ability being cast), dealing 100.00 damage of attack type Normal and damage type Normal
Also, the paladin is invulnerable for fatal damage (damage that would reduce health below 0).
-
Paladin Block Fatal Damage
-
Events
-
Game - ADE_Event_Fatal_Damage becomes Equal to 0.00
-
-
Conditions
-
Actions
-
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
-
If - Conditions
-
(Unit-type of ADE_Param_Target[ADE_Index]) Equal to Paladin
-
-
Then - Actions
-
Game - Display to (All players) the text: paladin took fatal ...
-
Set ADE_Param_PreventFatalDamage[ADE_Index] = True
-
-
Else - Actions
-
-
-
-
Far Seer Life Steal
-
Events
-
Game - ADE_Event_OnDamage_After becomes Equal to 0.00
-
-
Conditions
-
Actions
-
Custom script: local effect localEffect
-
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
-
If - Conditions
-
(Unit-type of ADE_Param_Source[ADE_Index]) Equal to Far Seer
-
ADE_Param_DamageType[ADE_Index] Equal to DAMAGE_TYPE_NORMAL
-
-
Then - Actions
-
-------- Somehow, heal doesnt play death animation when immediately destroyed. --------
-
-------- Could be that it has no death animation. --------
-
Special Effect - Create a special effect attached to the origin of ADE_Param_Source[ADE_Index] using Abilities\Spells\Human\Heal\HealTarget.mdl
-
Custom script: set localEffect = bj_lastCreatedEffect
-
Unit - Set life of ADE_Param_Source[ADE_Index] to ((Life of ADE_Param_Source[ADE_Index]) + (0.50 x ADE_Param_ActualAmount[ADE_Index]))
-
Wait 2.00 seconds
-
Custom script: call DestroyEffect(localEffect)
-
Custom script: set localEffect = null
-
-
Else - Actions
-
-
-
And the Paladin takes recoil damage on his basic attacks equal to 30% of the damage dealt:
-
Paladin Basic Attack Recoil
-
Events
-
Game - ADE_Event_OnDamage_After becomes Equal to 0.00
-
-
Conditions
-
Actions
-
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
-
If - Conditions
-
(Unit-type of ADE_Param_Source[ADE_Index]) Equal to Paladin
-
ADE_Param_HitType[ADE_Index] Equal to HIT_TYPE_BASICATTACK
-
-
Then - Actions
-
Unit - Cause ADE_Param_Source[ADE_Index] to damage ADE_Param_Source[ADE_Index], dealing (0.30 x ADE_Param_ActualAmount[ADE_Index]) damage of attack type Normal and damage type Normal
-
-
Else - Actions
-
-
-
(The GetDamageTypeFactor() etc, are the functions that slow down this system dramatically.
I made those to get as close as possible to the original damage which could be very crucial in some spells. (just for perfection)
But as you might understand, it is actually required for detection of damage.)
JASS:
globals
hashtable udg_TypeCastHashtable = InitHashtable()
endglobals
library typecasting
//BooleanExpr
function Integer2BooleanExpr takes integer i returns boolexpr
call SaveFogStateHandle(udg_TypeCastHashtable, 0, 0, ConvertFogState(i))
return LoadBooleanExprHandle(udg_TypeCastHashtable, 0, 0)
endfunction
function Handle2BooleanExpr takes handle h returns boolexpr
return Integer2BooleanExpr(GetHandleId(h))
endfunction
function BooleanExpr2Handle takes boolexpr b returns handle
return b
endfunction
//Button
function Integer2Button takes integer i returns button
call SaveFogStateHandle(udg_TypeCastHashtable, 0, 0, ConvertFogState(i))
return LoadButtonHandle(udg_TypeCastHashtable, 0, 0)
endfunction
function Handle2Button takes handle h returns button
return Integer2Button(GetHandleId(h))
endfunction
function Button2Handle takes button b returns handle
return b
endfunction
//DefeatCondition
function Integer2DefeatCondition takes integer i returns defeatcondition
call SaveFogStateHandle(udg_TypeCastHashtable, 0, 0, ConvertFogState(i))
return LoadDefeatConditionHandle(udg_TypeCastHashtable, 0, 0)
endfunction
function Handle2DefeatCondition takes handle h returns defeatcondition
return Integer2DefeatCondition(GetHandleId(h))
endfunction
function DefeatCondition2Handle takes defeatcondition d returns handle
return d
endfunction
//Destructable
function Integer2Destructable takes integer i returns destructable
call SaveFogStateHandle(udg_TypeCastHashtable, 0, 0, ConvertFogState(i))
return LoadDestructableHandle(udg_TypeCastHashtable, 0, 0)
endfunction
function Handle2Destructable takes handle h returns destructable
return Integer2Destructable(GetHandleId(h))
endfunction
function Destructable2Handle takes destructable d returns handle
return d
endfunction
//Dialog
function Integer2Dialog takes integer i returns dialog
call SaveFogStateHandle(udg_TypeCastHashtable, 0, 0, ConvertFogState(i))
return LoadDialogHandle(udg_TypeCastHashtable, 0, 0)
endfunction
function Handle2Dialog takes handle h returns dialog
return Integer2Dialog(GetHandleId(h))
endfunction
function Dialog2Handle takes dialog d returns handle
return d
endfunction
//Effect
function Integer2Effect takes integer i returns effect
call SaveFogStateHandle(udg_TypeCastHashtable, 0, 0, ConvertFogState(i))
return LoadEffectHandle(udg_TypeCastHashtable, 0, 0)
endfunction
function Handle2Effect takes handle h returns effect
return Integer2Effect(GetHandleId(h))
endfunction
function Effect2Handle takes effect e returns handle
return e
endfunction
//FogModifier
function Integer2FogModifier takes integer i returns fogmodifier
call SaveFogStateHandle(udg_TypeCastHashtable, 0, 0, ConvertFogState(i))
return LoadFogModifierHandle(udg_TypeCastHashtable, 0, 0)
endfunction
function Handle2FogModifier takes handle h returns fogmodifier
return Integer2FogModifier(GetHandleId(h))
endfunction
function FogModifier2Handle takes fogmodifier f returns handle
return f
endfunction
//FogState
function Integer2FogState takes integer i returns fogstate
call SaveFogStateHandle(udg_TypeCastHashtable, 0, 0, ConvertFogState(i))
return LoadFogStateHandle(udg_TypeCastHashtable, 0, 0)
endfunction
function Handle2FogState takes handle h returns fogstate
return Integer2FogState(GetHandleId(h))
endfunction
function FogState2Handle takes fogstate f returns handle
return f
endfunction
//Force
function Integer2Force takes integer i returns force
call SaveFogStateHandle(udg_TypeCastHashtable, 0, 0, ConvertFogState(i))
return LoadForceHandle(udg_TypeCastHashtable, 0, 0)
endfunction
function Handle2Force takes handle h returns force
return Integer2Force(GetHandleId(h))
endfunction
function Force2Handle takes force f returns handle
return f
endfunction
//Group
function Integer2Group takes integer i returns group
call SaveFogStateHandle(udg_TypeCastHashtable, 0, 0, ConvertFogState(i))
return LoadGroupHandle(udg_TypeCastHashtable, 0, 0)
endfunction
function Handle2Group takes handle h returns group
return Integer2Group(GetHandleId(h))
endfunction
function Group2Handle takes group g returns handle
return g
endfunction
//Hashtable
function Integer2Hashtable takes integer i returns hashtable
call SaveFogStateHandle(udg_TypeCastHashtable, 0, 0, ConvertFogState(i))
return LoadHashtableHandle(udg_TypeCastHashtable, 0, 0)
endfunction
function Handle2Hashtable takes handle h returns hashtable
return Integer2Hashtable(GetHandleId(h))
endfunction
function Hashtable2Handle takes hashtable h returns handle
return h
endfunction
//Image
function Integer2Image takes integer i returns image
call SaveFogStateHandle(udg_TypeCastHashtable, 0, 0, ConvertFogState(i))
return LoadImageHandle(udg_TypeCastHashtable, 0, 0)
endfunction
function Handle2Image takes handle h returns image
return Integer2Image(GetHandleId(h))
endfunction
function Image2Handle takes image i returns handle
return i
endfunction
//Item
function Integer2Item takes integer i returns item
call SaveFogStateHandle(udg_TypeCastHashtable, 0, 0, ConvertFogState(i))
return LoadItemHandle(udg_TypeCastHashtable, 0, 0)
endfunction
function Handle2Item takes handle h returns item
return Integer2Item(GetHandleId(h))
endfunction
function Item2Handle takes item i returns handle
return i
endfunction
//ItemPool
function Integer2ItemPool takes integer i returns itempool
call SaveFogStateHandle(udg_TypeCastHashtable, 0, 0, ConvertFogState(i))
return LoadItemPoolHandle(udg_TypeCastHashtable, 0, 0)
endfunction
function Handle2ItemPool takes handle h returns itempool
return Integer2ItemPool(GetHandleId(h))
endfunction
function ItemPool2Handle takes itempool i returns handle
return i
endfunction
//Leaderboard
function Integer2Leaderboard takes integer i returns leaderboard
call SaveFogStateHandle(udg_TypeCastHashtable, 0, 0, ConvertFogState(i))
return LoadLeaderboardHandle(udg_TypeCastHashtable, 0, 0)
endfunction
function Handle2Leaderboard takes handle h returns leaderboard
return Integer2Leaderboard(GetHandleId(h))
endfunction
function Leaderboard2Handle takes leaderboard l returns handle
return l
endfunction
//Lightning
function Integer2Lightning takes integer i returns lightning
call SaveFogStateHandle(udg_TypeCastHashtable, 0, 0, ConvertFogState(i))
return LoadLightningHandle(udg_TypeCastHashtable, 0, 0)
endfunction
function Handle2Lightning takes handle h returns lightning
return Integer2Lightning(GetHandleId(h))
endfunction
function Lightning2Handle takes lightning l returns handle
return l
endfunction
//Location
function Integer2Location takes integer i returns location
call SaveFogStateHandle(udg_TypeCastHashtable, 0, 0, ConvertFogState(i))
return LoadLocationHandle(udg_TypeCastHashtable, 0, 0)
endfunction
function Handle2Location takes handle h returns location
return Integer2Location(GetHandleId(h))
endfunction
function Location2Handle takes location l returns handle
return l
endfunction
//Multiboard
function Integer2Multiboard takes integer i returns multiboard
call SaveFogStateHandle(udg_TypeCastHashtable, 0, 0, ConvertFogState(i))
return LoadMultiboardHandle(udg_TypeCastHashtable, 0, 0)
endfunction
function Handle2Multiboard takes handle h returns multiboard
return Integer2Multiboard(GetHandleId(h))
endfunction
function Multiboard2Handle takes multiboard m returns handle
return m
endfunction
//MultiboardItem
function Integer2MultiboardItem takes integer i returns multiboarditem
call SaveFogStateHandle(udg_TypeCastHashtable, 0, 0, ConvertFogState(i))
return LoadMultiboardItemHandle(udg_TypeCastHashtable, 0, 0)
endfunction
function Handle2MultiboardItem takes handle h returns multiboarditem
return Integer2MultiboardItem(GetHandleId(h))
endfunction
function MultiboardItem2Handle takes multiboarditem m returns handle
return m
endfunction
//Player
function Integer2Player takes integer i returns player
call SaveFogStateHandle(udg_TypeCastHashtable, 0, 0, ConvertFogState(i))
return LoadPlayerHandle(udg_TypeCastHashtable, 0, 0)
endfunction
function Handle2Player takes handle h returns player
return Integer2Player(GetHandleId(h))
endfunction
function Player2Handle takes player p returns handle
return p
endfunction
//Quest
function Integer2Quest takes integer i returns quest
call SaveFogStateHandle(udg_TypeCastHashtable, 0, 0, ConvertFogState(i))
return LoadQuestHandle(udg_TypeCastHashtable, 0, 0)
endfunction
function Handle2Quest takes handle h returns quest
return Integer2Quest(GetHandleId(h))
endfunction
function Quest2Handle takes quest q returns handle
return q
endfunction
//QuestItem
function Integer2QuestItem takes integer i returns questitem
call SaveFogStateHandle(udg_TypeCastHashtable, 0, 0, ConvertFogState(i))
return LoadQuestItemHandle(udg_TypeCastHashtable, 0, 0)
endfunction
function Handle2QuestItem takes handle h returns questitem
return Integer2QuestItem(GetHandleId(h))
endfunction
function QuestItem2Handle takes questitem q returns handle
return q
endfunction
//Rect
function Integer2Rect takes integer i returns rect
call SaveFogStateHandle(udg_TypeCastHashtable, 0, 0, ConvertFogState(i))
return LoadRectHandle(udg_TypeCastHashtable, 0, 0)
endfunction
function Handle2Rect takes handle h returns rect
return Integer2Rect(GetHandleId(h))
endfunction
function Rect2Handle takes rect r returns handle
return r
endfunction
//Region
function Integer2Region takes integer i returns region
call SaveFogStateHandle(udg_TypeCastHashtable, 0, 0, ConvertFogState(i))
return LoadRegionHandle(udg_TypeCastHashtable, 0, 0)
endfunction
function Handle2Region takes handle h returns region
return Integer2Region(GetHandleId(h))
endfunction
function Region2Handle takes region r returns handle
return r
endfunction
//Sound
function Integer2Sound takes integer i returns sound
call SaveFogStateHandle(udg_TypeCastHashtable, 0, 0, ConvertFogState(i))
return LoadSoundHandle(udg_TypeCastHashtable, 0, 0)
endfunction
function Handle2Sound takes handle h returns sound
return Integer2Sound(GetHandleId(h))
endfunction
function Sound2Handle takes sound s returns handle
return s
endfunction
//TextTag
function Integer2TextTag takes integer i returns texttag
call SaveFogStateHandle(udg_TypeCastHashtable, 0, 0, ConvertFogState(i))
return LoadTextTagHandle(udg_TypeCastHashtable, 0, 0)
endfunction
function Handle2TextTag takes handle h returns texttag
return Integer2TextTag(GetHandleId(h))
endfunction
function TextTag2Handle takes texttag t returns handle
return t
endfunction
//Timer
function Integer2Timer takes integer i returns timer
call SaveFogStateHandle(udg_TypeCastHashtable, 0, 0, ConvertFogState(i))
return LoadTimerHandle(udg_TypeCastHashtable, 0, 0)
endfunction
function Handle2Timer takes handle h returns timer
return Integer2Timer(GetHandleId(h))
endfunction
function Timer2Handle takes timer t returns handle
return t
endfunction
//TimerDialog
function Integer2TimerDialog takes integer i returns timerdialog
call SaveFogStateHandle(udg_TypeCastHashtable, 0, 0, ConvertFogState(i))
return LoadTimerDialogHandle(udg_TypeCastHashtable, 0, 0)
endfunction
function Handle2TimerDialog takes handle h returns timerdialog
return Integer2TimerDialog(GetHandleId(h))
endfunction
function TimerDialog2Handle takes timerdialog t returns handle
return t
endfunction
//Trackable
function Integer2Trackable takes integer i returns trackable
call SaveFogStateHandle(udg_TypeCastHashtable, 0, 0, ConvertFogState(i))
return LoadTrackableHandle(udg_TypeCastHashtable, 0, 0)
endfunction
function Handle2Trackable takes handle h returns trackable
return Integer2Trackable(GetHandleId(h))
endfunction
function Trackable2Handle takes trackable t returns handle
return t
endfunction
//Trigger
function Integer2Trigger takes integer i returns trigger
call SaveFogStateHandle(udg_TypeCastHashtable, 0, 0, ConvertFogState(i))
return LoadTriggerHandle(udg_TypeCastHashtable, 0, 0)
endfunction
function Handle2WTrigger takes handle h returns trigger
return Integer2Trigger(GetHandleId(h))
endfunction
function Trigger2Handle takes trigger t returns handle
return t
endfunction
//TriggerAction
function Integer2TriggerAction takes integer i returns triggeraction
call SaveFogStateHandle(udg_TypeCastHashtable, 0, 0, ConvertFogState(i))
return LoadTriggerActionHandle(udg_TypeCastHashtable, 0, 0)
endfunction
function Handle2TriggerAction takes handle h returns triggeraction
return Integer2TriggerAction(GetHandleId(h))
endfunction
function TriggerAction2Handle takes triggeraction t returns handle
return t
endfunction
//TriggerCondition
function Integer2TriggerCondition takes integer i returns triggercondition
call SaveFogStateHandle(udg_TypeCastHashtable, 0, 0, ConvertFogState(i))
return LoadTriggerConditionHandle(udg_TypeCastHashtable, 0, 0)
endfunction
function Handle2TriggerCondition takes handle h returns triggercondition
return Integer2TriggerCondition(GetHandleId(h))
endfunction
function TriggerCondition2Handle takes triggercondition t returns handle
return t
endfunction
//TriggerEvent
function Integer2TriggerEvent takes integer i returns event
call SaveFogStateHandle(udg_TypeCastHashtable, 0, 0, ConvertFogState(i))
return LoadTriggerEventHandle(udg_TypeCastHashtable, 0, 0)
endfunction
function Handle2TriggerEvent takes handle h returns event
return Integer2TriggerEvent(GetHandleId(h))
endfunction
function TriggerEvent2Handle takes event e returns handle
return e
endfunction
//Ubersplat
function Integer2Ubersplat takes integer i returns ubersplat
call SaveFogStateHandle(udg_TypeCastHashtable, 0, 0, ConvertFogState(i))
return LoadUbersplatHandle(udg_TypeCastHashtable, 0, 0)
endfunction
function Handle2Ubersplat takes handle h returns ubersplat
return Integer2Ubersplat(GetHandleId(h))
endfunction
function Ubersplat2Handle takes ubersplat u returns handle
return u
endfunction
//Unit
function Integer2Unit takes integer i returns unit
call SaveFogStateHandle(udg_TypeCastHashtable, 0, 0, ConvertFogState(i))
return LoadUnitHandle(udg_TypeCastHashtable, 0, 0)
endfunction
function Handle2Unit takes handle h returns unit
return Integer2Unit(GetHandleId(h))
endfunction
function Unit2Handle takes unit u returns handle
return u
endfunction
//UnitPool
function Integer2UnitPool takes integer i returns unitpool
call SaveFogStateHandle(udg_TypeCastHashtable, 0, 0, ConvertFogState(i))
return LoadUnitPoolHandle(udg_TypeCastHashtable, 0, 0)
endfunction
function Handle2UnitPool takes handle h returns unitpool
return Integer2UnitPool(GetHandleId(h))
endfunction
function UnitPool2Handle takes unitpool u returns handle
return u
endfunction
//Widget
function Integer2Widget takes integer i returns widget
call SaveFogStateHandle(udg_TypeCastHashtable, 0, 0, ConvertFogState(i))
return LoadWidgetHandle(udg_TypeCastHashtable, 0, 0)
endfunction
function Handle2Widget takes handle h returns widget
return Integer2Widget(GetHandleId(h))
endfunction
function Widget2Handle takes widget w returns handle
return w
endfunction
endlibrary
JASS:
library convertion
function ConvertAttackTypeReverse takes attacktype at returns integer
if at == ATTACK_TYPE_NORMAL then
return 0
elseif at == ATTACK_TYPE_MELEE then
return 1
elseif at == ATTACK_TYPE_PIERCE then
return 2
elseif at == ATTACK_TYPE_SIEGE then
return 3
elseif at == ATTACK_TYPE_MAGIC then
return 4
elseif at == ATTACK_TYPE_CHAOS then
return 5
elseif at == ATTACK_TYPE_HERO then
return 6
endif
return 0
endfunction
function ConvertDamageTypeReverse takes damagetype dt returns integer
if dt == DAMAGE_TYPE_UNKNOWN then
return 0
elseif dt == DAMAGE_TYPE_NORMAL then
return 4
elseif dt == DAMAGE_TYPE_ENHANCED then
return 5
elseif dt == DAMAGE_TYPE_FIRE then
return 8
elseif dt == DAMAGE_TYPE_COLD then
return 9
elseif dt == DAMAGE_TYPE_LIGHTNING then
return 10
elseif dt == DAMAGE_TYPE_POISON then
return 11
elseif dt == DAMAGE_TYPE_DISEASE then
return 12
elseif dt == DAMAGE_TYPE_DIVINE then
return 13
elseif dt == DAMAGE_TYPE_MAGIC then
return 14
elseif dt == DAMAGE_TYPE_SONIC then
return 15
elseif dt == DAMAGE_TYPE_ACID then
return 16
elseif dt == DAMAGE_TYPE_FORCE then
return 17
elseif dt == DAMAGE_TYPE_DEATH then
return 18
elseif dt == DAMAGE_TYPE_MIND then
return 19
elseif dt == DAMAGE_TYPE_PLANT then
return 20
elseif dt == DAMAGE_TYPE_DEFENSIVE then
return 21
elseif dt == DAMAGE_TYPE_DEMOLITION then
return 22
elseif dt == DAMAGE_TYPE_SLOW_POISON then
return 23
elseif dt == DAMAGE_TYPE_SPIRIT_LINK then
return 24
elseif dt == DAMAGE_TYPE_SHADOW_STRIKE then
return 25
elseif dt == DAMAGE_TYPE_UNIVERSAL then
return 26
endif
return 0
endfunction
endlibrary
JASS:
library timerIndex uses TimerUtils
//*********************************************************************
//* TimerIndex 1.0
//* ----------
//*
//* This library creates a unique index for the TimerData of timerUtils.
//* A timer that is created with an index must also be released as an indexed timer.
//*
globals
integer udg_NextTimerIndex = 0
boolean array udg_TimerIndex_Occupied
endglobals
function ReleaseIndexedTimer takes timer t returns nothing
set udg_TimerIndex_Occupied[GetTimerData(t)] = false
call ReleaseTimer(t)
endfunction
function NewIndexedTimer takes nothing returns timer
loop
set udg_NextTimerIndex = udg_NextTimerIndex + 1
if udg_NextTimerIndex > 8191 then
set udg_NextTimerIndex = 1
endif
exitwhen not udg_TimerIndex_Occupied[udg_NextTimerIndex]
endloop
set udg_TimerIndex_Occupied[udg_NextTimerIndex] = true
return NewTimerEx(udg_NextTimerIndex)
endfunction
endlibrary
JASS:
library TimerUtils initializer init
//*********************************************************************
//* TimerUtils (red+blue+orange flavors for 1.24b+) 2.0
//* ----------
//*
//* To implement it , create a custom text trigger called TimerUtils
//* and paste the contents of this script there.
//*
//* To copy from a map to another, copy the trigger holding this
//* library to your map.
//*
//* (requires vJass) More scripts: htt://www.wc3c.net
//*
//* For your timer needs:
//* * Attaching
//* * Recycling (with double-free protection)
//*
//* set t=NewTimer() : Get a timer (alternative to CreateTimer)
//* set t=NewTimerEx(x) : Get a timer (alternative to CreateTimer), call
//* Initialize timer data as x, instead of 0.
//*
//* ReleaseTimer(t) : Relese a timer (alt to DestroyTimer)
//* SetTimerData(t,2) : Attach value 2 to timer
//* GetTimerData(t) : Get the timer's value.
//* You can assume a timer's value is 0
//* after NewTimer.
//*
//* Multi-flavor:
//* Set USE_HASH_TABLE to true if you don't want to complicate your life.
//*
//* If you like speed and giberish try learning about the other flavors.
//*
//********************************************************************
//================================================================
globals
//How to tweak timer utils:
// USE_HASH_TABLE = true (new blue)
// * SAFEST
// * SLOWEST (though hash tables are kind of fast)
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = true (orange)
// * kinda safe (except there is a limit in the number of timers)
// * ALMOST FAST
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = false (red)
// * THE FASTEST (though is only faster than the previous method
// after using the optimizer on the map)
// * THE LEAST SAFE ( you may have to tweak OFSSET manually for it to
// work)
//
private constant boolean USE_HASH_TABLE = true
private constant boolean USE_FLEXIBLE_OFFSET = false
private constant integer OFFSET = 0x100000
private integer VOFFSET = OFFSET
//Timers to preload at map init:
private constant integer QUANTITY = 256
//Changing this to something big will allow you to keep recycling
// timers even when there are already AN INCREDIBLE AMOUNT of timers in
// the stack. But it will make things far slower so that's probably a bad idea...
private constant integer ARRAY_SIZE = 8190
endglobals
//==================================================================================================
globals
private integer array data[ARRAY_SIZE]
private hashtable ht
endglobals
//It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
function SetTimerData takes timer t, integer value returns nothing
static if(USE_HASH_TABLE) then
// new blue
call SaveInteger(ht,0,GetHandleId(t), value)
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-VOFFSET]=value
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-OFFSET]=value
endif
endfunction
function GetTimerData takes timer t returns integer
static if(USE_HASH_TABLE) then
// new blue
return LoadInteger(ht,0,GetHandleId(t) )
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-VOFFSET]
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-OFFSET]
endif
endfunction
//==========================================================================================
globals
private timer array tT[ARRAY_SIZE]
private integer tN = 0
private constant integer HELD=0x28829022
//use a totally random number here, the more improbable someone uses it, the better.
private boolean didinit = false
endglobals
private keyword init
//==========================================================================================
// I needed to decide between duplicating code ignoring the "Once and only once" rule
// and using the ugly textmacros. I guess textmacros won.
//
//! textmacro TIMERUTIS_PRIVATE_NewTimerCommon takes VALUE
// On second thought, no.
//! endtextmacro
function NewTimerEx takes integer value returns timer
if (tN==0) then
if (not didinit) then
//This extra if shouldn't represent a major performance drawback
//because QUANTITY rule is not supposed to be broken every day.
call init.evaluate()
set tN = tN - 1
else
//If this happens then the QUANTITY rule has already been broken, try to fix the
// issue, else fail.
debug call BJDebugMsg("NewTimer: Warning, Exceeding TimerUtils_QUANTITY, make sure all timers are getting recycled correctly")
set tT[0]=CreateTimer()
static if( not USE_HASH_TABLE) then
debug call BJDebugMsg("In case of errors, please increase it accordingly, or set TimerUtils_USE_HASH_TABLE to true")
static if( USE_FLEXIBLE_OFFSET) then
if (GetHandleId(tT[0])-VOFFSET<0) or (GetHandleId(tT[0])-VOFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
else
if (GetHandleId(tT[0])-OFFSET<0) or (GetHandleId(tT[0])-OFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
endif
endif
endif
else
set tN=tN-1
endif
call SetTimerData(tT[tN],value)
return tT[tN]
endfunction
function NewTimer takes nothing returns timer
return NewTimerEx(0)
endfunction
//==========================================================================================
function ReleaseTimer takes timer t returns nothing
if(t==null) then
debug call BJDebugMsg("Warning: attempt to release a null timer")
return
endif
if (tN==ARRAY_SIZE) then
debug call BJDebugMsg("Warning: Timer stack is full, destroying timer!!")
//stack is full, the map already has much more troubles than the chance of bug
call DestroyTimer(t)
else
call PauseTimer(t)
if(GetTimerData(t)==HELD) then
debug call BJDebugMsg("Warning: ReleaseTimer: Double free!")
return
endif
call SetTimerData(t,HELD)
set tT[tN]=t
set tN=tN+1
endif
endfunction
private function init takes nothing returns nothing
local integer i=0
local integer o=-1
local boolean oops = false
if ( didinit ) then
return
else
set didinit = true
endif
static if( USE_HASH_TABLE ) then
set ht = InitHashtable()
loop
exitwhen(i==QUANTITY)
set tT[i]=CreateTimer()
call SetTimerData(tT[i], HELD)
set i=i+1
endloop
set tN = QUANTITY
else
loop
set i=0
loop
exitwhen (i==QUANTITY)
set tT[i] = CreateTimer()
if(i==0) then
set VOFFSET = GetHandleId(tT[i])
static if(USE_FLEXIBLE_OFFSET) then
set o=VOFFSET
else
set o=OFFSET
endif
endif
if (GetHandleId(tT[i])-o>=ARRAY_SIZE) then
exitwhen true
endif
if (GetHandleId(tT[i])-o>=0) then
set i=i+1
endif
endloop
set tN = i
exitwhen(tN == QUANTITY)
set oops = true
exitwhen not USE_FLEXIBLE_OFFSET
debug call BJDebugMsg("TimerUtils_init: Failed a initialization attempt, will try again")
endloop
if(oops) then
static if ( USE_FLEXIBLE_OFFSET) then
debug call BJDebugMsg("The problem has been fixed.")
//If this message doesn't appear then there is so much
//handle id fragmentation that it was impossible to preload
//so many timers and the thread crashed! Therefore this
//debug message is useful.
elseif(DEBUG_MODE) then
call BJDebugMsg("There were problems and the new timer limit is "+I2S(i))
call BJDebugMsg("This is a rare ocurrence, if the timer limit is too low:")
call BJDebugMsg("a) Change USE_FLEXIBLE_OFFSET to true (reduces performance a little)")
call BJDebugMsg("b) or try changing OFFSET to "+I2S(VOFFSET) )
endif
endif
endif
endfunction
endlibrary
-
Unit Indexer
-
Events
-
Map initialization
-
-
Conditions
-
Actions
-
Custom script: call ExecuteFunc("InitializeUnitIndexer")
-
Custom script: endfunction
-
-------- --------
-
-------- This is the most important function - it provides an index for units as they enter the map --------
-
-------- --------
-
Custom script: function IndexUnit takes nothing returns boolean
-
Custom script: local integer pdex = udg_UDex
-
-------- --------
-
-------- You can use the boolean UnitIndexerEnabled to protect some of your undesirable units from being indexed --------
-
-------- - Example: --------
-
-------- -- Set UnitIndexerEnabled = False --------
-
-------- -- Unit - Create 1 Dummy for (Triggering player) at TempLoc facing 0.00 degrees --------
-
-------- -- Set UnitIndexerEnabled = True --------
-
-------- --------
-
-------- You can also customize the following block - if conditions are false the (Matching unit) won't be indexed. --------
-
-------- --------
-
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
-
If - Conditions
-
UnitIndexerEnabled Equal to True
-
-
Then - Actions
-
-------- --------
-
-------- Generate a unique integer index for this unit --------
-
-------- --------
-
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
-
If - Conditions
-
UDexRecycle Equal to 0
-
-
Then - Actions
-
Set UDex = (UDexGen + 1)
-
Set UDexGen = UDex
-
-
Else - Actions
-
Set UDex = UDexRecycle
-
Set UDexRecycle = UDexNext[UDex]
-
-
-
-------- --------
-
-------- Link index to unit, unit to index --------
-
-------- --------
-
Set UDexUnits[UDex] = (Matching unit)
-
Unit - Set the custom value of UDexUnits[UDex] to UDex
-
-------- --------
-
-------- Use a doubly-linked list to store all active indexes --------
-
-------- --------
-
Set UDexPrev[UDexNext[0]] = UDex
-
Set UDexNext[UDex] = UDexNext[0]
-
Set UDexNext[0] = UDex
-
-------- --------
-
-------- Fire index event for UDex --------
-
-------- --------
-
Set UnitIndexEvent = 0.00
-
Set UnitIndexEvent = 1.00
-
Set UnitIndexEvent = 0.00
-
Custom script: set udg_UDex = pdex
-
-
Else - Actions
-
-
Custom script: return false
-
Custom script: endfunction
-
-------- --------
-
-------- The next function is called each time a unit enters the map --------
-
-------- --------
-
Custom script: function IndexNewUnit takes nothing returns boolean
-
Custom script: local integer pdex = udg_UDex
-
Custom script: local integer ndex
-
-------- --------
-
-------- Recycle indices of units no longer in-play every (15) units created --------
-
-------- --------
-
Set UDexWasted = (UDexWasted + 1)
-
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
-
If - Conditions
-
UDexWasted Equal to 15
-
-
Then - Actions
-
Set UDexWasted = 0
-
Set UDex = UDexNext[0]
-
Custom script: loop
-
Custom script: exitwhen udg_UDex == 0
-
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
-
If - Conditions
-
(Custom value of UDexUnits[UDex]) Equal to 0
-
-
Then - Actions
-
-------- --------
-
-------- Remove index from linked list --------
-
-------- --------
-
Custom script: set ndex = udg_UDexNext[udg_UDex]
-
Custom script: set udg_UDexNext[udg_UDexPrev[udg_UDex]] = ndex
-
Custom script: set udg_UDexPrev[ndex] = udg_UDexPrev[udg_UDex]
-
Set UDexPrev[UDex] = 0
-
-------- --------
-
-------- Fire deindex event for UDex --------
-
-------- --------
-
Set UnitIndexEvent = 2.00
-
Set UnitIndexEvent = 0.00
-
-------- --------
-
-------- Recycle the index for later use --------
-
-------- --------
-
Set UDexUnits[UDex] = No unit
-
Set UDexNext[UDex] = UDexRecycle
-
Set UDexRecycle = UDex
-
Custom script: set udg_UDex = ndex
-
-
Else - Actions
-
Set UDex = UDexNext[UDex]
-
-
-
Custom script: endloop
-
Custom script: set udg_UDex = pdex
-
-
Else - Actions
-
-
-------- --------
-
-------- Handle the entering unit (Matching unit) --------
-
-------- --------
-
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
-
If - Conditions
-
(Custom value of (Matching unit)) Equal to 0
-
-
Then - Actions
-
Custom script: call IndexUnit()
-
-
Else - Actions
-
-
Custom script: return false
-
Custom script: endfunction
-
-------- --------
-
-------- The next function initializes the core of the system --------
-
-------- --------
-
Custom script: function InitializeUnitIndexer takes nothing returns nothing
-
Custom script: local integer i = 0
-
Custom script: local region re = CreateRegion()
-
Custom script: local rect r = GetWorldBounds()
-
Set UnitIndexerEnabled = True
-
Custom script: call RegionAddRect(re, r)
-
Custom script: call TriggerRegisterEnterRegion(CreateTrigger(), re, Filter(function IndexNewUnit))
-
Custom script: call RemoveRect(r)
-
Custom script: set re = null
-
Custom script: set r = null
-
Custom script: loop
-
Custom script: call GroupEnumUnitsOfPlayer(bj_lastCreatedGroup, Player(i), Filter(function IndexUnit))
-
Custom script: set i = i + 1
-
Custom script: exitwhen i == 16
-
Custom script: endloop
-
-------- --------
-
-------- This is the "Unit Indexer Initialized" event, use it instead of "Map Initialization" for best results --------
-
-------- --------
-
Set UnitIndexEvent = 3.00
-
Set UnitIndexEvent = 0.00
-
-
I forgot to do the credits:
- to lookin_for_help for the idea of the reversed spell damage and making artillery damage explode units.
- to Nestharus and edo494 for helping with the concept and structure.
- to Bribe for his Unit Indexer.
I hope that I have said everything that I wanted to say... I actually start to forget things when things get so complicated as this.
Map attached in comment.
Last edited: