Name | Type | is_array | initial_value |
ADHDPicker | dialog | No | |
ADHDPickerButton | button | No | |
AfterDamageEvent | real | No | |
AHSTCap | integer | No | 20 |
AHSTRequired | real | No | 0.25 |
AHSTSpeedDecrease | real | No | 5.00 |
AnorarDisruptionMax | real | No | 20.00 |
AnorarDisruptionUpgrade | real | No | 0.75 |
AnorarMindEmbryoDeath | real | No | 5.00 |
AnorarMindNeuronDeath | real | No | 2.00 |
AnorarMindNodeDeath | real | No | 10.00 |
AOEDamageEvent | real | No | |
AOEDamageSource | unit | No | |
ARMOR_TYPE_ETHEREAL | integer | No | |
ARMOR_TYPE_FLESH | integer | No | |
ARMOR_TYPE_METAL | integer | No | |
ARMOR_TYPE_NONE | integer | No | |
ARMOR_TYPE_STONE | integer | No | |
ARMOR_TYPE_WOOD | integer | No | |
ArmorTypeDebugStr | string | Yes | |
ArraySize | integer | No | |
ATTACK_TYPE_CHAOS | integer | No | |
ATTACK_TYPE_HERO | integer | No | |
ATTACK_TYPE_MAGIC | integer | No | |
ATTACK_TYPE_NORMAL | integer | No | |
ATTACK_TYPE_PIERCE | integer | No | |
ATTACK_TYPE_SIEGE | integer | No | |
ATTACK_TYPE_SPELLS | integer | No | |
AttackTypeDebugStr | string | Yes | |
b | boolean | No | |
BargeInArea | real | No | 100.00 |
BargeInDamage | integer | No | 20 |
BargeInPeriod | real | No | 0.10 |
BargeInRange | real | No | 1200.00 |
BargeInReload | real | No | 30.00 |
BargeInTime | real | No | 2.00 |
CargoEvent | real | No | |
CargoTransportGroup | group | Yes | |
CargoTransportUnit | unit | Yes | |
CheckDeathInList | boolean | Yes | |
CheckDeathList | integer | Yes | |
CheckDeathTimer | timer | No | |
CoffeeGroup | group | No | |
ConcentratorAmplificator | integer | No | 10 |
ConcentratorBreakTime | real | No | 30.00 |
ConcentratorRange | real | No | 800.00 |
ConcentratorRangeUpgrade | real | No | 1000.00 |
ConcentratorSynapse | real | No | 20.00 |
ConcentratorTargets | integer | No | 5 |
ConcentratorTargetsUpgrade | integer | No | 6 |
CONVERTED_ATTACK_TYPE | attacktype | Yes | |
CONVERTED_DAMAGE_TYPE | damagetype | Yes | |
CooldownFirst | real | No | 30.00 |
CooldownNext | real | No | 1.00 |
CreativeSurgeGroup | group | No | |
CreativityAuraGroup | group | No | |
d | destructable | No | |
DAMAGE_TYPE_ACID | integer | No | |
DAMAGE_TYPE_COLD | integer | No | |
DAMAGE_TYPE_DEATH | integer | No | |
DAMAGE_TYPE_DEFENSIVE | integer | No | |
DAMAGE_TYPE_DEMOLITION | integer | No | |
DAMAGE_TYPE_DISEASE | integer | No | |
DAMAGE_TYPE_DIVINE | integer | No | |
DAMAGE_TYPE_ENHANCED | integer | No | |
DAMAGE_TYPE_FIRE | integer | No | |
DAMAGE_TYPE_FORCE | integer | No | |
DAMAGE_TYPE_LIGHTNING | integer | No | |
DAMAGE_TYPE_MAGIC | integer | No | |
DAMAGE_TYPE_MIND | integer | No | |
DAMAGE_TYPE_NORMAL | integer | No | |
DAMAGE_TYPE_PLANT | integer | No | |
DAMAGE_TYPE_POISON | integer | No | |
DAMAGE_TYPE_SHADOW_STRIKE | integer | No | |
DAMAGE_TYPE_SLOW_POISON | integer | No | |
DAMAGE_TYPE_SONIC | integer | No | |
DAMAGE_TYPE_SPIRIT_LINK | integer | No | |
DAMAGE_TYPE_UNIVERSAL | integer | No | |
DAMAGE_TYPE_UNKNOWN | integer | No | |
DamageEvent | real | No | |
DamageEventAmount | real | No | |
DamageEventAOE | integer | No | |
DamageEventAOEGroup | group | No | |
DamageEventArmorPierced | real | No | |
DamageEventArmorT | integer | No | |
DamageEventAttackT | integer | No | |
DamageEventDamageT | integer | No | |
DamageEventDefenseT | integer | No | |
DamageEventLevel | integer | No | |
DamageEventOverride | boolean | No | |
DamageEventPrevAmt | real | No | |
DamageEventSource | unit | No | |
DamageEventTarget | unit | No | |
DamageEventTrigger | trigger | No | |
DamageEventType | integer | No | |
DamageEventWeaponT | integer | No | |
DamageFilterAttackT | integer | No | |
DamageFilterDamageT | integer | No | |
DamageFilterMinAmount | real | No | |
DamageFilterSource | unit | No | |
DamageFilterSourceB | buffcode | No | |
DamageFilterSourceT | unitcode | No | |
DamageFilterTarget | unit | No | |
DamageFilterTargetB | buffcode | No | |
DamageFilterTargetT | unitcode | No | |
DamageFilterType | integer | No | |
DamageModifierEvent | real | No | |
DamageScalingUser | real | No | |
DamageScalingWC3 | real | No | |
DamageTypeBlocked | integer | No | |
DamageTypeCode | integer | No | |
DamageTypeCriticalStrike | integer | No | |
DamageTypeDebugStr | string | Yes | |
DamageTypeExplosive | integer | No | |
DamageTypeHeal | integer | No | |
DamageTypePure | integer | No | |
DamageTypePureExplosive | integer | No | |
DamageTypeReduced | integer | No | |
DeathEvent | real | No | |
DeconcentrationTime | real | No | 10.00 |
DEFENSE_TYPE_DIVINE | integer | No | |
DEFENSE_TYPE_FORTIFIED | integer | No | |
DEFENSE_TYPE_HEAVY | integer | No | |
DEFENSE_TYPE_HERO | integer | No | |
DEFENSE_TYPE_LIGHT | integer | No | |
DEFENSE_TYPE_MEDIUM | integer | No | |
DEFENSE_TYPE_NORMAL | integer | No | |
DEFENSE_TYPE_UNARMORED | integer | No | |
DefenseTypeDebugStr | string | Yes | |
DetectRemoveAbility | abilcode | No | |
DetectTransformAbility | abilcode | No | |
e | effect | No | |
EnhancedDamageTarget | unit | No | |
f | force | No | |
Fusion_CreationIndex | integer | No | |
Fusion_Current_CreatedObject | integer | No | |
Fusion_Current_Data | integer | No | |
Fusion_Current_FilterUnit | unit | No | |
Fusion_Current_Object | integer | No | |
Fusion_Current_Pointer | integer | No | |
Fusion_Data_AmountOfMergers | integer | No | |
Fusion_Data_AoE | real | Yes | |
Fusion_Data_AoEPerLevel | real | Yes | |
Fusion_Data_AutoAddCaster | boolean | Yes | |
Fusion_Data_AutoAddTarget | boolean | Yes | |
Fusion_Data_DefuseAfterDur | boolean | Yes | |
Fusion_Data_DefuseAfterDurHP | real | Yes | |
Fusion_Data_DefuseAfterDurMP | real | Yes | |
Fusion_Data_DefuseDispellMat | boolean | Yes | |
Fusion_Data_DefuseDistance | real | Yes | |
Fusion_Data_DefuseOnKilled | boolean | Yes | |
Fusion_Data_DefuseOnKilledHP | real | Yes | |
Fusion_Data_DefuseOnKilledMP | real | Yes | |
Fusion_Data_DefuseSFX | modelfile | Yes | |
Fusion_Data_DefusionEXPMulti | real | Yes | |
Fusion_Data_ErrorMsgMain | string | Yes | |
Fusion_Data_ErrorMsgPre | string | Yes | |
Fusion_Data_ErrorMsgWild | string | Yes | |
Fusion_Data_FadeIn | real | Yes | |
Fusion_Data_FadeInHidden | real | Yes | |
Fusion_Data_FadeVulnerable | boolean | Yes | |
Fusion_Data_FilterMain | trigger | Yes | |
Fusion_Data_FilterPre | trigger | Yes | |
Fusion_Data_FilterWild | trigger | Yes | |
Fusion_Data_HeroAllowBoniStats | boolean | Yes | |
Fusion_Data_HeroStatsMod | integer | Yes | |
Fusion_Data_HeroSumLevel | boolean | Yes | |
Fusion_Data_OrderCheck | string | Yes | |
Fusion_Data_Remove | boolean | Yes | |
Fusion_Data_Replace | unitcode | Yes | |
Fusion_Data_Result | unitcode | Yes | |
Fusion_Data_ResultDur | real | Yes | |
Fusion_Data_ResultDurPerLevel | real | Yes | |
Fusion_Data_ResultHPAverage | boolean | Yes | |
Fusion_Data_ResultMPAverage | boolean | Yes | |
Fusion_Data_SFX | modelfile | Yes | |
Fusion_Data_SFXResult | modelfile | Yes | |
Fusion_Data_SFXResultAttacht | string | Yes | |
Fusion_Data_SFXUnit | modelfile | Yes | |
Fusion_Data_SFXUnitAttacht | string | Yes | |
Fusion_Data_SkillGained | abilcode | Yes | |
Fusion_Data_SpawnAtTargetPoint | boolean | Yes | |
Fusion_Data_Speed | real | Yes | |
Fusion_Data_SpeedZ | real | Yes | |
Fusion_Data_Spell | abilcode | Yes | |
Fusion_Data_UnitTypes | unitcode | Yes | |
Fusion_Event | real | No | |
Fusion_Event_Fusion | unit | No | |
Fusion_Event_Group | group | No | |
Fusion_Event_Source | unit | No | |
Fusion_Event_SpellData | integer | No | |
Fusion_Event_SpellLevel | integer | No | |
Fusion_Event_SpellObject | integer | No | |
Fusion_Item_DefNext | integer | Yes | |
Fusion_Item_DefReuse | integer | Yes | |
Fusion_Item_DefReuseSize | integer | No | |
Fusion_Item_DefSize | integer | No | |
Fusion_Item_Item | item | Yes | |
Fusion_Item_Owner | unit | Yes | |
Fusion_Item_Size | integer | No | |
Fusion_Object_Bool | boolean | Yes | |
Fusion_Object_DataIndex | integer | Yes | |
Fusion_Object_Effect | effect | Yes | |
Fusion_Object_Fusion | unit | Yes | |
Fusion_Object_Group | group | Yes | |
Fusion_Object_Int1 | integer | Yes | |
Fusion_Object_Int2 | integer | Yes | |
Fusion_Object_Int3 | integer | Yes | |
Fusion_Object_Int4 | integer | Yes | |
Fusion_Object_Loc | location | Yes | |
Fusion_Object_Pointer | integer | Yes | |
Fusion_Object_Real1 | real | Yes | |
Fusion_Object_Real2 | real | Yes | |
Fusion_Object_Real3 | real | Yes | |
Fusion_Object_Real4 | real | Yes | |
Fusion_Object_Source | unit | Yes | |
Fusion_Object_SpellLevel | integer | Yes | |
Fusion_Object_Type | string | Yes | |
Fusion_System_DefusionTrigger | trigger | No | |
Fusion_System_DefusionUser | group | No | |
Fusion_System_Filter | boolexpr | No | |
Fusion_System_ObjectSize | integer | No | |
Fusion_System_Pointer | integer | Yes | |
Fusion_System_Pointer_Finished | boolean | Yes | |
Fusion_System_Pointer_Last | integer | No | |
Fusion_System_Reuse | integer | Yes | |
Fusion_System_ReuseSize | integer | No | |
Fusion_System_SaveLoc | location | No | |
Fusion_System_Timer | timer | No | |
Fusion_System_TimerDisabled | boolean | No | |
Fusion_System_UnitLastTaken | integer | No | |
Fusion_System_Units | unit | Yes | |
Fusion_System_UnitTypesEnd | integer | Yes | |
Fusion_System_UnitTypesStart | integer | Yes | |
GDD__Integers | integer | Yes | |
GDD__LeftMapGroup | group | No | |
GDD__TriggerArray | trigger | Yes | |
GDD__UnitArray | unit | Yes | |
GDD_Damage | real | No | |
GDD_DamagedUnit | unit | No | |
GDD_DamageSource | unit | No | |
GDD_Event | real | No | |
Gug | group | No | |
HashAnorar | hashtable | No | |
heal_amount | real | No | |
heal_check | boolean | No | |
HEAL_CHECK_INTERVAL | real | No | |
heal_count | integer | No | |
heal_diff | real | No | |
heal_exitwhen | integer | No | |
heal_indexRef | integer | Yes | |
heal_indices | integer | Yes | |
heal_inSys | boolean | Yes | |
heal_integer | integervar | No | |
heal_lastLife | real | Yes | |
heal_life | real | No | |
heal_regen | real | Yes | |
heal_source | unit | No | |
heal_target | unit | No | |
HEAL_THRESHOLD | real | No | |
heal_timer | timer | No | |
HealEvent | real | No | |
HighLimit | integer | No | 20 |
HopInDuration | real | No | 30.00 |
HopInHeal | real | No | 1.50 |
HopInRange | real | No | 800.00 |
i | integer | No | |
IsDamageAttack | boolean | No | |
IsDamageCode | boolean | No | |
IsDamageMelee | boolean | No | |
IsDamageRanged | boolean | No | |
IsDamageSpell | boolean | No | |
IsUnitAlive | boolean | Yes | |
IsUnitBeingUnloaded | boolean | Yes | |
IsUnitNew | boolean | Yes | |
IsUnitPreplaced | boolean | Yes | |
IsUnitReincarnating | boolean | Yes | |
IsUnitRemoved | boolean | Yes | |
IsUnitTransforming | boolean | Yes | |
item | item | No | |
k | handle | No | |
k2 | handle | No | |
k3 | handle | No | |
KillerOfUnit | unit | Yes | |
l | location | No | |
l2 | location | No | |
l3 | location | No | |
Last_Selected | unit | No | |
LeeroyJenkinsGroup | group | No | |
LethalDamageEvent | real | No | |
LethalDamageHP | real | No | |
MadKingDuration | real | No | 30.00 |
MadKingRange | real | No | 600.00 |
MagicGrenade | unit | No | |
MagicGrenadeTarget | unit | No | |
MagicGrenadeTargets | group | No | |
MindFissureRange | real | No | 300.00 |
MindNeuronDot | integer | No | 18 |
MindNeuronEffectDivisor | integer | No | |
MindNeuronEffectZone | string | No | TC_EnergyBolt.mdx |
MindNeuronRange | real | No | 600.00 |
MindNodeDot | integer | No | 36 |
MindNodeRange | real | No | 1200.00 |
NextDamageIsAttack | boolean | No | |
NextDamageIsMelee | boolean | No | |
NextDamageIsRanged | boolean | No | |
NextDamageType | integer | No | |
NextDamageWeaponT | integer | No | |
NextHealAmount | real | No | |
NextHealSource | unit | No | |
NextHealTarget | unit | No | |
OilAuraGroup | group | No | |
OrbOfSilverGroup | group | No | |
OverclockGroup | group | No | |
p | player | No | |
p2 | player | No | |
Playlist | string | No | Snarky_Puppy_-_What_about_me.mp3;Tales_of_the_forgotten_-_Egregore.mp3;Tales_of_the_forgotten_-_Ottumn.mp3;Toni_Leys_-_Speedstar.mp3;Waterflame_-_Color_Blockade.mp3 |
PossessionGroup | group | No | |
r | real | No | |
r2 | real | No | |
r3 | real | No | |
regen_buildup | real | Yes | |
REGEN_EVENT_INTERVAL | real | No | |
REGEN_STRENGTH_VALUE | real | No | |
REGEN_THRESHOLD | real | No | |
regen_timeleft | real | Yes | |
SacrificeAbility | abilcode | No | A007 |
SacrificeHeal | real | No | 500.00 |
SacrificeHealHero | real | No | 300.00 |
SacrificeHPBonus | integer | No | 25 |
SAGroup | group | No | |
SlowChainRange | real | No | 500.00 |
SqrtShieldLimit | real | No | 0.80 |
SqrtShieldReload | real | No | 20.00 |
SummonerOfUnit | unit | Yes | |
t | timer | No | |
TempInteger | integer | No | |
u | unit | No | |
u2 | unit | No | |
u3 | unit | No | |
u4 | unit | No | |
UDex | integer | No | |
UDexGen | integer | No | |
UDexLastRecycled | integer | No | |
UDexMax | integer | No | |
UDexNext | integer | Yes | |
UDexPrev | integer | Yes | |
UDexRecycle | integer | No | |
UDexUnits | unit | Yes | |
UDexWasted | integer | No | |
ug | group | No | |
ug2 | group | No | |
ug3 | group | No | |
UnitIndexerEnabled | boolean | No | |
UnitIndexEvent | real | No | |
UnitTypeEvent | real | No | |
UnitTypeOf | unitcode | Yes | |
ut | unitcode | No | |
v | fogmodifier | No | |
w | integer | No | |
WEAPON_TYPE_AM_CHOP | integer | No | |
WEAPON_TYPE_CH_SLICE | integer | No | |
WEAPON_TYPE_CL_SLICE | integer | No | |
WEAPON_TYPE_CM_SLICE | integer | No | |
WEAPON_TYPE_MH_BASH | integer | No | |
WEAPON_TYPE_MH_CHOP | integer | No | |
WEAPON_TYPE_MH_SLICE | integer | No | |
WEAPON_TYPE_MH_STAB | integer | No | |
WEAPON_TYPE_ML_CHOP | integer | No | |
WEAPON_TYPE_ML_SLICE | integer | No | |
WEAPON_TYPE_MM_BASH | integer | No | |
WEAPON_TYPE_MM_CHOP | integer | No | |
WEAPON_TYPE_MM_SLICE | integer | No | |
WEAPON_TYPE_MM_STAB | integer | No | |
WEAPON_TYPE_NONE | integer | No | |
WEAPON_TYPE_RH_BASH | integer | No | |
WEAPON_TYPE_WH_BASH | integer | No | |
WEAPON_TYPE_WH_SLICE | integer | No | |
WEAPON_TYPE_WL_BASH | integer | No | |
WEAPON_TYPE_WL_SLICE | integer | No | |
WEAPON_TYPE_WL_STAB | integer | No | |
WEAPON_TYPE_WM_BASH | integer | No | |
WEAPON_TYPE_WM_SLICE | integer | No | |
WEAPON_TYPE_WM_STAB | integer | No | |
WeaponTypeDebugStr | string | Yes | |
WorldMaxX | real | No | |
WorldMaxY | real | No | |
x | integer | No | |
y | integer | No | |
z | integer | No |
//===========================================================================
function UnitEventDestroyGroup takes integer i returns nothing
if udg_CargoTransportGroup[i] != null then
call DestroyGroup(udg_CargoTransportGroup[i])
set udg_CargoTransportGroup[i] = null
endif
endfunction
function UnitEventCheckAfter takes nothing returns nothing
local integer i = 0
loop
set i = udg_CheckDeathList[i]
exitwhen i == 0
if udg_IsUnitNew[i] then
//The unit was just created.
set udg_IsUnitNew[i] = false
elseif udg_IsUnitTransforming[i] then
//Added 21 July 2017 to fix the issue re-adding this ability in the same instant
set udg_UDex = i
set udg_UnitTypeEvent = 0.00
set udg_UnitTypeEvent = 1.00
set udg_UnitTypeOf[i] = GetUnitTypeId(udg_UDexUnits[i]) //Set this afterward to give the user extra reference
set udg_IsUnitTransforming[i] = false
call UnitAddAbility(udg_UDexUnits[i], udg_DetectTransformAbility)
elseif udg_IsUnitAlive[i] then
//The unit has started reincarnating.
set udg_IsUnitReincarnating[i] = true
set udg_IsUnitAlive[i] = false
set udg_UDex = i
set udg_DeathEvent = 0.50
set udg_DeathEvent = 0.00
endif
set udg_CheckDeathInList[i] = false
endloop
//Empty the list
set udg_CheckDeathList[0] = 0
endfunction
function UnitEventCheckAfterProxy takes integer i returns nothing
if udg_CheckDeathList[0] == 0 then
call TimerStart(udg_CheckDeathTimer, 0.00, false, function UnitEventCheckAfter)
endif
if not udg_CheckDeathInList[i] then
set udg_CheckDeathList[i] = udg_CheckDeathList[0]
set udg_CheckDeathList[0] = i
set udg_CheckDeathInList[i] = true
endif
endfunction
function UnitEventOnUnload takes nothing returns nothing
local integer i = udg_UDex
call GroupRemoveUnit(udg_CargoTransportGroup[GetUnitUserData(udg_CargoTransportUnit[i])], udg_UDexUnits[i])
set udg_IsUnitBeingUnloaded[i] = true
set udg_CargoEvent = 0.00
set udg_CargoEvent = 2.00
set udg_CargoEvent = 0.00
set udg_IsUnitBeingUnloaded[i] = false
if not IsUnitLoaded(udg_UDexUnits[i]) or IsUnitType(udg_CargoTransportUnit[i], UNIT_TYPE_DEAD) or GetUnitTypeId(udg_CargoTransportUnit[i]) == 0 then
set udg_CargoTransportUnit[i] = null
endif
endfunction
function UnitEventOnDeath takes nothing returns boolean
local integer pdex = udg_UDex
set udg_UDex = GetUnitUserData(GetTriggerUnit())
if udg_UDex != 0 then
set udg_KillerOfUnit[udg_UDex] = GetKillingUnit() //Added 29 May 2017 for GIMLI_2
set udg_IsUnitAlive[udg_UDex] = false
set udg_DeathEvent = 0.00
set udg_DeathEvent = 1.00
set udg_DeathEvent = 0.00
set udg_KillerOfUnit[udg_UDex] = null
if udg_CargoTransportUnit[udg_UDex] != null then
call UnitEventOnUnload()
endif
endif
set udg_UDex = pdex
return false
endfunction
function UnitEventOnOrder takes nothing returns boolean
local integer pdex = udg_UDex
local unit u = GetFilterUnit()
local integer i = GetUnitUserData(u)
if i > 0 then
set udg_UDex = i
if GetUnitAbilityLevel(u, udg_DetectRemoveAbility) == 0 then
if not udg_IsUnitRemoved[i] then
set udg_IsUnitRemoved[i] = true
set udg_IsUnitAlive[i] = false
set udg_SummonerOfUnit[i] = null
//For backwards-compatibility:
set udg_DeathEvent = 0.00
set udg_DeathEvent = 3.00
set udg_DeathEvent = 0.00
//Fire deindex event for UDex:
set udg_UnitIndexEvent = 0.00
set udg_UnitIndexEvent = 2.00
set udg_UnitIndexEvent = 0.00
set udg_UDexNext[udg_UDexPrev[i]] = udg_UDexNext[i]
set udg_UDexPrev[udg_UDexNext[i]] = udg_UDexPrev[i]
// Recycle the index for later use
set udg_UDexUnits[i] = null
set udg_UDexPrev[i] = udg_UDexLastRecycled
set udg_UDexLastRecycled = i
call UnitEventDestroyGroup(i)
endif
elseif not udg_IsUnitAlive[i] then
if not IsUnitType(u, UNIT_TYPE_DEAD) then
set udg_IsUnitAlive[i] = true
set udg_DeathEvent = 0.00
set udg_DeathEvent = 2.00
set udg_DeathEvent = 0.00
set udg_IsUnitReincarnating[i] = false
endif
elseif IsUnitType(u, UNIT_TYPE_DEAD) then
if udg_IsUnitNew[i] then
//This unit was created as a corpse.
set udg_IsUnitAlive[i] = false
set udg_DeathEvent = 0.00
set udg_DeathEvent = 1.00
set udg_DeathEvent = 0.00
elseif udg_CargoTransportUnit[i] == null or not IsUnitType(u, UNIT_TYPE_HERO) then
//The unit may have just started reincarnating.
call UnitEventCheckAfterProxy(i)
endif
elseif GetUnitAbilityLevel(u, udg_DetectTransformAbility) == 0 and not udg_IsUnitTransforming[i] then
set udg_IsUnitTransforming[i] = true
call UnitEventCheckAfterProxy(i) //This block has been updated on 21 July 2017
endif
if udg_CargoTransportUnit[i] != null and not udg_IsUnitBeingUnloaded[i] and not IsUnitLoaded(u) or IsUnitType(u, UNIT_TYPE_DEAD) then
call UnitEventOnUnload()
endif
set udg_UDex = pdex
endif
set u = null
return false
endfunction
function UnitEventOnSummon takes nothing returns boolean
local integer pdex = udg_UDex
set udg_UDex = GetUnitUserData(GetTriggerUnit())
if udg_IsUnitNew[udg_UDex] then
set udg_SummonerOfUnit[udg_UDex] = GetSummoningUnit()
set udg_UnitIndexEvent = 0.00
set udg_UnitIndexEvent = 0.50
set udg_UnitIndexEvent = 0.00
endif
set udg_UDex = pdex
return false
endfunction
function UnitEventOnLoad takes nothing returns boolean
local integer pdex = udg_UDex
local integer i = GetUnitUserData(GetTriggerUnit())
local integer index
if i != 0 then
set udg_UDex = i
if udg_CargoTransportUnit[i] != null then
call UnitEventOnUnload()
endif
//Loaded corpses do not issue an order when unloaded, therefore must
//use the enter-region event method taken from Jesus4Lyf's Transport.
if not udg_IsUnitAlive[i] then
call SetUnitX(udg_UDexUnits[i], udg_WorldMaxX)
call SetUnitY(udg_UDexUnits[i], udg_WorldMaxY)
endif
set udg_CargoTransportUnit[i] = GetTransportUnit()
set index = GetUnitUserData(udg_CargoTransportUnit[i])
if udg_CargoTransportGroup[index] == null then
set udg_CargoTransportGroup[index] = CreateGroup()
endif
call GroupAddUnit(udg_CargoTransportGroup[index], udg_UDexUnits[i])
set udg_CargoEvent = 0.00
set udg_CargoEvent = 1.00
set udg_CargoEvent = 0.00
set udg_UDex = pdex
endif
return false
endfunction
function UnitEventEnter takes nothing returns boolean
local integer pdex = udg_UDex
local integer i = udg_UDexLastRecycled
local unit u = GetFilterUnit()
if udg_UnitIndexerEnabled and GetUnitAbilityLevel(u, udg_DetectRemoveAbility) == 0 then
//Generate a unique integer index for this unit
if i == 0 then
set i = udg_UDexMax + 1
set udg_UDexMax = i
else
set udg_UDexLastRecycled = udg_UDexPrev[i]
endif
//Link index to unit, unit to index
set udg_UDexUnits[i] = u
call SetUnitUserData(u, i)
//For backwards-compatibility, add the unit to a linked list
set udg_UDexNext[i] = udg_UDexNext[0]
set udg_UDexPrev[udg_UDexNext[0]] = i
set udg_UDexNext[0] = i
set udg_UDexPrev[i] = 0
set udg_CheckDeathInList[i] = false
call UnitAddAbility(u, udg_DetectRemoveAbility)
call UnitMakeAbilityPermanent(u, true, udg_DetectRemoveAbility)
call UnitAddAbility(u, udg_DetectTransformAbility)
set udg_UnitTypeOf[i] = GetUnitTypeId(u)
set udg_IsUnitNew[i] = true
set udg_IsUnitAlive[i] = true
set udg_IsUnitRemoved[i] = false
set udg_IsUnitReincarnating[i] = false
set udg_IsUnitPreplaced[i] = udg_IsUnitPreplaced[0] //Added 29 May 2017 for Spellbound
call UnitEventCheckAfterProxy(i)
//Fire index event for UDex
set udg_UDex = i
set udg_UnitIndexEvent = 0.00
set udg_UnitIndexEvent = 1.00
set udg_UnitIndexEvent = 0.00
else
set udg_UDex = GetUnitUserData(u)
if udg_CargoTransportUnit[udg_UDex] != null and not IsUnitLoaded(u) then
//The unit was dead, but has re-entered the map.
call UnitEventOnUnload()
endif
endif
set udg_UDex = pdex
set u = null
return false
endfunction
//===========================================================================
function UnitEventInit takes nothing returns nothing
local integer i = bj_MAX_PLAYER_SLOTS //update to make it work with 1.29
local player p
local trigger t = CreateTrigger()
local trigger load = CreateTrigger()
local trigger death = CreateTrigger()
local trigger summon = CreateTrigger()
local rect r = GetWorldBounds()
local region re = CreateRegion()
local boolexpr enterB = Filter(function UnitEventEnter)
local boolexpr orderB = Filter(function UnitEventOnOrder)
set udg_WorldMaxX = GetRectMaxX(r)
set udg_WorldMaxY = GetRectMaxY(r)
call RegionAddRect(re, r)
call RemoveRect(r)
call UnitEventDestroyGroup(0)
call UnitEventDestroyGroup(1)
set udg_CheckDeathList[0] = 0
set udg_UnitIndexerEnabled = true
call TriggerRegisterEnterRegion(CreateTrigger(), re, enterB)
call TriggerAddCondition(load, Filter(function UnitEventOnLoad))
call TriggerAddCondition(death, Filter(function UnitEventOnDeath))
call TriggerAddCondition(summon, Filter(function UnitEventOnSummon))
loop
set i = i - 1
set p = Player(i)
call SetPlayerAbilityAvailable(p, udg_DetectRemoveAbility, false)
call SetPlayerAbilityAvailable(p, udg_DetectTransformAbility, false)
call TriggerRegisterPlayerUnitEvent(summon, p, EVENT_PLAYER_UNIT_SUMMON, null)
call TriggerRegisterPlayerUnitEvent(t, p, EVENT_PLAYER_UNIT_ISSUED_ORDER, orderB)
call TriggerRegisterPlayerUnitEvent(death, p, EVENT_PLAYER_UNIT_DEATH, null)
call TriggerRegisterPlayerUnitEvent(load, p, EVENT_PLAYER_UNIT_LOADED, null)
call GroupEnumUnitsOfPlayer(bj_lastCreatedGroup, p, enterB)
exitwhen i == 0
endloop
set summon = null
set death = null
set load = null
set re = null
set enterB = null
set orderB = null
set p = null
set r = null
set t = null
endfunction
function InitTrig_Unit_Event takes nothing returns nothing
endfunction
//Unit Fusion System V8a
//by Tasyen
//======================================
//API
//======================================
// function UnitDefusion takes unit u, boolean killed, integer indexFusion returns nothing
// tries to defuse an unit u, killed, or Defusionen Index
// indexFusion is faster, but most times you won't know the DefusionIndex
// If you do not know the defusion index call it with -1
// function UnitFusionStartFadeIn takes unit u, real dur, real hiddenStateAfter, string sfx, boolean immunDuringFade returns nothing
// pauses an unit and makes it transparent both will be lost over time.
// the pausing will be reapplied every timeout of "UnitFusionTimerSpeed"
// - u the unit
// - dur how long the process will take in seconds.
// - hiddenStateAfter this much % will the unit stay transparent after finishing the process (expects a number from 0 to 100)
// - sfx the modell which will displayed during the fadein
// - immunDuringFade if true the unit becomes invulnurable during fadein.
// - This will throw an FadeInFinish-Event with Fusion_Event_SpellData = -1
// - To Manipulate this used Fusion_Object use udg_Fusion_Current_CreatedObject right after calling it.
// function UnitFusionTimerStart takes nothing returns nothing
// Activaded automatacly normally.
// will start the System-timer, withthat the fusion behaviour overall.
// use it if you stopped the timer manually.
// "udg_Fusion_System_TimerDisabled = true" will prevent starting the timer that way.
//======================================
// Fusion_Data_HeroStatsMod:
// 0 uses Results default
// 1 uses Average of fusion members
// 2 uses sum of fusion members
// Fusion_Data_DefuseAfterDurHP is a % value between 0 and 1 or -1 to use Fusions %
// Fusion_Event
//
// 1 = NonHero Fusion
// 2 = Hero Fusion
// 3 = FadeInFinish
// -1 = Defusion
// Fusion_Event_Fusion = the Fusion
// Fusion_Event_Source = the Source casted fusion spell.
// Fusion_Event_Group = the merged/demerged Units; is does not contain substitutes.
// Fusion_Event_SpellData = the data index of the used Spell for fusing.
// Fusion_Event_SpellLevel = the level with which the fusion was casted.
// Fusion_Event_SpellObject = the FusionObjectIndex with this you an manipulate data inside an event, most time unneeded.
// Arrays here generally start with 1
//======================================
//Constants
//======================================
//Will the Fusion will be automatacly added to the selection of the owning Player?
constant function UnitFusionAutoSelect takes nothing returns boolean
return true
endfunction
constant function UnitFusionErrorMsg takes nothing returns string
return "Misses:"
endfunction
//ErrorMessage for each Missing Wildcard Unit.
//Looks like this:
//Misses:
// - Peon
// - Warlock
// - WildCard-Unit
// - WildCard-Unit
//
constant function UnitFusionWildCard takes nothing returns string
return " - WildCard-Unit"
endfunction
//How much is an unit transparent while flying 255 = 0%, 0 = 100%
constant function UnitFusionFade takes nothing returns integer
return 128
endfunction
//This is used to get units beeing at the edge of the AoE Indikator of a spell, beeing inside wither their hitbox.
constant function UnitMaxColison takes nothing returns real
return 200.0
endfunction
//Intervale used for fadingIn/Pulling
constant function UnitFusionTimerSpeed takes nothing returns real
return 0.05
endfunction
//How long one does see what is missing to fuse in seconds
constant function UnitFusionErrorDur takes nothing returns real
return 11.0
endfunction
constant function UnitFusionEventNonHero takes nothing returns real
return 1.0
endfunction
constant function UnitFusionEventHero takes nothing returns real
return 2.0
endfunction
constant function UnitFusionEventFadeInFinish takes nothing returns real
return 3.0
endfunction
constant function UnitFusionEventDefusion takes nothing returns real
return -1.0
endfunction
//The Fusion_Current_ItemStack usage for Defusions starts at Offset.
constant function UnitDefusionItemOffset takes nothing returns integer
return 200
endfunction
//Used by Fusion_Object_Type
constant function UnitFusionTypePull takes nothing returns string
return "UnitFusionPulled"
endfunction
constant function UnitFusionTypeDefusion takes nothing returns string
return "UnitDefusionMonitor"
endfunction
constant function UnitFusionTypeFadeIn takes nothing returns string
return "UnitFusionFadeIn"
endfunction
function StringIsEmpty takes string s returns boolean
return s == null or s == ""
endfunction
//======================================
//Code - Starts
//======================================
//This will return the Entering Index of the new Object
//And creates an pointer pointing at it.
//The LastUsed ObjectIndex is saved in udg_Fusion_Current_CreatedObject.
function UnitFusionInserObject takes nothing returns integer
local integer returnValue
if udg_Fusion_System_ReuseSize > 0 then
set returnValue = udg_Fusion_System_Reuse[udg_Fusion_System_ReuseSize]
set udg_Fusion_System_ReuseSize = udg_Fusion_System_ReuseSize - 1
else
set udg_Fusion_System_ObjectSize = udg_Fusion_System_ObjectSize + 1
set returnValue = udg_Fusion_System_ObjectSize
endif
set udg_Fusion_Current_CreatedObject = returnValue
//Create Pointer with used Object.
set udg_Fusion_System_Pointer_Last = udg_Fusion_System_Pointer_Last + 1
set udg_Fusion_System_Pointer[udg_Fusion_System_Pointer_Last] = returnValue
set udg_Fusion_Object_Pointer[returnValue] = udg_Fusion_System_Pointer_Last
set udg_Fusion_System_Pointer_Finished[udg_Fusion_System_Pointer_Last] = false
return returnValue
endfunction
//Will give you the index of an free spot in the Defusion Items.
function UnitDefusionItemGetFreeSpot takes nothing returns integer
local integer returnValue
if udg_Fusion_Item_DefReuseSize > 0 then
set returnValue = udg_Fusion_Item_DefReuse[udg_Fusion_Item_DefReuseSize]
set udg_Fusion_Item_DefReuseSize = udg_Fusion_Item_DefReuseSize - 1
else
set udg_Fusion_Item_DefSize = udg_Fusion_Item_DefSize + 1
set returnValue = udg_Fusion_Item_DefSize
endif
return returnValue
endfunction
// Will Create a new Fusion Object
//Cloning Fusion, Source,LEvel,Owner,Data, add all Units to the a group
function UnitFusionCloneObject takes integer sourceObject returns integer
local integer indexObject = UnitFusionInserObject()
if udg_Fusion_Object_Loc[indexObject] == null then
set udg_Fusion_Object_Loc[indexObject] = Location(GetLocationX(udg_Fusion_Object_Loc[sourceObject]),GetLocationY(udg_Fusion_Object_Loc[sourceObject]))
else
call MoveLocation(udg_Fusion_Object_Loc[indexObject],GetLocationX(udg_Fusion_Object_Loc[sourceObject]),GetLocationY(udg_Fusion_Object_Loc[sourceObject]))
endif
if udg_Fusion_Object_Group[indexObject] == null then
set udg_Fusion_Object_Group[indexObject] = CreateGroup()
else
call GroupClear(udg_Fusion_Object_Group[indexObject])
endif
set udg_Fusion_Object_Fusion[indexObject] = udg_Fusion_Object_Fusion[sourceObject]
set udg_Fusion_Object_Source[indexObject] = udg_Fusion_Object_Source[sourceObject]
set udg_Fusion_Object_SpellLevel[indexObject] = udg_Fusion_Object_SpellLevel[sourceObject]
set udg_Fusion_Object_DataIndex[indexObject] = udg_Fusion_Object_DataIndex[sourceObject]
set udg_Fusion_Object_Effect[indexObject] = null
call GroupAddGroup(udg_Fusion_Object_Group[sourceObject],udg_Fusion_Object_Group[indexObject])
// call printCloneGroups(udg_Fusion_Object_Group[sourceObject],udg_Fusion_Object_Group[indexObject])
return indexObject
endfunction
function UnitFusionItemStackRemove takes integer indexChoosen returns nothing
//That makes no sense
if indexChoosen == -1 then
return
endif
if indexChoosen != udg_Fusion_Item_Size then
set udg_Fusion_Item_Item[indexChoosen] = udg_Fusion_Item_Item[udg_Fusion_Item_Size]
set udg_Fusion_Item_Owner[indexChoosen] = udg_Fusion_Item_Owner[udg_Fusion_Item_Size]
endif
set udg_Fusion_Item_Item[udg_Fusion_Item_Size] = null
set udg_Fusion_Item_Owner[udg_Fusion_Item_Size] = null
set udg_Fusion_Item_Size = udg_Fusion_Item_Size - 1
endfunction
//Returns the Item with the highest Level from the stack.
//removeReturned = true will take it from the stack and countdown.
function UnitFusionBestItem takes nothing returns integer
local integer LoopA = 1
local integer indexChoosen = -1
local integer level = 0
//Find one with highestLevel
loop
exitwhen LoopA > udg_Fusion_Item_Size
if level < GetItemLevel(udg_Fusion_Item_Item[LoopA]) then
set indexChoosen = LoopA
set level = GetItemLevel(udg_Fusion_Item_Item[LoopA])
endif
set LoopA = LoopA + 1
endloop
return indexChoosen
endfunction
//Returns the ItemTypeId of the item with the highest Level from the stack.
//removeReturned = true will take it from the stack and countdown.
//might be unneeded
function UnitFusionBestItemType takes boolean removeReturned returns integer
local integer LoopA = 1
local integer indexChoosen = -1
local integer itemId = 0
local integer level = 0
//Find one with highestLevel
loop
exitwhen LoopA > udg_Fusion_Item_Size
if level < GetItemLevel(udg_Fusion_Item_Item[LoopA]) then
set indexChoosen = LoopA
set itemId = GetItemTypeId(udg_Fusion_Item_Item[indexChoosen])
set level = GetItemLevel(udg_Fusion_Item_Item[LoopA])
endif
set LoopA = LoopA + 1
endloop
//Reindex?
if removeReturned and indexChoosen != -1 then
if indexChoosen != udg_Fusion_Item_Size then
set udg_Fusion_Item_Item[indexChoosen] = udg_Fusion_Item_Item[udg_Fusion_Item_Size]
set udg_Fusion_Item_Owner[udg_Fusion_Item_Size] = udg_Fusion_Item_Owner[udg_Fusion_Item_Size]
else
set udg_Fusion_Item_Item[udg_Fusion_Item_Size] = null
set udg_Fusion_Item_Owner[udg_Fusion_Item_Size] = null
endif
set udg_Fusion_Item_Size = udg_Fusion_Item_Size - 1
endif
return itemId
endfunction
//Take items from the ItemStack and move them to the Unit u.
//Will give the hero the best (heighest Level) first
function UnitFusionGiveItems takes unit u returns nothing
local integer creationCount = UnitInventorySize(u)
local integer indexChoosen
local integer indexCurrent
local integer indexLast
loop
exitwhen 0 == udg_Fusion_Item_Size or creationCount == 0
set indexChoosen = UnitFusionBestItem()
if indexChoosen != 0 then
call UnitAddItem (u, udg_Fusion_Item_Item[indexChoosen])
call UnitFusionItemStackRemove(indexChoosen)
set creationCount = creationCount - 1
else
set creationCount = 0
endif
endloop
endfunction
//Take items from the ItemStack and move them to the Unit u.
//Will give the hero the best (heighest Level) first
// This will save items and old owners.
function UnitFusionGiveItemsSave takes unit u, integer indexDefusion returns nothing
local integer creationCount = UnitInventorySize(u)
local integer indexChoosen
local integer indexCurrent
local integer indexLast
//This is the End point of this Defusions items.
set udg_Fusion_Object_Int3[indexDefusion] = UnitDefusionItemGetFreeSpot()
set indexCurrent =udg_Fusion_Object_Int3[indexDefusion]
loop
exitwhen 0 == udg_Fusion_Item_Size or creationCount == 0
set indexChoosen = UnitFusionBestItem()
if indexChoosen != -1 then
set indexLast = indexCurrent
set indexCurrent = UnitDefusionItemGetFreeSpot()
set udg_Fusion_Item_DefNext[indexLast] = indexCurrent
set udg_Fusion_Item_Item[indexCurrent] = udg_Fusion_Item_Item[indexChoosen]
set udg_Fusion_Item_Owner[indexCurrent] = udg_Fusion_Item_Owner[indexChoosen]
//call BJDebugMsg(GetItemName(udg_Fusion_Item_Item[indexCurrent])+ GetHeroProperName(udg_Fusion_Item_Owner[indexCurrent]))
call UnitAddItem (u, udg_Fusion_Item_Item[indexChoosen])
call UnitFusionItemStackRemove(indexChoosen)
set creationCount = creationCount - 1
else
set creationCount = 0
endif
endloop
//finish the list
set udg_Fusion_Item_DefNext[indexCurrent] = -1
endfunction
//This Loads all Items of the unit into the stack.
//Will Count up udg_Fusion_Item_Size
function UnitFusionLoadInventory takes unit u returns nothing
local integer LoopInventory = 0
//Gain Items
if UnitInventorySize(u) != 0 then
loop
exitwhen LoopInventory == UnitInventorySize(u)
if UnitItemInSlot(u, LoopInventory) != null then
set udg_Fusion_Item_Size = udg_Fusion_Item_Size + 1
set udg_Fusion_Item_Item[udg_Fusion_Item_Size] = UnitItemInSlot(u, LoopInventory)
set udg_Fusion_Item_Owner[udg_Fusion_Item_Size] = u
endif
set LoopInventory = LoopInventory + 1
endloop
endif
endfunction
//Overall timer
//Executes sub actions based on Type.
//Main Index for sub functions are
// udg_Fusion_Current_Pointer the pointer
function UnitFusionTimer takes nothing returns nothing
local integer LoopA = 1
//call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,1,I2S(udg_Fusion_System_Pointer_Last))
loop
exitwhen LoopA > udg_Fusion_System_Pointer_Last
if not udg_Fusion_System_Pointer_Finished[LoopA] then
set udg_Fusion_Current_Pointer = LoopA
set udg_Fusion_Current_Object = udg_Fusion_System_Pointer[LoopA]
set udg_Fusion_Current_Data = udg_Fusion_Object_DataIndex[udg_Fusion_Current_Object]
call ExecuteFunc(udg_Fusion_Object_Type[udg_Fusion_Current_Object])
else
//Mark DataRow reusable
set udg_Fusion_System_ReuseSize = udg_Fusion_System_ReuseSize + 1
set udg_Fusion_System_Reuse[udg_Fusion_System_ReuseSize] = udg_Fusion_System_Pointer[LoopA]
//Pointer Reindex
set udg_Fusion_Object_Pointer[udg_Fusion_System_Pointer[LoopA]] = udg_Fusion_System_Pointer_Last
set udg_Fusion_System_Pointer_Finished[LoopA] = udg_Fusion_System_Pointer_Finished[udg_Fusion_System_Pointer_Last]
set udg_Fusion_System_Pointer[LoopA] = udg_Fusion_System_Pointer[udg_Fusion_System_Pointer_Last]
set udg_Fusion_System_Pointer_Last = udg_Fusion_System_Pointer_Last - 1
set LoopA = LoopA - 1
endif
set LoopA = LoopA + 1
endloop
if udg_Fusion_System_Pointer_Last == 0 then
call PauseTimer(udg_Fusion_System_Timer)
endif
endfunction
//This is called to (re)start the timer.
function UnitFusionTimerStart takes nothing returns nothing
if not udg_Fusion_System_TimerDisabled then
call TimerStart(udg_Fusion_System_Timer, UnitFusionTimerSpeed(),true, function UnitFusionTimer)
endif
endfunction
function UnitDropInventory takes unit u returns nothing
local integer LoopInventory = UnitInventorySize(u)
if UnitInventorySize(u) != 0 then
loop
set LoopInventory = LoopInventory - 1
exitwhen LoopInventory == -1
call UnitRemoveItemFromSlot(u, LoopInventory)
endloop
endif
endfunction
//This function will defusion an fusion unit.
//call it with index -1, if you don't know the Defusion index.
function UnitDefusion takes unit u, boolean killed, integer indexFusion returns nothing
local integer LoopA = 1
local integer LoopB
local integer itemIndex
local integer indexData
local real x
local real x2
local real y
local real y2
local real angleInc
local real angle
local item i
local integer amountMats
local integer exp
local unit fog
local boolean wasSelected = IsUnitSelected(u, GetOwningPlayer(u))
//Skip calls using unit without anyone in users.
if FirstOfGroup(udg_Fusion_System_DefusionUser) == null and indexFusion == -1 then
return
endif
//call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 5, "Defusion")
//When indexFusion unknown find it.
if indexFusion == - 1 then
loop
exitwhen LoopA > udg_Fusion_System_Pointer_Last
//Find Defusion
if u == udg_Fusion_Object_Fusion[udg_Fusion_System_Pointer[LoopA]] then
// call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 5, "Nr:"+I2S(LoopA))
set indexFusion = udg_Fusion_System_Pointer[LoopA]
set udg_Fusion_System_Pointer_Finished[LoopA] = true
exitwhen true
endif
set LoopA = LoopA + 1
endloop
set x = GetUnitX(u)
set y = GetUnitY(u)
else
set udg_Fusion_System_Pointer_Finished[udg_Fusion_Object_Pointer[indexFusion]] = true
set u = udg_Fusion_Object_Fusion[indexFusion]
set x = GetLocationX(udg_Fusion_Object_Loc[indexFusion])
set y = GetLocationY(udg_Fusion_Object_Loc[indexFusion])
endif
call GroupRemoveUnit(udg_Fusion_System_DefusionUser, u)
//not found?
if indexFusion == -1 then
return
endif
set indexData = udg_Fusion_Object_DataIndex[indexFusion]
set amountMats = CountUnitsInGroup (udg_Fusion_Object_Group[indexFusion])
//call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 5, GetObjectName(udg_Fusion_Data_Spell[indexData]))
call DestroyEffect( AddSpecialEffect(udg_Fusion_Data_DefuseSFX[indexData],x,y))
//Drop Items and give them to their owners.
if udg_Fusion_Object_Int3[indexFusion] != -1 then
set itemIndex = udg_Fusion_Object_Int3[indexFusion]
loop
exitwhen itemIndex == -1
//call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 5, "Item Nr: "+I2S(itemIndex)+GetItemName(udg_Fusion_Item_Item[itemIndex]))
if UnitHasItem(u, udg_Fusion_Item_Item[itemIndex]) then
// call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 5, "Give it to: "+I2S(itemIndex)+GetHeroProperName(udg_Fusion_Item_Owner[itemIndex]))
call PauseUnit(udg_Fusion_Item_Owner[itemIndex], false)
call ShowUnit(udg_Fusion_Item_Owner[itemIndex], true)
call UnitAddItem(udg_Fusion_Item_Owner[itemIndex], udg_Fusion_Item_Item[itemIndex])
endif
//mark as free.
set udg_Fusion_Item_DefReuseSize = udg_Fusion_Item_DefReuseSize + 1
set udg_Fusion_Item_DefReuse[udg_Fusion_Item_DefReuseSize] = itemIndex
//next item
set itemIndex = udg_Fusion_Item_DefNext[itemIndex]
endloop
//Drop all items from the fusion.
set LoopA = UnitInventorySize(u) - 1
loop
exitwhen LoopA == -1
call SetItemPosition( UnitItemInSlot (u, LoopA),x,y)
set LoopA = LoopA - 1
endloop
endif
//Prepare Event
set udg_Fusion_Event_Fusion = u
set udg_Fusion_Event_Source = udg_Fusion_Object_Source[indexFusion]
set udg_Fusion_Event_SpellData = udg_Fusion_Object_DataIndex[indexFusion]
set udg_Fusion_Event_SpellLevel = udg_Fusion_Object_SpellLevel[indexFusion]
set udg_Fusion_Event_SpellObject = indexFusion
call GroupClear (udg_Fusion_Event_Group)
//Remove the Fuion?
if udg_Fusion_Data_Remove[indexData] then
call RemoveUnit(u)
else
//Might be a Custom call to defuse
call KillUnit(u)
endif
set angle = 0
set angleInc = 2 * bj_PI / amountMats
//Current Exp - old exp = gained Exp
set exp = R2I((udg_Fusion_Object_Int2[indexFusion] - udg_Fusion_Object_Int1[indexFusion]) * udg_Fusion_Data_DefusionEXPMulti[indexData] / amountMats)
//Restore fusion Parts.
loop
set fog = FirstOfGroup (udg_Fusion_Object_Group[indexFusion])
exitwhen fog == null
call GroupRemoveUnit(udg_Fusion_Object_Group[indexFusion],fog)
set x2 = x + udg_Fusion_Data_DefuseDistance[indexData]*Cos(angle)
set y2 = y + udg_Fusion_Data_DefuseDistance[indexData]*Sin(angle)
set angle = angle + angleInc
// call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 5, "ReGain "+GetUnitName(fog) )
//Make Mats useable
call SetUnitPosition(fog, x2,y2)
call ShowUnit(fog,true)
call PauseUnit(fog,false)
call SetUnitInvulnerable(fog, false )
call SetUnitPathing (fog, true)
call SetUnitVertexColor(fog,255,255,255,255)
call UnitRemoveAbility(fog ,'Arav')
call AddHeroXP(fog, exp, true)
if udg_Fusion_Data_DefuseDispellMat[indexData] then
call UnitRemoveBuffs(fog, true, true)
endif
call SetUnitFacing(fog,bj_RADTODEG * Atan2(y - y2, x - x2))
//Load defused material into fusionGroup
call GroupAddUnit(udg_Fusion_Event_Group, fog)
//What shall happen with the mat?
if (killed and not udg_Fusion_Data_DefuseOnKilled[indexData]) or ( not killed and not udg_Fusion_Data_DefuseAfterDur[indexData] )then
//units are lost.
call UnitDropInventory(fog)
call RemoveUnit(fog)
else
call SetUnitUseFood( fog, true )
if wasSelected then
call SelectUnitAddForPlayer( fog, GetOwningPlayer(fog))
endif
if killed then
//call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 5, "Fusion killed/Removed - Set Restored Unit's Life to ="+GetUnitName(u)+" "+ R2S(( GetUnitState(u, UNIT_STATE_MAX_LIFE))* udg_Fusion_Data_DefuseOnKilledHP[indexData]))
call SetUnitState(fog, UNIT_STATE_LIFE, GetUnitState(fog, UNIT_STATE_MAX_LIFE) * udg_Fusion_Data_DefuseOnKilledHP[indexData])
call SetUnitState(fog, UNIT_STATE_MANA, GetUnitState(fog, UNIT_STATE_MAX_MANA) * udg_Fusion_Data_DefuseOnKilledMP[indexData])
else
if udg_Fusion_Data_DefuseAfterDurHP[indexData] == -1 then
call SetUnitState(fog, UNIT_STATE_LIFE, GetUnitState(fog, UNIT_STATE_MAX_LIFE) * udg_Fusion_Object_Real1[indexFusion])
else
call SetUnitState(fog, UNIT_STATE_LIFE, GetUnitState(fog, UNIT_STATE_MAX_LIFE) * udg_Fusion_Data_DefuseAfterDurHP[indexData])
endif
if udg_Fusion_Data_DefuseAfterDurMP[indexData] == -1 then
call SetUnitState(fog, UNIT_STATE_MANA, GetUnitState(fog, UNIT_STATE_MAX_MANA) * udg_Fusion_Object_Real2[indexFusion])
else
call SetUnitState(fog, UNIT_STATE_MANA, GetUnitState(fog, UNIT_STATE_MAX_MANA) * udg_Fusion_Data_DefuseAfterDurMP[indexData])
endif
endif
endif
endloop
//Throw Event
set udg_Fusion_Event = UnitFusionEventDefusion()
set udg_Fusion_Event = 0
endfunction
//Will get one the Life and Mana from the Defusion. To use on defusion.
// Int1 = Old EP
// Int2 = current ep
// Real1 = current Life
// Real2 = current Mana.
function UnitDefusionMonitor takes nothing returns nothing
local integer indexObject = udg_Fusion_System_Pointer[udg_Fusion_Current_Pointer]
//was Removed?
if GetUnitState(udg_Fusion_Object_Fusion[indexObject], UNIT_STATE_MAX_LIFE) != 0 then
set udg_Fusion_Object_Int2[indexObject] = GetHeroXP (udg_Fusion_Object_Fusion[indexObject])
call MoveLocation(udg_Fusion_Object_Loc[indexObject],GetUnitX(udg_Fusion_Object_Fusion[indexObject]),GetUnitY(udg_Fusion_Object_Fusion[indexObject]))
//Percent
set udg_Fusion_Object_Real1[indexObject] = GetUnitState( udg_Fusion_Object_Fusion[indexObject], UNIT_STATE_LIFE)/ GetUnitState( udg_Fusion_Object_Fusion[indexObject], UNIT_STATE_MAX_LIFE)
if GetUnitState(udg_Fusion_Object_Fusion[indexObject], UNIT_STATE_MAX_MANA) != 0 then
set udg_Fusion_Object_Real2[indexObject] = GetUnitState( udg_Fusion_Object_Fusion[indexObject], UNIT_STATE_MANA)/GetUnitState( udg_Fusion_Object_Fusion[indexObject], UNIT_STATE_MAX_MANA)
endif
else
//call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 5, "Force Defusion: ")
call UnitDefusion(null, true, indexObject)
endif
endfunction
//Triggers if an Unit dies.
function UnitDefusionDeath takes nothing returns nothing
if IsUnitInGroup (GetTriggerUnit(), udg_Fusion_System_DefusionUser) then
call UnitDefusion(GetTriggerUnit(), (GetKillingUnit() != null), -1 )
endif
endfunction
//This will use the given Fusion_Object and use it for defusion
//If you need an new one call it with InserObject or with cloneObject
function UnitDefusionTransformObject takes integer indexObject returns nothing
set udg_Fusion_Object_Int1[indexObject] = GetHeroXP (udg_Fusion_Object_Fusion[indexObject])
set udg_Fusion_Object_Int2[indexObject] = udg_Fusion_Object_Int1[indexObject]
//Next Line saves defusions if they do not take over items
set udg_Fusion_Object_Int3[indexObject] = -1
set udg_Fusion_Object_Type[indexObject] = UnitFusionTypeDefusion()
call DestroyEffect(udg_Fusion_Object_Effect[indexObject])
set udg_Fusion_Object_Effect[indexObject] = null
call GroupAddUnit(udg_Fusion_System_DefusionUser, udg_Fusion_Object_Fusion[indexObject])
call UnitFusionTimerStart()
endfunction
//perfoms actions an Material for Defusion should do.
function UnitDefusionSaveMatObject takes unit u, integer indexObject returns nothing
call GroupAddUnit(udg_Fusion_Object_Group[indexObject], u)
call SetUnitInvulnerable(u, true )
call PauseUnit(u, true )
call ShowUnit(u, false)
call SetUnitUseFood( u, false )
call SetUnitPathing (u, false)
call SetUnitPositionLoc(u, udg_Fusion_System_SaveLoc)
endfunction
//Action
// Real1 = remaningDur in seconds.
// Real2 = CurrentTransparenz
// Real3 = Transparenz change a intervale
function UnitFusionFadeIn takes nothing returns nothing
local integer indexObject = udg_Fusion_System_Pointer[udg_Fusion_Current_Pointer]
local integer indexData = udg_Fusion_Object_DataIndex[indexObject]
//Stop instantly when Fusion Unit was removed/dead.
if GetWidgetLife(udg_Fusion_Object_Fusion[indexObject]) < 0.405 then
set udg_Fusion_System_Pointer_Finished[udg_Fusion_Current_Pointer] = true
call DestroyEffect(udg_Fusion_Object_Effect[indexObject])
set udg_Fusion_Object_Effect[indexObject] = null
return
endif
//Calc new Transperence
set udg_Fusion_Object_Real2[indexObject] = udg_Fusion_Object_Real2[indexObject] + udg_Fusion_Object_Real3[indexObject]
call SetUnitVertexColor(udg_Fusion_Object_Fusion[indexObject], 255, 255, 255, R2I(udg_Fusion_Object_Real2[indexObject]))
set udg_Fusion_Object_Real1[indexObject] = udg_Fusion_Object_Real1[indexObject] - UnitFusionTimerSpeed()
//FadeIn Finish?
if udg_Fusion_Object_Real1[indexObject] <= 0.0 then
set udg_Fusion_System_Pointer_Finished[udg_Fusion_Current_Pointer] = true
//Finish destroy
if not udg_Fusion_Object_Bool[indexObject] then
call SetUnitInvulnerable(udg_Fusion_Object_Fusion[indexObject], false )
endif
call PauseUnit(udg_Fusion_Object_Fusion[indexObject], false)
if UnitFusionAutoSelect() then
call SelectUnitAddForPlayer(udg_Fusion_Object_Fusion[indexObject], GetOwningPlayer(udg_Fusion_Object_Fusion[indexObject]))
endif
//call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, UnitFusionErrorDur(), udg_Fusion_Data_SFXResult[indexData] +" "+ udg_Fusion_Data_SFXResultAttacht[indexData] )
call DestroyEffect(AddSpecialEffectTarget( udg_Fusion_Data_SFXResult[indexData] , udg_Fusion_Object_Fusion[indexObject],udg_Fusion_Data_SFXResultAttacht[indexData] ))
call DestroyEffect(udg_Fusion_Object_Effect[indexObject])
set udg_Fusion_Object_Effect[indexObject] = null
//Throw Event
call GroupClear (udg_Fusion_Event_Group)
call GroupAddGroup(udg_Fusion_Object_Group[indexObject], udg_Fusion_Event_Group)
set udg_Fusion_Event_Fusion = udg_Fusion_Object_Fusion[indexObject]
set udg_Fusion_Event_Source = udg_Fusion_Object_Source[indexObject]
set udg_Fusion_Event_SpellData = indexData
set udg_Fusion_Event_SpellLevel = udg_Fusion_Object_SpellLevel[indexObject]
set udg_Fusion_Event_SpellObject = indexObject
set udg_Fusion_Event = UnitFusionEventFadeInFinish()
set udg_Fusion_Event = 0
//this will clean the objct on next timer intervale
else
call PauseUnit(udg_Fusion_Object_Fusion[indexObject], true)
endif
endfunction
//Takeover an FusionObject for fading in
//To start an new call it with cloneObject(orginalObject)
// Real1 = remaningDur in seconds.
// Real2 = CurrentTransparenz
// Real3 = Transparenz change a intervale
function UnitFusionStartFadeInTakeOver takes integer indexObject returns nothing
local integer indexData = udg_Fusion_Object_DataIndex[indexObject]
if not udg_Fusion_Data_FadeVulnerable[indexData] then
call SetUnitInvulnerable( udg_Fusion_Object_Fusion[indexObject], true )
endif
set udg_Fusion_Object_Bool[indexObject] = udg_Fusion_Data_FadeVulnerable[indexData]
call PauseUnit(udg_Fusion_Object_Fusion[indexObject], true)
call SetUnitVertexColor(udg_Fusion_Object_Fusion[indexObject], 255, 255, 255, 0)
if udg_Fusion_Object_Effect[indexObject] == null then
set udg_Fusion_Object_Effect[indexObject] = AddSpecialEffect( udg_Fusion_Data_SFX[indexData] , GetUnitX(udg_Fusion_Object_Fusion[indexObject]),GetUnitY(udg_Fusion_Object_Fusion[indexObject]))
endif
set udg_Fusion_Object_Type[indexObject] = UnitFusionTypeFadeIn()
set udg_Fusion_Object_Real1[indexObject] = udg_Fusion_Data_FadeIn[indexData]
set udg_Fusion_Object_Real2[indexObject] = 0
set udg_Fusion_Object_Real3[indexObject]= PercentToInt(100 - udg_Fusion_Data_FadeInHidden[indexData], 255) / udg_Fusion_Data_FadeIn[indexData] * UnitFusionTimerSpeed()
//Duration above 0?
if udg_Fusion_Data_ResultDur[indexData] + udg_Fusion_Data_ResultDurPerLevel[indexData] * udg_Fusion_Object_SpellLevel[indexObject] > 0 then
call UnitApplyTimedLife( udg_Fusion_Object_Fusion[indexObject], 'BTLF', udg_Fusion_Data_ResultDur[indexData] + udg_Fusion_Data_ResultDurPerLevel[indexData] * udg_Fusion_Object_SpellLevel[indexObject] )
endif
call UnitFusionTimerStart()
endfunction
//Start FadingIn for u
// Creates a new Fusion Object.
//This for peouple who want to use the fadeinEffect.
function UnitFusionStartFadeIn takes unit u, real dur, real hiddenStateAfter, string sfx, boolean immunDuringFade returns nothing
local integer indexObject
set indexObject = UnitFusionInserObject()
if immunDuringFade then
call SetUnitInvulnerable( u, true )
endif
set udg_Fusion_Object_Bool[indexObject] = immunDuringFade
call PauseUnit(u, true)
call SetUnitVertexColor(u, 255, 255, 255, 0)
//Call it without unit.
set udg_Fusion_Object_Fusion[indexObject] = u
set udg_Fusion_Object_Type[indexObject] = UnitFusionTypeFadeIn()
set udg_Fusion_Object_Real1[indexObject] = dur
set udg_Fusion_Object_DataIndex[indexObject] = -1
//Create new effect?
set udg_Fusion_Object_Effect[indexObject] = AddSpecialEffect( sfx, GetUnitX(u), GetUnitY(u) )
set udg_Fusion_Object_Real2[indexObject] = 0
set udg_Fusion_Object_Real3[indexObject]= PercentToInt(100 - hiddenStateAfter, 255) / dur * UnitFusionTimerSpeed()
call UnitFusionTimerStart()
endfunction
function UnitFusionPulledGetItems takes nothing returns nothing
call UnitFusionLoadInventory(GetEnumUnit())
endfunction
//Subfunction - UnitFusionPulled
//Removes the material
function UnitFusionCleanMats takes nothing returns nothing
local unit u = GetEnumUnit()
call ShowUnit(u, false)
call ShowUnit(u, true)
if udg_Fusion_Data_Remove[udg_Fusion_Current_Data] then
call UnitDropInventory(u)
call RemoveUnit(u)
else
call KillUnit(u)
endif
set u = null
endfunction
//Subfunction - UnitFusionPulled
//Removes substitutes missles
function UnitFusionPulledClean takes nothing returns nothing
local unit u = GetEnumUnit()
if GetUnitTypeId(u) == udg_Fusion_Data_Replace[udg_Fusion_Current_Data] then
call GroupRemoveUnit(udg_Fusion_Object_Group[udg_Fusion_Current_Object] , u)
call RemoveUnit(u)
endif
set u = null
endfunction
//Loads real Units into the FusionEventGroup
//Old - Unneeded
function UnitFusionLoadParts takes nothing returns nothing
if GetUnitTypeId(GetEnumUnit()) != udg_Fusion_Data_Replace[udg_Fusion_Current_Data] then
call GroupAddUnit (udg_Fusion_Event_Group, GetEnumUnit())
endif
endfunction
//Subfunction - UnitFusionPulled
//Group Enumeration of Current FusionGroup
//Real1 = Speed
//Real2 = ZSpeed
function UnitFusionPulledPull takes nothing returns nothing
local integer indexObject = udg_Fusion_System_Pointer[udg_Fusion_Current_Pointer]
local integer indexData = udg_Fusion_Object_DataIndex[indexObject]
local unit u = GetEnumUnit()
local real x
local real y
local real angle
//call BJDebugMsg("Pull")
//do not move real units if there is an replace.
if udg_Fusion_Data_Replace[indexData] != 0 and GetUnitTypeId(u) != udg_Fusion_Data_Replace[indexData] then
return
endif
//Flying enabled?
if udg_Fusion_Object_Real2[indexObject] > 0 then
call SetUnitFlyHeight( u, ( GetUnitFlyHeight(u) + udg_Fusion_Object_Real2[indexObject] ), 0.00 )
endif
//Avoid Moving units over the Location; hidden defusion using an replace do not matter.
if IsUnitInRangeLoc(u, udg_Fusion_Object_Loc[indexObject], udg_Fusion_Object_Real1[indexObject]) or ((udg_Fusion_Data_DefuseAfterDur[indexData] or udg_Fusion_Data_DefuseOnKilled[indexData]) and udg_Fusion_Data_Replace[indexData] == 0 and GetUnitTypeId(u) != udg_Fusion_Data_Replace[indexData]) then
call SetUnitPositionLoc( u, udg_Fusion_Object_Loc[indexObject] )
else
set udg_Fusion_Object_Bool[indexObject] = false
set x = GetUnitX(u)
set y = GetUnitY(u)
set angle = Atan2(GetLocationY(udg_Fusion_Object_Loc[indexObject]) - y, GetLocationX(udg_Fusion_Object_Loc[indexObject]) - x)
set x = x + udg_Fusion_Object_Real1[indexObject] * Cos(angle)
set y = y + udg_Fusion_Object_Real1[indexObject] * Sin(angle)
call SetUnitPosition( u, x,y )
endif
endfunction
//Group Action to take defusion Material out of play.
function UnitFusionSaveMat takes nothing returns nothing
call UnitDefusionSaveMatObject(GetEnumUnit(),udg_Fusion_Current_Object)
endfunction
//Spawns the Fusion
//Based on the Fusion Object
//Will fill udg_Fusion_Object_Fusion[indexObject] with the fusion.
function UnitFusionSpawn takes integer indexObject, real x, real y returns nothing
local integer indexData = udg_Fusion_Object_DataIndex[indexObject]
local unit u = CreateUnit (GetOwningPlayer(udg_Fusion_Object_Source[indexObject]), udg_Fusion_Data_Result[indexData], x, y, 270 )
local boolean hasInventory = (UnitInventorySize(u) != 0)
local boolean defusion = udg_Fusion_Data_DefuseAfterDur[indexData] or udg_Fusion_Data_DefuseOnKilled[indexData]
call UnitAddAbility(u, udg_Fusion_Data_SkillGained[indexData])
set udg_Fusion_Object_Fusion[indexObject] = u
call SetHeroLevel (u, udg_Fusion_Object_Int1[indexObject], false)
//Which Statmod, statsmod 0 is default?
if udg_Fusion_Data_HeroStatsMod[indexData] != 0 then
call SetHeroAgi (u, udg_Fusion_Object_Int2[indexObject], true)
call SetHeroStr (u, udg_Fusion_Object_Int3[indexObject], true)
call SetHeroInt (u, udg_Fusion_Object_Int4[indexObject], true)
endif
//Load Items.
if hasInventory then
set udg_Fusion_Item_Size = 0
call ForGroup(udg_Fusion_Object_Group[indexObject], function UnitFusionPulledGetItems)
endif
//Defusion?
if defusion then
call UnitDefusionTransformObject(indexObject)
set udg_Fusion_Current_Object = indexObject
call ForGroup(udg_Fusion_Object_Group[indexObject], function UnitFusionSaveMat)
set udg_Fusion_System_Pointer_Finished[udg_Fusion_Current_Pointer] = false
if hasInventory then
call UnitFusionGiveItemsSave(u, indexObject)
endif
else
set udg_Fusion_System_Pointer_Finished[udg_Fusion_Current_Pointer] = true
if hasInventory then
call UnitFusionGiveItems(u)
endif
endif
//apply Averrage Life?
if udg_Fusion_Data_ResultHPAverage[indexData] then
call SetUnitState(u, UNIT_STATE_LIFE, GetUnitState(u, UNIT_STATE_MAX_LIFE) * udg_Fusion_Object_Real3[indexObject] )
endif
//apply Averrage Mana?
if udg_Fusion_Data_ResultMPAverage[indexData] then
call SetUnitState(u, UNIT_STATE_MANA, GetUnitState(u, UNIT_STATE_MAX_MANA) * udg_Fusion_Object_Real4[indexObject] )
endif
//Throw Event
call GroupClear(udg_Fusion_Event_Group)
//call ForGroup(udg_Fusion_Object_Group[indexObject], function UnitFusionLoadParts)
call GroupAddGroup(udg_Fusion_Object_Group[indexObject], udg_Fusion_Event_Group)
set udg_Fusion_Event_Fusion = u
set udg_Fusion_Event_Source = udg_Fusion_Object_Source[indexObject]
set udg_Fusion_Event_SpellData = indexData
set udg_Fusion_Event_SpellLevel = udg_Fusion_Object_SpellLevel[indexObject]
set udg_Fusion_Event_SpellObject = indexObject
if IsUnitType (u, UNIT_TYPE_HERO) then
set udg_Fusion_Event = UnitFusionEventHero()
else
set udg_Fusion_Event = UnitFusionEventNonHero()
endif
set udg_Fusion_Event = 0
//Start FadeIn after pulling?
if udg_Fusion_Data_FadeIn[indexData] > 0 then
//Start a new Fusion Object or takeover?
if udg_Fusion_System_Pointer_Finished[udg_Fusion_Current_Pointer] then
call UnitFusionStartFadeInTakeOver(indexObject)
set udg_Fusion_System_Pointer_Finished[udg_Fusion_Current_Pointer] = false
else
call UnitFusionStartFadeInTakeOver(UnitFusionCloneObject(indexObject))
endif
else
// Timed Life > 0
// Constant + Level * Levelboni
if udg_Fusion_Data_ResultDur[indexData] + ( udg_Fusion_Data_ResultDurPerLevel[indexData]* udg_Fusion_Object_SpellLevel[indexObject]) > 0 then
call UnitApplyTimedLife( u, 'BTLF', udg_Fusion_Data_ResultDur[indexData] + ( udg_Fusion_Data_ResultDurPerLevel[indexData]* udg_Fusion_Object_SpellLevel[indexObject]) )
endif
call DestroyEffect(udg_Fusion_Object_Effect[indexObject])
set udg_Fusion_Object_Effect[indexObject] = null
if UnitFusionAutoSelect() then
call SelectUnitAddForPlayer(u, GetOwningPlayer(udg_Fusion_Object_Source[indexObject]))
endif
call DestroyEffect(AddSpecialEffectTarget( udg_Fusion_Data_SFXResult[indexData] , u,udg_Fusion_Data_SFXResultAttacht[indexData] ))
endif
//Clean mats if no defusion
if not defusion then
call ForGroup(udg_Fusion_Object_Group[indexObject], function UnitFusionCleanMats)
endif
set u = null
endfunction
//Timer Sub Action Pull Fusion
// Real = Speed
// Real2 = ZSpeed
// Real3 = life On Fusion
// Real4 = Mana on fusion
// Int1 = heroLevel
// Int2 = heroAgi
// Int3 = heroStr
// Int4 = heroInt
function UnitFusionPulled takes nothing returns nothing
local integer indexObject = udg_Fusion_System_Pointer[udg_Fusion_Current_Pointer]
set udg_Fusion_Object_Bool[indexObject] = true
//Loop All running fusion
//Used in the Subfunction
call ForGroup(udg_Fusion_Object_Group[indexObject], function UnitFusionPulledPull)
//All parts are near Enough?
if udg_Fusion_Object_Bool[indexObject] then
call ForGroup(udg_Fusion_Object_Group[indexObject], function UnitFusionPulledClean)
call UnitFusionSpawn(indexObject, GetLocationX(udg_Fusion_Object_Loc[indexObject]),GetLocationY(udg_Fusion_Object_Loc[indexObject]))
endif
endfunction
function UnitFusionIsPart takes unit u, integer indexData returns boolean
local integer indexEnd = udg_Fusion_System_UnitTypesEnd[indexData]
local integer indexCurrent = udg_Fusion_System_UnitTypesStart[indexData]
set udg_Fusion_Current_FilterUnit = u
//Can Unit be part of Fusion?
loop
if udg_Fusion_Data_UnitTypes[indexCurrent] == 0 and udg_Fusion_System_Units[indexCurrent] == null then
if TriggerEvaluate(udg_Fusion_Data_FilterWild[indexData]) then
set udg_Fusion_System_Units[indexCurrent] = u
return true
endif
endif
set indexCurrent = indexCurrent + 1
exitwhen indexCurrent > indexEnd
endloop
return false
endfunction
function UnitFusionIsSpecificPart takes unit u, integer indexData returns boolean
local integer indexEnd = udg_Fusion_System_UnitTypesEnd[indexData]
local integer indexCurrent = udg_Fusion_System_UnitTypesStart[indexData]
local integer uTyp = GetUnitTypeId(u)
//Can Unit be part of Fusion?
loop
if uTyp == udg_Fusion_Data_UnitTypes[indexCurrent] and udg_Fusion_System_Units[indexCurrent] == null then
set udg_Fusion_System_Units[indexCurrent] = u
return true
endif
set indexCurrent = indexCurrent + 1
exitwhen indexCurrent > indexEnd
endloop
return false
endfunction
function UnitFusionPickAny takes nothing returns nothing
call UnitFusionIsPart(GetEnumUnit(), udg_Fusion_Current_Data)
call GroupRemoveUnit(udg_Fusion_Object_Group[0], GetEnumUnit())
endfunction
function UnitFusionPickSpecific takes nothing returns nothing
if UnitFusionIsSpecificPart(GetEnumUnit(), udg_Fusion_Current_Data) then
call GroupRemoveUnit(udg_Fusion_Object_Group[0], GetEnumUnit())
endif
endfunction
function UnitFusionPickSelected takes nothing returns nothing
if IsUnitSelected(GetEnumUnit(), GetTriggerPlayer()) then
call UnitFusionPickSpecific()
endif
endfunction
function UnitFusionFilter takes unit u, integer indexData returns boolean
local integer indexEnd = udg_Fusion_System_UnitTypesEnd[indexData]
local integer indexCurrent = udg_Fusion_System_UnitTypesStart[indexData]
local real life = GetWidgetLife(u)
set udg_Fusion_Current_FilterUnit = u
//Allowed?
//Ordercheck;
//Filter Units if OrderCheck is set and Unit has not the expectedOrder.
if not (udg_Fusion_Data_OrderCheck[indexData] == "" or udg_Fusion_Data_OrderCheck[indexData] == null ) and OrderId(udg_Fusion_Data_OrderCheck[indexData]) != GetUnitCurrentOrder(u) then
return false
endif
if not TriggerEvaluate(udg_Fusion_Data_FilterPre[indexData]) and udg_Fusion_Data_FilterPre[indexData] != null then
return false
endif
if not TriggerEvaluate(udg_Fusion_Data_FilterMain[indexData]) and udg_Fusion_Data_FilterMain[indexData] != null then
return false
endif
//Needed UnitTypes pass
loop
if GetUnitTypeId(u) == udg_Fusion_Data_UnitTypes[indexCurrent] or udg_Fusion_Data_UnitTypes[indexCurrent] == 0 then
return true
endif
set indexCurrent = indexCurrent + 1
exitwhen indexCurrent > indexEnd
endloop
//if something goes terrible wrong.
return false
endfunction
function UnitFusionFilterEnum takes nothing returns boolean
if IsUnitPaused(GetFilterUnit()) or IsUnitIllusion(GetFilterUnit()) or not IsUnitInRangeLoc(GetFilterUnit(), udg_Fusion_Object_Loc[0], udg_Fusion_Object_Real1[0]) then
return false
endif
return UnitFusionFilter(GetFilterUnit(),udg_Fusion_Current_Data)
endfunction
function UnitFusionFilterMessage takes integer indexData, integer indexCurrent, string s returns string
local string seperator = "\n"
set s = s +seperator
//Specific UnitType?
if udg_Fusion_Data_UnitTypes[indexCurrent] != null then
set s = s + " - " + GetObjectName(udg_Fusion_Data_UnitTypes[indexCurrent])
else
set s = s + UnitFusionWildCard()
endif
set seperator = null
return s
endfunction
//Generate ErrorWarrinng
function UnitFusionErrorMessage takes integer indexData, string s returns string
local string seperator = "\n"
set s = "|cffffcc00"+ GetObjectName(udg_Fusion_Data_Spell[indexData])+"|r"
if udg_Fusion_Data_FilterPre[indexData]!= null and udg_Fusion_Data_ErrorMsgPre[indexData] != null and udg_Fusion_Data_ErrorMsgPre[indexData] !="" then
set s = s + seperator
set s = s + udg_Fusion_Data_ErrorMsgPre[indexData]
endif
if udg_Fusion_Data_FilterMain[indexData]!= null and udg_Fusion_Data_ErrorMsgMain[indexData] != null and udg_Fusion_Data_ErrorMsgMain[indexData] !="" then
set s = s + seperator
set s = s + udg_Fusion_Data_ErrorMsgMain[indexData]
endif
if udg_Fusion_Data_FilterWild[indexData]!= null and udg_Fusion_Data_ErrorMsgWild[indexData] != null and udg_Fusion_Data_ErrorMsgWild[indexData] !="" then
set s = s + seperator
set s = s + udg_Fusion_Data_ErrorMsgWild[indexData]
endif
set s = s + seperator + UnitFusionErrorMsg()
set seperator = null
return s
endfunction
function UnitFusionLoadGroup takes integer indexCurrent, integer indexEnd, integer indexObject returns nothing
loop
call GroupAddUnit(udg_Fusion_Object_Group[indexObject], udg_Fusion_System_Units[indexCurrent])
set indexCurrent = indexCurrent + 1
exitwhen indexCurrent > indexEnd
endloop
endfunction
function UnitFusionFuse takes integer indexData, location loc returns nothing
local integer indexEnd = udg_Fusion_System_UnitTypesEnd[indexData]
local integer indexCurrent = udg_Fusion_System_UnitTypesStart[indexData]
local integer amount = ( udg_Fusion_System_UnitTypesEnd[indexData] - udg_Fusion_System_UnitTypesStart[indexData] ) + 1
local real x = 0
local real y = 0
local real x2 = 0
local real y2 = 0
local boolean isValidFusion = true
local unit u
local integer level = GetUnitAbilityLevel(GetTriggerUnit(), udg_Fusion_Data_Spell[indexData])
local real life = 0
local real mana = 0
local string s
local boolean defusion = udg_Fusion_Data_DefuseAfterDur[indexData] or udg_Fusion_Data_DefuseOnKilled[indexData]
local integer heroLevel = 0
local integer heroAgi = 0
local integer heroStr = 0
local integer heroInt = 0
local integer indexEnter
local boolean isResultHero = IsUnitIdType(udg_Fusion_Data_Result[indexData], UNIT_TYPE_HERO)
set udg_Fusion_Current_Data = indexData
//clear old data
call GroupClear(udg_Fusion_Object_Group[0])
loop
set udg_Fusion_System_Units[indexCurrent] = null
exitwhen indexCurrent == indexEnd
set indexCurrent = indexCurrent + 1
endloop
//Index 0 is never used, so one can use it here.
set udg_Fusion_Object_Real1[0] = udg_Fusion_Data_AoE[indexData] + ( level * udg_Fusion_Data_AoEPerLevel[indexData])
if udg_Fusion_Object_Real1[0] > 0 then
set udg_Fusion_Object_Loc[0] = loc
call GroupEnumUnitsInRangeOfLoc(udg_Fusion_Object_Group[0], loc, udg_Fusion_Object_Real1[0] + UnitMaxColison() , udg_Fusion_System_Filter)
set udg_Fusion_Object_Loc[0] = null
endif
//AutoAddCaster?
if udg_Fusion_Data_AutoAddCaster[indexData] and UnitFusionFilter(GetTriggerUnit(),indexData ) then
if UnitFusionIsSpecificPart(GetTriggerUnit(), udg_Fusion_Current_Data) then
call GroupRemoveUnit(udg_Fusion_Object_Group[0], GetTriggerUnit())
endif
endif
//AutoAddTarget?
if udg_Fusion_Data_AutoAddTarget[indexData] and UnitFusionFilter(GetSpellTargetUnit(),indexData ) then
if UnitFusionIsSpecificPart(GetSpellTargetUnit(), udg_Fusion_Current_Data) then
call GroupRemoveUnit(udg_Fusion_Object_Group[0], GetSpellTargetUnit())
endif
endif
//First check selected
call ForGroup(udg_Fusion_Object_Group[0], function UnitFusionPickSelected)
//then check for defined unittypes
call ForGroup(udg_Fusion_Object_Group[0], function UnitFusionPickSpecific)
//then use wildcard unittypes
set indexCurrent = udg_Fusion_System_UnitTypesStart[indexData]
//spell has wildcards?
loop
if udg_Fusion_Data_UnitTypes[indexCurrent] == 0 then
call ForGroup(udg_Fusion_Object_Group[0], function UnitFusionPickAny)
exitwhen true
endif
set indexCurrent = indexCurrent + 1
exitwhen indexCurrent > indexEnd
endloop
//All MergingParts found?
set indexCurrent = udg_Fusion_System_UnitTypesStart[indexData]
set s = UnitFusionErrorMessage(indexData,"")
loop
if udg_Fusion_System_Units[indexCurrent] == null then
set isValidFusion = false
set s = UnitFusionFilterMessage(indexData,indexCurrent,s)
else
set x = x + GetUnitX(udg_Fusion_System_Units[indexCurrent])
set y = y + GetUnitY(udg_Fusion_System_Units[indexCurrent])
set life = life + GetUnitStatePercent(udg_Fusion_System_Units[indexCurrent] , UNIT_STATE_LIFE, UNIT_STATE_MAX_LIFE)
set mana = mana + GetUnitStatePercent(udg_Fusion_System_Units[indexCurrent] , UNIT_STATE_MANA, UNIT_STATE_MAX_MANA)
//HeroStuf
if IsUnitType(udg_Fusion_System_Units[indexCurrent] ,UNIT_TYPE_HERO) and isResultHero then
set heroLevel = heroLevel + GetHeroLevel (udg_Fusion_System_Units[indexCurrent])
set heroAgi = heroAgi + GetHeroAgi(udg_Fusion_System_Units[indexCurrent], udg_Fusion_Data_HeroAllowBoniStats[indexData])
set heroStr = heroStr + GetHeroStr(udg_Fusion_System_Units[indexCurrent], udg_Fusion_Data_HeroAllowBoniStats[indexData])
set heroInt = heroInt + GetHeroInt(udg_Fusion_System_Units[indexCurrent], udg_Fusion_Data_HeroAllowBoniStats[indexData])
endif
endif
set indexCurrent = indexCurrent + 1
exitwhen indexCurrent > indexEnd
endloop
if isValidFusion then
set x= x/amount
set y = y/amount
set life = (life/amount)*0.01
set mana = (mana/amount) *0.01
set indexCurrent = udg_Fusion_System_UnitTypesStart[indexData]
if udg_Fusion_Data_SpawnAtTargetPoint[indexData] then
set x = GetLocationX(loc)
set y = GetLocationY(loc)
endif
//Gives an free spot in the Object Arrays.
set indexEnter = UnitFusionInserObject()
set udg_Fusion_Current_Pointer = udg_Fusion_System_Pointer_Last
set udg_Fusion_Current_Object = indexEnter
set udg_Fusion_Object_DataIndex[indexEnter] = indexData
set udg_Fusion_Object_Source[indexEnter] = GetTriggerUnit()
set udg_Fusion_Object_Fusion[indexEnter] = null
set udg_Fusion_Object_SpellLevel[indexEnter] = level
set udg_Fusion_Object_Real3[indexEnter] = life
set udg_Fusion_Object_Real4[indexEnter] = mana
if isResultHero then
if not udg_Fusion_Data_HeroSumLevel[indexData] then
set heroLevel = heroLevel / amount
endif
if udg_Fusion_Data_HeroStatsMod[indexData] == 1 then
set heroAgi = heroAgi / amount
set heroStr = heroStr / amount
set heroInt = heroInt / amount
endif
set udg_Fusion_Object_Int1[indexEnter] = heroLevel
set udg_Fusion_Object_Int2[indexEnter] = heroAgi
set udg_Fusion_Object_Int3[indexEnter] = heroStr
set udg_Fusion_Object_Int4[indexEnter] = heroInt
endif
if udg_Fusion_Object_Group[indexEnter] == null then
set udg_Fusion_Object_Group[indexEnter] = CreateGroup()
else
call GroupClear (udg_Fusion_Object_Group[indexEnter])
endif
call UnitFusionLoadGroup(indexCurrent,indexEnd,indexEnter)
if udg_Fusion_Object_Loc[indexEnter] == null then
set udg_Fusion_Object_Loc[indexEnter] = Location(x,y)
else
call MoveLocation(udg_Fusion_Object_Loc[indexEnter],x,y)
endif
//Mark the Object as finished?
//Pulled Fusions / Defusions / Fadeins will take over this object.
//set udg_Fusion_System_Pointer_Finished[udg_Fusion_System_Pointer_Last] = not (udg_Fusion_Data_Speed[indexData] > 0 or udg_Fusion_Data_FadeIn[indexData] > 0 or defusion)
// Pull together:
if udg_Fusion_Data_Speed[indexData] > 0 then
set udg_Fusion_Object_Effect[indexEnter] = AddSpecialEffect( udg_Fusion_Data_SFX[indexData],x,y )
set udg_Fusion_Object_Type[indexEnter] = UnitFusionTypePull()
//For Pull Real 1 is Speed.
set udg_Fusion_Object_Real1[indexEnter] = udg_Fusion_Data_Speed[indexData] * UnitFusionTimerSpeed()
//For Pull Real2 is ZSpeed
set udg_Fusion_Object_Real2[indexEnter] = udg_Fusion_Data_SpeedZ[indexData] * UnitFusionTimerSpeed()
//Pull orginal units?
if udg_Fusion_Data_Replace[indexData] == 0 then
loop
call SetUnitFacing(udg_Fusion_System_Units[indexCurrent],bj_RADTODEG * Atan2(y - GetUnitY(udg_Fusion_System_Units[indexCurrent]), x - GetUnitX(udg_Fusion_System_Units[indexCurrent])))
call SetUnitVertexColor(udg_Fusion_System_Units[indexCurrent], 255, 255, 255, UnitFusionFade())
call DestroyEffect(AddSpecialEffectTarget( udg_Fusion_Data_SFXUnit[indexData] , udg_Fusion_System_Units[indexCurrent], udg_Fusion_Data_SFXUnitAttacht[indexData] ))
call UnitAddAbility(udg_Fusion_System_Units[indexCurrent], 'Arav' )
if not defusion then
call UnitAddAbility(udg_Fusion_System_Units[indexCurrent] , 'Aloc')
else
call SetUnitInvulnerable(udg_Fusion_System_Units[indexCurrent], true )
call SetUnitPathing (udg_Fusion_System_Units[indexCurrent], false)
endif
call PauseUnit(udg_Fusion_System_Units[indexCurrent], true )
set indexCurrent = indexCurrent + 1
exitwhen indexCurrent > indexEnd
endloop
else
//Pull substitutes
loop
set x2 =GetUnitX(udg_Fusion_System_Units[indexCurrent])
set y2 =GetUnitY(udg_Fusion_System_Units[indexCurrent])
call DestroyEffect(AddSpecialEffect( udg_Fusion_Data_SFXUnit[indexData],x2,y2 ))
if not defusion then
if udg_Fusion_Data_Remove[indexData] then
//Hide and Pause until pull is finished.
call ShowUnit(udg_Fusion_System_Units[indexCurrent], false)
call PauseUnit(udg_Fusion_System_Units[indexCurrent], true)
else
call KillUnit(udg_Fusion_System_Units[indexCurrent])
endif
else
call SetUnitInvulnerable(udg_Fusion_System_Units[indexCurrent], true )
call PauseUnit(udg_Fusion_System_Units[indexCurrent], true )
call SetUnitPathing (udg_Fusion_System_Units[indexCurrent], false)
call ShowUnit (udg_Fusion_System_Units[indexCurrent], false)
endif
//Substitudes should flying
set u = CreateUnit(GetTriggerPlayer(), udg_Fusion_Data_Replace[indexData], x2, y2, bj_RADTODEG * Atan2(y - y2, x - x2) )
call GroupAddUnit( udg_Fusion_Object_Group[indexEnter], u )
call PauseUnit(u, true )
set indexCurrent = indexCurrent + 1
exitwhen indexCurrent > indexEnd
endloop
set u = null
endif
call UnitFusionTimerStart()
else
//Instant Fusion
//Spawn Grafic Supstitudes
loop
set x2 =GetUnitX(udg_Fusion_System_Units[indexCurrent])
set y2 =GetUnitY(udg_Fusion_System_Units[indexCurrent])
call DestroyEffect(AddSpecialEffect( udg_Fusion_Data_SFXUnit[indexData],x2,y2 ))
//Spawn extra Units, if wanted.
//that is actually a hidden feature:
//if one does not set speed but uses replaces it will summon units, where the old units were standing.
//This summons have the same duration as the fusion.
if udg_Fusion_Data_Replace[indexData] != 0 then
set u = CreateUnit(GetTriggerPlayer(), udg_Fusion_Data_Replace[indexData], x2, y2, bj_RADTODEG * Atan2(y - y2, x - x2) )
// Timed Life > 0
// Constant + Level * Levelboni
if udg_Fusion_Data_ResultDur[indexData] + ( udg_Fusion_Data_ResultDurPerLevel[indexData]*level) > 0 then
call UnitApplyTimedLife(u, 'BTLF', udg_Fusion_Data_ResultDur[indexData] + ( udg_Fusion_Data_ResultDurPerLevel[indexData]*level))
endif
endif
set indexCurrent = indexCurrent + 1
exitwhen indexCurrent > indexEnd
endloop
call UnitFusionSpawn(indexEnter,x,y)
set u = null
endif
else
call DisplayTimedTextToPlayer(GetTriggerPlayer(), 0, 0, UnitFusionErrorDur(), s)
call DisplayTimedTextToPlayer(GetTriggerPlayer(), 0, 0, UnitFusionErrorDur(), ( "---------------" ))
endif
set s = null
set u = null
endfunction
function UnitFusionCasting takes nothing returns nothing
local integer indexData = 0
local integer Id = GetSpellAbilityId()
local location loc
if IsUnitHidden(GetTriggerUnit()) then
return
endif
//Find Casted Skill
loop
exitwhen indexData == udg_Fusion_CreationIndex
if Id == udg_Fusion_Data_Spell[indexData] then
//Has TargetUnit
if GetSpellTargetUnit() != null then
set loc = GetUnitLoc(GetSpellTargetUnit())
else
//Has TargetLoc? not 100% correct, but its pretty unlikly to cast something exactly at 0/0.
if GetSpellTargetX() == 0.0 and GetSpellTargetY() == 0.0 then
set loc = GetUnitLoc(GetTriggerUnit())
else
set loc = GetSpellTargetLoc()
endif
endif
call UnitFusionFuse(indexData, loc)
call RemoveLocation(loc)
set loc = null
return
endif
set indexData = indexData + 1
endloop
endfunction
//On First Execution of this System
//Preload Skills
//Enable Fusion
//Enable Defusion death detecion
//Preload Specialeffects
//Autogenerate missing Atttachmentpoints
//Printout Warnings for using wildcard units but having no FilterWild
function UnitFusionPreload takes nothing returns nothing
local unit u
local integer LoopA = 0
local integer LoopB
local real x = GetRectMaxX (bj_mapInitialPlayableArea)
local real y = GetRectMaxY (bj_mapInitialPlayableArea)
call TriggerClearActions(gg_trg_UnitFusion)
call TriggerAddAction( gg_trg_UnitFusion, function UnitFusionCasting )
call TriggerRegisterAnyUnitEventBJ( gg_trg_UnitFusion, EVENT_PLAYER_UNIT_SPELL_EFFECT )
set u = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), 'hfoo', 0,0, 270 )
call UnitAddAbility(u, 'Arav')
call UnitAddAbility(u, 'Aloc')
call RemoveUnit( u )
set udg_Fusion_System_DefusionTrigger = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ( udg_Fusion_System_DefusionTrigger, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddAction(udg_Fusion_System_DefusionTrigger, function UnitDefusionDeath)
set u = null
set udg_Fusion_Item_DefSize = UnitDefusionItemOffset()
//Define Filter for finding Mats.
set udg_Fusion_System_Filter = Condition(function UnitFusionFilterEnum)
//Preload specialeffects
//Autofills Attachmentpoints, if needed
loop
exitwhen LoopA == udg_Fusion_CreationIndex
call DestroyEffect(AddSpecialEffect( udg_Fusion_Data_SFXUnit[LoopA],x,y ))
call DestroyEffect(AddSpecialEffect( udg_Fusion_Data_SFX[LoopA],x,y ))
call DestroyEffect(AddSpecialEffect( udg_Fusion_Data_SFXResult[LoopA],x,y ))
//Use default attachment point?
if udg_Fusion_Data_SFXUnit[LoopA] != "" and StringIsEmpty(udg_Fusion_Data_SFXUnitAttacht[LoopA]) then
set udg_Fusion_Data_SFXUnitAttacht[LoopA] = "chest"
endif
//Use default attachment point?
if udg_Fusion_Data_SFXResult[LoopA] != "" and StringIsEmpty(udg_Fusion_Data_SFXResultAttacht[LoopA]) then
set udg_Fusion_Data_SFXResultAttacht[LoopA] = "origin"
endif
set LoopA = LoopA + 1
endloop
//Printout Warnings for using Wildcards but not using Wildcard Filters.
set LoopA = 0
loop
exitwhen LoopA == udg_Fusion_CreationIndex
set LoopB = udg_Fusion_System_UnitTypesStart[LoopA]
loop
exitwhen LoopB > udg_Fusion_System_UnitTypesEnd[LoopA]
if udg_Fusion_Data_UnitTypes[LoopB] == 0 then
if udg_Fusion_Data_FilterWild[LoopA] == null then
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,30,"|cffff0000Warning|r: "+ GetObjectName(udg_Fusion_Data_Spell[LoopA])+" uses Wildcards but has no Wildcard Filter.")
exitwhen true
endif
endif
set LoopB = LoopB + 1
endloop
set LoopA = LoopA + 1
endloop
endfunction
//===============
function InitTrig_UnitFusion takes nothing returns nothing
set gg_trg_UnitFusion = CreateTrigger( )
call TriggerAddAction( gg_trg_UnitFusion, function UnitFusionPreload )
endfunction
//===========================================================================
//
// Damage Engine 5.7.1.2 - update requires replacing the JASS script.
//
/*
Three GUI Damage systems for the community of The Hive,
Seven vJass Damage systems for the JASS-heads on their pedestals high,
Nine competing Damage systems, doomed to die,
One for Bribe on his dark throne
In the Land of the Hive where the Workshop lies.
One Damage Engine to rule them all, One Damage Engine to find them,
One Damage Engine to bring them all and in cross-compatibility unite them.
*/
//! novjass
JASS API (work in progress - I have a lot of documentation to go through):
struct Damage extends array
readonly static unit source //stores udg_DamageEventSource
readonly static unit target //stores udg_DamageEventTarget
static real amount //stores udg_DamageEventAmount
readonly unit sourceUnit //stores udg_DamageEventSource by index
readonly unit targetUnit //stores udg_DamageEventTarget by index
real damage //stores udg_DamageEventAmount by index
readonly real prevAmt //stores udg_DamageEventPrevAmt by index
attacktype attackType //stores udg_DamageEventAttackT by index
damagetype damageType //stores udg_DamageEventDamageT by index
weapontype weaponType //stores udg_DamageEventWeaponT by index
integer userType //stores udg_DamageEventType by index
readonly integer eFilter //replaces the previous eventFilter variable
readonly boolean isAttack //stores udg_IsDamageAttack by index
readonly boolean isCode //stores udg_IsDamageCode by index
readonly boolean isMelee //stores udg_IsDamageMelee by index
readonly boolean isRanged //stores udg_IsDamageRanged by index
readonly boolean isSpell //stores udg_IsDamageSpell by index
real armorPierced //stores udg_DamageEventArmorPierced by index
integer armorType //stores udg_DamageEventArmorT by index
integer defenseType //stores udg_DamageEventDefenseT by index
static boolean operator enabled
- Set to false to disable the damage event triggers/false to reverse that
static method apply takes unit src, unit tgt, real amt, boolean a, boolean r, attacktype at, damagetype dt, weapontype wt returns Damage
- Same arguments as "UnitDamageTarget" but has the benefit of being performance-friendly during recursive events.
- Will automatically cause the damage to be registered as Code damage.
static method applySpell takes unit src, unit tgt, real amt, damagetype dt returns Damage
- A simplified version of the above function that autofills in the booleans, attack type and weapon type.
static method applyAttack takes unit src, unit tgt, real amt, boolean ranged, attacktype at, weapontype wt returns Damage
- A different variation of the above which autofills the "attack" boolean and sets the damagetype to DAMAGE_TYPE_NORMAL.
struct DamageTrigger extends array
method operator filter= takes integer filter returns nothing
// Apply primary filters such as DamageEngine_FILTER_MELEE/RANGED/SPELL which are based off of limitop handles to enable easier access for GUI folks
// Full filter list:
- global integer DamageEngine_FILTER_ATTACK
- global integer DamageEngine_FILTER_MELEE
- global integer DamageEngine_FILTER_OTHER
- global integer DamageEngine_FILTER_RANGED
- global integer DamageEngine_FILTER_SPELL
- global integer DamageEngine_FILTER_CODE
boolean configured //set to True after configuring any filters listed below.
method configure takes nothing returns nothing
// Apply custom filters after setting any desired udg_DamageFilter variables (for GUI).
// Alternatively, vJass users can set these instead. Just be mindful to set the variable
// "configured" to true after settings these.
unit source
unit target
integer sourceType
integer targetType
integer sourceBuff
integer targetBuff
real damageMin
integer attackType
integer damageType
integer userType
//The string in the aruments below requires the following API:
// "" for standard damage event
// "Modifier(or Mod if you prefer)/After/Lethal/AOE" for the others
static method getIndex takes trigger t, string eventName, real value returns integer
static method registerTrigger takes trigger whichTrig, string var, real weight returns nothing
static method unregister takes trigger t, string eventName, real value, boolean reset returns boolean
static method operator [] takes code c returns trigger
// Converts a code argument to a trigger, while checking if the same code had already been registered before.
//The accepted strings here use the same criteria as DamageTrigger.getIndex/registerTrigger/unregister
function TriggerRegisterDamageEngineEx takes trigger whichTrig, string eventName, real value, integer f returns nothing
function TriggerRegisterDamageEngine takes trigger whichTrig, string eventName, real value returns nothing
function RegisterDamageEngineEx takes code c, string eventName, real value, integer f returns nothing
function RegisterDamageEngine takes code c, string eventName, real value returns nothing
//! endnovjass
//===========================================================================
library DamageEngine
globals
private constant boolean USE_GUI = true //If you don't use any of the GUI events, set to false to slightly improve performance
private constant boolean USE_SCALING = USE_GUI //If you don't need or want to use DamageScalingUser/WC3 then set this to false
private constant boolean USE_EXTRA = true //If you don't use DamageEventLevel or AOEDamageEvent, set this to false
private constant boolean USE_ARMOR_MOD = true //If you do not modify nor detect armor/defense, set this to false
private constant boolean USE_MELEE_RANGE= true //If you do not detect melee nor ranged damage, set this to false
private constant boolean USE_LETHAL = true //If you do not use LethalDamageEvent nor negative damage (explosive) types, set this to false
private constant integer LIMBO = 16 //When manually-enabled recursion is enabled via DamageEngine_recurion, the engine will never go deeper than LIMBO.
public constant integer TYPE_CODE = 1 //Must be the same as udg_DamageTypeCode, or 0 if you prefer to disable the automatic flag.
public constant integer TYPE_PURE = 2 //Must be the same as udg_DamageTypePure
private constant real DEATH_VAL = 0.405 //In case Blizz ever changes this, it'll be a quick fix here.
private timer alarm = CreateTimer()
private boolean alarmSet = false
//Values to track the original pre-spirit Link/defensive damage values
private Damage lastInstance = 0
private boolean canKick = true
private boolean totem = false
private boolean array attacksImmune
private boolean array damagesImmune
//Made global in order to use enable/disable behavior.
private trigger t1 = CreateTrigger()
private trigger t2 = CreateTrigger()
private trigger t3 = CreateTrigger() //Catches, stores recursive events
//These variables coincide with Blizzard's "limitop" type definitions so as to enable users (GUI in particular) with some nice performance perks.
public constant integer FILTER_ATTACK = 0 //LESS_THAN
public constant integer FILTER_MELEE = 1 //LESS_THAN_OR_EQUAL
public constant integer FILTER_OTHER = 2 //EQUAL
public constant integer FILTER_RANGED = 3 //GREATER_THAN_OR_EQUAL
public constant integer FILTER_SPELL = 4 //GREATER_THAN
public constant integer FILTER_CODE = 5 //NOT_EQUAL
public constant integer FILTER_MAX = 6
private integer eventFilter = FILTER_OTHER
public boolean inception = false //When true, it allows your trigger to potentially go recursive up to LIMBO. However it must be set per-trigger throughout the game and not only once per trigger during map initialization.
private boolean dreaming = false
private integer sleepLevel = 0
private group proclusGlobal = CreateGroup() //track sources of recursion
private group fischerMorrow = CreateGroup() //track targets of recursion
private boolean kicking = false
private boolean eventsRun = false
private keyword run
private keyword trigFrozen
private keyword levelsDeep
private keyword inceptionTrig
private boolean hasLethal = false
endglobals
native UnitAlive takes unit u returns boolean
//GUI Vars:
/*
Retained from 3.8 and prior:
----------------------------
unit udg_DamageEventSource
unit udg_DamageEventTarget
unit udg_EnhancedDamageTarget
group udg_DamageEventAOEGroup
integer udg_DamageEventAOE
integer udg_DamageEventLevel
real udg_DamageModifierEvent
real udg_DamageEvent
real udg_AfterDamageEvent
real udg_DamageEventAmount
real udg_DamageEventPrevAmt
real udg_AOEDamageEvent
boolean udg_DamageEventOverride
boolean udg_NextDamageType
boolean udg_DamageEventType
boolean udg_IsDamageSpell
//Added in 5.0:
boolean udg_IsDamageMelee
boolean udg_IsDamageRanged
unit udg_AOEDamageSource
real udg_LethalDamageEvent
real udg_LethalDamageHP
real udg_DamageScalingWC3
integer udg_DamageEventAttackT
integer udg_DamageEventDamageT
integer udg_DamageEventWeaponT
//Added in 5.1:
boolean udg_IsDamageCode
//Added in 5.2:
integer udg_DamageEventArmorT
integer udg_DamageEventDefenseT
//Addded in 5.3:
real DamageEventArmorPierced
real udg_DamageScalingUser
//Added in 5.4.2 to allow GUI users to re-issue the exact same attack and damage type at the attacker.
attacktype array udg_CONVERTED_ATTACK_TYPE
damagetype array udg_CONVERTED_DAMAGE_TYPE
//Added after Reforged introduced the new native BlzGetDamageIsAttack
boolean udg_IsDamageAttack
//Added in 5.6 to give GUI users control over the "IsDamageAttack", "IsDamageRanged" and "DamageEventWeaponT" field
boolean udg_NextDamageIsAttack //The first boolean value in the UnitDamageTarget native
boolean udg_NextDamageIsMelee //Flag the damage classification as melee
boolean udg_NextDamageIsRanged //The second boolean value in the UnitDamageTarget native
integer udg_NextDamageWeaponT //Allows control over damage sound effect
//Added in 5.7 to enable efficient, built-in filtering (see the below "checkConfiguration" method - I recommend commenting-out anything you don't need in your map)
integer udg_DamageFilterAttackT
integer udg_DamageFilterDamageT //filter for a specific attack/damage type
unit udg_DamageFilterSource
unit udg_DamageFilterTarget //filter for a specific source/target
integer udg_DamageFilterSourceT
integer udg_DamageFilterTargetT //unit type of source/target
integer udg_DamageFilterType //which DamageEventType was used
integer udg_DamageFilterSourceB
integer udg_DamageFilterTargetB //if source/target has a buff
real udg_DamageFilterMinAmount //only allow a minimum damage threshold
*/
struct DamageTrigger extends array
//Map-makers should comment-out any booleans they will never need to check for.
method checkConfiguration takes nothing returns boolean
if this.userType != 0 and udg_DamageEventType != this.userType then
elseif this.source != null and this.source != udg_DamageEventSource then
elseif this.target != null and this.target != udg_DamageEventTarget then
elseif this.attackType >= 0 and this.attackType != udg_DamageEventAttackT then
elseif this.damageType >= 0 and this.damageType != udg_DamageEventDamageT then
elseif this.sourceType != 0 and GetUnitTypeId(udg_DamageEventSource) != this.sourceType then
elseif this.targetType != 0 and GetUnitTypeId(udg_DamageEventTarget) != this.targetType then
elseif this.sourceBuff != 0 and GetUnitAbilityLevel(udg_DamageEventSource, this.sourceBuff) == 0 then
elseif this.targetBuff != 0 and GetUnitAbilityLevel(udg_DamageEventTarget, this.targetBuff) == 0 then
elseif udg_DamageEventAmount > this.damageMin then
return true
endif
return false
endmethod
//The below variables are constant
readonly static thistype MOD = 1
readonly static thistype SHIELD = 4
readonly static thistype DAMAGE = 5
readonly static thistype ZERO = 6
readonly static thistype AFTER = 7
readonly static thistype LETHAL = 8
readonly static thistype AOE = 9
private static integer count = 9
static thistype lastRegistered = 0
private static thistype array trigIndexStack
static thistype eventIndex = 0
static boolean array filters
readonly string eventStr
readonly real weight
boolean configured
boolean usingGUI
//The below variables are private
private thistype next
private trigger rootTrig
boolean trigFrozen //Whether the trigger is currently disabled due to recursion
integer levelsDeep //How deep the user recursion currently is.
boolean inceptionTrig //Added in 5.4.2 to simplify the inception variable for very complex DamageEvent trigger.
unit source
unit target
integer sourceType
integer targetType
integer sourceBuff
integer targetBuff
real damageMin
integer attackType
integer damageType
integer userType
method configure takes nothing returns nothing
set this.attackType = udg_DamageFilterAttackT
set this.damageType = udg_DamageFilterDamageT
set this.source = udg_DamageFilterSource
set this.target = udg_DamageFilterTarget
set this.sourceType = udg_DamageFilterSourceT
set this.targetType = udg_DamageFilterTargetT
set this.sourceBuff = udg_DamageFilterSourceB
set this.targetBuff = udg_DamageFilterTargetB
set this.userType = udg_DamageFilterType
set this.damageMin = udg_DamageFilterMinAmount
set udg_DamageFilterAttackT =-1
set udg_DamageFilterDamageT =-1
set udg_DamageFilterSource = null
set udg_DamageFilterTarget = null
set udg_DamageFilterSourceT = 0
set udg_DamageFilterTargetT = 0
set udg_DamageFilterType = 0
set udg_DamageFilterSourceB = 0
set udg_DamageFilterTargetB = 0
set udg_DamageFilterMinAmount=0.00
set this.configured = true
endmethod
static method setGUIFromStruct takes boolean full returns nothing
set udg_DamageEventAmount = Damage.index.damage
set udg_DamageEventAttackT = GetHandleId(Damage.index.attackType)
set udg_DamageEventDamageT = GetHandleId(Damage.index.damageType)
set udg_DamageEventWeaponT = GetHandleId(Damage.index.weaponType)
set udg_DamageEventType = Damage.index.userType
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_DamageEventArmorPierced = Damage.index.armorPierced
set udg_DamageEventArmorT = Damage.index.armorType
set udg_DamageEventDefenseT = Damage.index.defenseType
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if full then
set udg_DamageEventSource = Damage.index.sourceUnit
set udg_DamageEventTarget = Damage.index.targetUnit
set udg_DamageEventPrevAmt = Damage.index.prevAmt
set udg_IsDamageAttack = Damage.index.isAttack
set udg_IsDamageCode = Damage.index.isCode
set udg_IsDamageSpell = Damage.index.isSpell
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_IsDamageMelee = Damage.index.isMelee
set udg_IsDamageRanged = Damage.index.isRanged
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endif
endmethod
static method setStructFromGUI takes nothing returns nothing
set Damage.index.damage = udg_DamageEventAmount
set Damage.index.attackType = ConvertAttackType(udg_DamageEventAttackT)
set Damage.index.damageType = ConvertDamageType(udg_DamageEventDamageT)
set Damage.index.weaponType = ConvertWeaponType(udg_DamageEventWeaponT)
set Damage.index.userType = udg_DamageEventType
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set Damage.index.armorPierced = udg_DamageEventArmorPierced
set Damage.index.armorType = udg_DamageEventArmorT
set Damage.index.defenseType = udg_DamageEventDefenseT
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endmethod
static method getVerboseStr takes string eventName returns string
if eventName == "Modifier" or eventName == "Mod" then
return "udg_DamageModifierEvent"
endif
return "udg_" + eventName + "DamageEvent"
endmethod
private static method getStrIndex takes string var, real lbs returns thistype
local integer root = R2I(lbs)
if var == "udg_DamageModifierEvent" then
if root >= 4 then
set root= SHIELD //4.00 or higher
else
set root= MOD //Less than 4.00
endif
elseif var == "udg_DamageEvent" then
if root == 2 or root == 0 then
set root= ZERO
else
set root= DAMAGE //Above 0.00 but less than 2.00, generally would just be 1.00
endif
elseif var == "udg_AfterDamageEvent" then
set root = AFTER
elseif var == "udg_LethalDamageEvent" then
set root = LETHAL
elseif var == "udg_AOEDamageEvent" then
set root = AOE
else
set root = 0
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_GDD()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_PDD()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_05()
endif
return root
endmethod
private method toggleAllFilters takes boolean flag returns nothing
set filters[this + FILTER_ATTACK] = flag
set filters[this + FILTER_MELEE] = flag
set filters[this + FILTER_OTHER] = flag
set filters[this + FILTER_RANGED] = flag
set filters[this + FILTER_SPELL] = flag
set filters[this + FILTER_CODE] = flag
endmethod
method operator filter= takes integer f returns nothing
set this = this*FILTER_MAX
if f == FILTER_OTHER then
call this.toggleAllFilters(true)
else
if f == FILTER_ATTACK then
set filters[this + FILTER_ATTACK] = true
set filters[this + FILTER_MELEE] = true
set filters[this + FILTER_RANGED] = true
else
set filters[this + f] = true
endif
endif
endmethod
static method registerVerbose takes trigger whichTrig, string var, real lbs, boolean GUI, integer filt returns thistype
local thistype index= getStrIndex(var, lbs)
local thistype i = 0
local thistype id = 0
if index == 0 then
return 0
elseif lastRegistered.rootTrig == whichTrig and lastRegistered.usingGUI then
set filters[lastRegistered*FILTER_MAX + filt] = true //allows GUI to register multiple different types of Damage filters to the same trigger
return 0
endif
if not hasLethal and index == LETHAL then
set hasLethal = true
endif
if trigIndexStack[0] == 0 then
set count = count + 1 //List runs from index 10 and up
set id = count
else
set id = trigIndexStack[0]
set trigIndexStack[0] = trigIndexStack[id]
endif
set lastRegistered = id
set id.filter = filt
set id.rootTrig = whichTrig
set id.usingGUI = GUI
set id.weight = lbs
set id.eventStr = var
//Next 2 lines added to fix a bug when using manual vJass configuration,
//discovered and solved by lolreported
set id.attackType = -1
set id.damageType = -1
loop
set i = index.next
exitwhen i == 0 or lbs < i.weight
set index = i
endloop
set index.next = id
set id.next = i
//call BJDebugMsg("Registered " + I2S(id) + " to " + I2S(index) + " and before " + I2S(i))
return lastRegistered
endmethod
static method registerTrigger takes trigger t, string var, real lbs returns thistype
return registerVerbose(t, DamageTrigger.getVerboseStr(var), lbs, false, FILTER_OTHER)
endmethod
private static thistype prev = 0
static method getIndex takes trigger t, string eventName, real lbs returns thistype
local thistype index = getStrIndex(getVerboseStr(eventName), lbs)
loop
set prev = index
set index = index.next
exitwhen index == 0 or index.rootTrig == t
endloop
return index
endmethod
static method unregister takes trigger t, string eventName, real lbs, boolean reset returns boolean
local thistype index = getIndex(t, eventName, lbs)
if index == 0 then
return false
endif
set prev.next = index.next
set trigIndexStack[index] = trigIndexStack[0]
set trigIndexStack[0] = index
if reset then
call index.configure()
set index.configured = false
set index = index*FILTER_MAX
call index.toggleAllFilters(false)
endif
return true
endmethod
method run takes nothing returns nothing
local integer cat = this
local Damage d = Damage.index
static if USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
local boolean structUnset = false
local boolean guiUnset = false
local boolean mod = cat <= DAMAGE
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if dreaming then
return
endif
set dreaming = true
call DisableTrigger(t1)
call DisableTrigger(t2)
call EnableTrigger(t3)
//call BJDebugMsg("Start of event running")
loop
set this = this.next
exitwhen this == 0
exitwhen cat == MOD and (udg_DamageEventOverride or udg_DamageEventType == TYPE_PURE)
exitwhen cat == SHIELD and udg_DamageEventAmount <= 0.00
static if USE_LETHAL then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
exitwhen cat == LETHAL and udg_LethalDamageHP > DEATH_VAL
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set eventIndex = this
if not this.trigFrozen and filters[this*FILTER_MAX + d.eFilter] and IsTriggerEnabled(this.rootTrig) and (not this.configured or this.checkConfiguration()) then
static if USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if mod then
if this.usingGUI then
if guiUnset then
set guiUnset = false
call setGUIFromStruct(false)
endif
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_PDD()
elseif structUnset then
set structUnset = false
call setStructFromGUI()
endif
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_05()
//JASS users who do not use actions can modify the below block to just evaluate.
//It should not make any perceptable difference in terms of performance.
if TriggerEvaluate(this.rootTrig) then
call TriggerExecute(this.rootTrig)
endif
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_05()
static if USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if mod then
if this.usingGUI then
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_PDD()
if cat != MOD then
set d.damage = udg_DamageEventAmount
else
set structUnset = true
endif
elseif cat != MOD then
set udg_DamageEventAmount = d.damage
else
set guiUnset = true
endif
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endif
endloop
static if USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if structUnset then
call setStructFromGUI()
endif
if guiUnset then
call setGUIFromStruct(false)
endif
else// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call setGUIFromStruct(false)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
//call BJDebugMsg("End of event running")
call DisableTrigger(t3)
call EnableTrigger(t1)
call EnableTrigger(t2)
set dreaming = false
endmethod
static trigger array autoTriggers
static boolexpr array autoFuncs
static integer autoN = 0
static method operator [] takes code c returns trigger
local integer i = 0
local boolexpr b = Filter(c)
loop
if i == autoN then
set autoTriggers[i] = CreateTrigger()
set autoFuncs[i] = b
call TriggerAddCondition(autoTriggers[i], b)
exitwhen true
endif
set i = i + 1
exitwhen b == autoFuncs[i]
endloop
return autoTriggers[i]
endmethod
endstruct
//! runtextmacro optional DAMAGE_EVENT_USER_STRUCT_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_USER_STRUCT_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_USER_STRUCT_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_USER_STRUCT_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_USER_STRUCT_PLUGIN_05()
struct Damage extends array
readonly unit sourceUnit //stores udg_DamageEventSource
readonly unit targetUnit //stores udg_DamageEventTarget
real damage //stores udg_DamageEventAmount
readonly real prevAmt //stores udg_DamageEventPrevAmt
attacktype attackType //stores udg_DamageEventAttackT
damagetype damageType //stores udg_DamageEventDamageT
weapontype weaponType //stores udg_DamageEventWeaponT
integer userType //stores udg_DamageEventType
readonly boolean isAttack //stores udg_IsDamageAttack
readonly boolean isCode //stores udg_IsDamageCode
readonly boolean isSpell //stores udg_IsDamageSpell
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
readonly boolean isMelee //stores udg_IsDamageMelee
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
readonly boolean isRanged //stores udg_IsDamageRanged
readonly integer eFilter //stores the previous eventFilter variable
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
real armorPierced //stores udg_DamageEventArmorPierced
integer armorType //stores udg_DamageEventArmorT
integer defenseType //stores udg_DamageEventDefenseT
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
readonly static Damage index = 0
private static Damage damageStack = 0
private static Damage prepped = 0
private static integer count = 0 //The number of currently-running queued or sequential damage instances
private Damage stackRef
private DamageTrigger recursiveTrig
private integer prevArmorT
private integer prevDefenseT
static method operator source takes nothing returns unit
return udg_DamageEventSource
endmethod
static method operator target takes nothing returns unit
return udg_DamageEventTarget
endmethod
static method operator amount takes nothing returns real
return Damage.index.damage
endmethod
static method operator amount= takes real r returns nothing
set Damage.index.damage = r
endmethod
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
private method setArmor takes boolean reset returns nothing
local real pierce
local integer at
local integer dt
if reset then
set pierce = udg_DamageEventArmorPierced
set at = Damage.index.prevArmorT
set dt = Damage.index.prevDefenseT
set udg_DamageEventArmorPierced = 0.00
set this.armorPierced = 0.00
else
set pierce = -udg_DamageEventArmorPierced
set at = udg_DamageEventArmorT
set dt = udg_DamageEventDefenseT
endif
if pierce != 0.00 then
call BlzSetUnitArmor(udg_DamageEventTarget, BlzGetUnitArmor(udg_DamageEventTarget) + pierce)
endif
if Damage.index.prevArmorT != udg_DamageEventArmorT then
call BlzSetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_ARMOR_TYPE, at)
endif
if Damage.index.prevDefenseT != udg_DamageEventDefenseT then
call BlzSetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_DEFENSE_TYPE, dt)
endif
endmethod
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
static if USE_EXTRA then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
private static method onAOEEnd takes nothing returns nothing
if udg_DamageEventAOE > 1 then
call DamageTrigger.AOE.run()
endif
set udg_DamageEventAOE = 0
set udg_DamageEventLevel = 0
set udg_EnhancedDamageTarget = null
set udg_AOEDamageSource = null
call GroupClear(udg_DamageEventAOEGroup)
endmethod
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
private static method afterDamage takes nothing returns nothing
if udg_DamageEventPrevAmt != 0.00 and udg_DamageEventDamageT != 0 then
call DamageTrigger.AFTER.run()
set udg_DamageEventDamageT = 0
set udg_DamageEventPrevAmt = 0.00
endif
endmethod
private method doPreEvents takes boolean natural returns boolean
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set this.armorType = BlzGetUnitIntegerField(this.targetUnit, UNIT_IF_ARMOR_TYPE)
set this.defenseType = BlzGetUnitIntegerField(this.targetUnit, UNIT_IF_DEFENSE_TYPE)
set this.prevArmorT = this.armorType
set this.prevDefenseT = this.defenseType
set this.armorPierced = 0.00
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set Damage.index = this
call DamageTrigger.setGUIFromStruct(true)
call GroupAddUnit(proclusGlobal, udg_DamageEventSource)
call GroupAddUnit(fischerMorrow, udg_DamageEventTarget)
//! runtextmacro optional DAMAGE_EVENT_PRE_VARS_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_PRE_VARS_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_PRE_VARS_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_PRE_VARS_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_PRE_VARS_PLUGIN_05()
if udg_DamageEventAmount != 0.00 then
set udg_DamageEventOverride = udg_DamageEventDamageT == 0
call DamageTrigger.MOD.run()
static if not USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call DamageTrigger.setGUIFromStruct(false)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if natural then
call BlzSetEventAttackType(this.attackType)
call BlzSetEventDamageType(this.damageType)
call BlzSetEventWeaponType(this.weaponType)
call BlzSetEventDamage(udg_DamageEventAmount)
endif
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call this.setArmor(false)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
return false
endif
return true
endmethod
private static method unfreeze takes nothing returns nothing
local Damage i = damageStack
loop
exitwhen i == 0
set i = i - 1
set i.stackRef.recursiveTrig.trigFrozen = false
set i.stackRef.recursiveTrig.levelsDeep = 0
endloop
call EnableTrigger(t1)
call EnableTrigger(t2)
set kicking = false
set damageStack = 0
set prepped = 0
set dreaming = false
set sleepLevel = 0
call GroupClear(proclusGlobal)
call GroupClear(fischerMorrow)
//call BJDebugMsg("Cleared up the groups")
endmethod
static method finish takes nothing returns nothing
local Damage i = 0
local integer exit
if eventsRun then
set eventsRun = false
call afterDamage()
endif
if canKick and not kicking then
if damageStack != 0 then
set kicking = true
loop
set sleepLevel = sleepLevel + 1
set exit = damageStack
loop
set prepped = i.stackRef
if UnitAlive(prepped.targetUnit) then //Added just in case dead units had issues.
call prepped.doPreEvents(false) //don't evaluate the pre-event
if prepped.damage > 0.00 then
call DisableTrigger(t1) //Force only the after armor event to run.
call EnableTrigger(t2) //in case the user forgot to re-enable this
set totem = true
call UnitDamageTarget(prepped.sourceUnit, prepped.targetUnit, prepped.damage, prepped.isAttack, prepped.isRanged, prepped.attackType, prepped.damageType, prepped.weaponType)
else
//No new events run at all in this case
if udg_DamageEventDamageT != 0 then
call DamageTrigger.DAMAGE.run()
endif
if prepped.damage < 0.00 then
//No need for BlzSetEventDamage here
call SetWidgetLife(prepped.targetUnit, GetWidgetLife(prepped.targetUnit) - prepped.damage)
endif
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call prepped.setArmor(true)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endif
call afterDamage()
endif
set i = i + 1
exitwhen i == exit
endloop
exitwhen i == damageStack
endloop
endif
call unfreeze()
endif
endmethod
private static method failsafeClear takes nothing returns nothing
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call Damage.index.setArmor(true)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set canKick = true
set kicking = false
set totem = false
if udg_DamageEventDamageT != 0 then
call DamageTrigger.DAMAGE.run()
set eventsRun = true
endif
call finish()
endmethod
static method operator enabled= takes boolean b returns nothing
if b then
if dreaming then
call EnableTrigger(t3)
else
call EnableTrigger(t1)
call EnableTrigger(t2)
endif
else
if dreaming then
call DisableTrigger(t3)
else
call DisableTrigger(t1)
call DisableTrigger(t2)
endif
endif
endmethod
static method operator enabled takes nothing returns boolean
return IsTriggerEnabled(t1)
endmethod
private static boolean arisen = false
private static method getOutOfBed takes nothing returns nothing
if totem then
call failsafeClear() //WarCraft 3 didn't run the DAMAGED event despite running the DAMAGING event.
else
set canKick = true
set kicking = false
call finish()
endif
static if USE_EXTRA then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call onAOEEnd()
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set arisen = true
endmethod
private static method wakeUp takes nothing returns nothing
set dreaming = false
set Damage.enabled = true
call ForForce(bj_FORCE_PLAYER[0], function thistype.getOutOfBed) //Moved to a new thread in case of a thread crash
if not arisen then
//call BJDebugMsg("DamageEngine issue: thread crashed!")
call unfreeze()
else
set arisen = false
endif
set Damage.count = 0
set Damage.index = 0
set alarmSet = false
//call BJDebugMsg("Timer wrapped up")
endmethod
private method addRecursive takes nothing returns nothing
if this.damage != 0.00 then
set this.recursiveTrig = DamageTrigger.eventIndex
if not this.isCode then
set this.isCode = true
set this.userType = TYPE_CODE
endif
set inception = inception or DamageTrigger.eventIndex.inceptionTrig
if kicking and IsUnitInGroup(this.sourceUnit, proclusGlobal) and IsUnitInGroup(this.targetUnit, fischerMorrow) then
if not inception then
set DamageTrigger.eventIndex.trigFrozen = true
elseif not DamageTrigger.eventIndex.trigFrozen then
set DamageTrigger.eventIndex.inceptionTrig = true
if DamageTrigger.eventIndex.levelsDeep < sleepLevel then
set DamageTrigger.eventIndex.levelsDeep = DamageTrigger.eventIndex.levelsDeep + 1
if DamageTrigger.eventIndex.levelsDeep >= LIMBO then
set DamageTrigger.eventIndex.trigFrozen = true
endif
endif
endif
endif
set damageStack.stackRef = this
set damageStack = damageStack + 1
//call BJDebugMsg("damageStack: " + I2S(damageStack) + " levelsDeep: " + I2S(DamageTrigger.eventIndex.levelsDeep) + " sleepLevel: " + I2S(sleepLevel))
endif
set inception = false
endmethod
private static method clearNexts takes nothing returns nothing
set udg_NextDamageIsAttack = false
set udg_NextDamageType = 0
set udg_NextDamageWeaponT = 0
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_NextDamageIsMelee = false
set udg_NextDamageIsRanged = false
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endmethod
static method create takes unit src, unit tgt, real amt, boolean a, attacktype at, damagetype dt, weapontype wt returns Damage
local Damage d = Damage.count + 1
set Damage.count = d
set d.sourceUnit = src
set d.targetUnit = tgt
set d.damage = amt
set d.prevAmt = amt
set d.attackType = at
set d.damageType = dt
set d.weaponType = wt
set d.isAttack = udg_NextDamageIsAttack or a
set d.isSpell = d.attackType == null and not d.isAttack
return d
endmethod
private static method createFromEvent takes nothing returns Damage
local Damage d = create(GetEventDamageSource(), GetTriggerUnit(), GetEventDamage(), BlzGetEventIsAttack(), BlzGetEventAttackType(), BlzGetEventDamageType(), BlzGetEventWeaponType())
set d.isCode = udg_NextDamageType != 0 or udg_NextDamageIsAttack or udg_NextDamageIsRanged or udg_NextDamageIsMelee or d.damageType == DAMAGE_TYPE_MIND or udg_NextDamageWeaponT != 0 or (d.damage != 0.00 and d.damageType == DAMAGE_TYPE_UNKNOWN)
if d.isCode then
if udg_NextDamageType != 0 then
set d.userType = udg_NextDamageType
else
set d.userType = TYPE_CODE
endif
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set d.isMelee = udg_NextDamageIsMelee
set d.isRanged = udg_NextDamageIsRanged
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set d.eFilter = FILTER_CODE
if udg_NextDamageWeaponT != 0 then
set d.weaponType = ConvertWeaponType(udg_NextDamageWeaponT)
set udg_NextDamageWeaponT = 0
endif
else
set d.userType = 0
if d.damageType == DAMAGE_TYPE_NORMAL and d.isAttack then
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set d.isMelee = IsUnitType(d.sourceUnit, UNIT_TYPE_MELEE_ATTACKER)
set d.isRanged = IsUnitType(d.sourceUnit, UNIT_TYPE_RANGED_ATTACKER)
if d.isMelee and d.isRanged then
set d.isMelee = d.weaponType != null // Melee units play a sound when damaging
set d.isRanged = not d.isMelee // In the case where a unit is both ranged and melee, the ranged attack plays no sound.
endif
if d.isMelee then
set d.eFilter = FILTER_MELEE
elseif d.isRanged then
set d.eFilter = FILTER_RANGED
else
set d.eFilter = FILTER_ATTACK
endif
else
set d.eFilter = FILTER_ATTACK
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
else
if d.isSpell then
set d.eFilter = FILTER_SPELL
else
set d.eFilter = FILTER_OTHER
endif
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set d.isMelee = false
set d.isRanged = false
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endif
endif
call clearNexts()
return d
endmethod
private static method onRecursion takes nothing returns boolean //New in 5.7
local Damage d = Damage.createFromEvent()
call d.addRecursive()
call BlzSetEventDamage(0.00)
return false
endmethod
private static method onDamaging takes nothing returns boolean
local Damage d = Damage.createFromEvent()
//call BJDebugMsg("Pre-damage event running for " + GetUnitName(GetTriggerUnit()))
if alarmSet then
if totem then //WarCraft 3 didn't run the DAMAGED event despite running the DAMAGING event.
if d.damageType == DAMAGE_TYPE_SPIRIT_LINK or d.damageType == DAMAGE_TYPE_DEFENSIVE or d.damageType == DAMAGE_TYPE_PLANT then
set totem = false
set lastInstance= Damage.index
set canKick = false
else
call failsafeClear() //Not an overlapping event - just wrap it up
endif
else
call finish() //wrap up any previous damage index
endif
static if USE_EXTRA then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if d.sourceUnit != udg_AOEDamageSource then
call onAOEEnd()
set udg_AOEDamageSource = d.sourceUnit
elseif d.targetUnit == udg_EnhancedDamageTarget then
set udg_DamageEventLevel= udg_DamageEventLevel + 1
elseif not IsUnitInGroup(d.targetUnit, udg_DamageEventAOEGroup) then
set udg_DamageEventAOE = udg_DamageEventAOE + 1
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
else
call TimerStart(alarm, 0.00, false, function Damage.wakeUp)
set alarmSet = true
static if USE_EXTRA then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_AOEDamageSource = d.sourceUnit
set udg_EnhancedDamageTarget= d.targetUnit
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endif
static if USE_EXTRA then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call GroupAddUnit(udg_DamageEventAOEGroup, d.targetUnit)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if d.doPreEvents(true) then
call DamageTrigger.ZERO.run()
set canKick = true
call finish()
endif
set totem = lastInstance == 0 or attacksImmune[udg_DamageEventAttackT] or damagesImmune[udg_DamageEventDamageT] or not IsUnitType(udg_DamageEventTarget, UNIT_TYPE_MAGIC_IMMUNE)
return false
endmethod
private static method onDamaged takes nothing returns boolean
local real r = GetEventDamage()
local Damage d = Damage.index
//call BJDebugMsg("Second damage event running for " + GetUnitName(GetTriggerUnit()))
if prepped > 0 then
set prepped = 0
elseif dreaming or d.prevAmt == 0.00 then
return false
elseif totem then
set totem = false
else
//This should only happen for stuff like Spirit Link or Thorns Aura/Carapace
call afterDamage()
set Damage.index = lastInstance
set lastInstance = 0
set d = Damage.index
set canKick = true
call DamageTrigger.setGUIFromStruct(true)
endif
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call d.setArmor(true)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
static if USE_SCALING then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if udg_DamageEventAmount != 0.00 and r != 0.00 then
set udg_DamageScalingWC3 = r / udg_DamageEventAmount
elseif udg_DamageEventAmount > 0.00 then
set udg_DamageScalingWC3 = 0.00
else
set udg_DamageScalingWC3 = 1.00
if udg_DamageEventPrevAmt == 0.00 then
set udg_DamageScalingUser = 0.00
else
set udg_DamageScalingUser = udg_DamageEventAmount/udg_DamageEventPrevAmt
endif
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_DamageEventAmount = r
set d.damage = r
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_GDD()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_PDD()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_05()
if udg_DamageEventAmount > 0.00 then
call DamageTrigger.SHIELD.run()
static if not USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_DamageEventAmount = d.damage
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
static if USE_LETHAL then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if hasLethal or udg_DamageEventType < 0 then
set udg_LethalDamageHP = GetWidgetLife(udg_DamageEventTarget) - udg_DamageEventAmount
if udg_LethalDamageHP <= DEATH_VAL then
if hasLethal then
call DamageTrigger.LETHAL.run()
set udg_DamageEventAmount = GetWidgetLife(udg_DamageEventTarget) - udg_LethalDamageHP
set d.damage = udg_DamageEventAmount
endif
if udg_DamageEventType < 0 and udg_LethalDamageHP <= DEATH_VAL then
call SetUnitExploded(udg_DamageEventTarget, true)
endif
endif
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
static if USE_SCALING then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if udg_DamageEventPrevAmt == 0.00 or udg_DamageScalingWC3 == 0.00 then
set udg_DamageScalingUser = 0.00
else
set udg_DamageScalingUser = udg_DamageEventAmount/udg_DamageEventPrevAmt/udg_DamageScalingWC3
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endif
if udg_DamageEventDamageT != 0 then
call DamageTrigger.DAMAGE.run()
endif
call BlzSetEventDamage(udg_DamageEventAmount)
set eventsRun = true
if udg_DamageEventAmount == 0.00 then
call finish()
endif
return false
endmethod
static method apply takes unit src, unit tgt, real amt, boolean a, boolean r, attacktype at, damagetype dt, weapontype wt returns Damage
local Damage d
if udg_NextDamageType == 0 then
set udg_NextDamageType = TYPE_CODE
endif
if dreaming then
set d = create(src, tgt, amt, a, at, dt, wt)
set d.isCode = true
set d.eFilter = FILTER_CODE
set d.userType = udg_NextDamageType
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if not d.isSpell then
set d.isRanged = udg_NextDamageIsRanged or r
set d.isMelee = not d.isRanged
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call d.addRecursive()
else
call UnitDamageTarget(src, tgt, amt, a, r, at, dt, wt)
set d = Damage.index
call finish()
endif
call clearNexts()
return d
endmethod
static method applySpell takes unit src, unit tgt, real amt, damagetype dt returns Damage
return apply(src, tgt, amt, false, false, null, dt, null)
endmethod
static method applyAttack takes unit src, unit tgt, real amt, boolean ranged, attacktype at, weapontype wt returns Damage
return apply(src, tgt, amt, true, ranged, at, DAMAGE_TYPE_NORMAL, wt)
endmethod
//===========================================================================
private static method onInit takes nothing returns nothing
call TriggerRegisterAnyUnitEventBJ(t1, EVENT_PLAYER_UNIT_DAMAGING)
// added because neutral weren't detected
call TriggerRegisterPlayerUnitEvent(t1, Player(24),EVENT_PLAYER_UNIT_DAMAGING,null)
call TriggerRegisterPlayerUnitEvent(t1, Player(25),EVENT_PLAYER_UNIT_DAMAGING,null)
call TriggerRegisterPlayerUnitEvent(t1, Player(26),EVENT_PLAYER_UNIT_DAMAGING,null)
call TriggerRegisterPlayerUnitEvent(t1, Player(27),EVENT_PLAYER_UNIT_DAMAGING,null)
//
call TriggerAddCondition(t1, Filter(function Damage.onDamaging))
call TriggerRegisterAnyUnitEventBJ(t2, EVENT_PLAYER_UNIT_DAMAGED)
// added because neutral weren't detected
call TriggerRegisterPlayerUnitEvent(t2, Player(24),EVENT_PLAYER_UNIT_DAMAGED,null)
call TriggerRegisterPlayerUnitEvent(t2, Player(25),EVENT_PLAYER_UNIT_DAMAGED,null)
call TriggerRegisterPlayerUnitEvent(t2, Player(26),EVENT_PLAYER_UNIT_DAMAGED,null)
call TriggerRegisterPlayerUnitEvent(t2, Player(27),EVENT_PLAYER_UNIT_DAMAGED,null)
//
call TriggerAddCondition(t2, Filter(function Damage.onDamaged))
//For recursion
call TriggerRegisterAnyUnitEventBJ(t3, EVENT_PLAYER_UNIT_DAMAGING)
// added because neutral weren't detected
call TriggerRegisterPlayerUnitEvent(t3, Player(24),EVENT_PLAYER_UNIT_DAMAGING,null)
call TriggerRegisterPlayerUnitEvent(t3, Player(25),EVENT_PLAYER_UNIT_DAMAGING,null)
call TriggerRegisterPlayerUnitEvent(t3, Player(26),EVENT_PLAYER_UNIT_DAMAGING,null)
call TriggerRegisterPlayerUnitEvent(t3, Player(27),EVENT_PLAYER_UNIT_DAMAGING,null)
//
call TriggerAddCondition(t3, Filter(function Damage.onRecursion))
call DisableTrigger(t3)
//For preventing Thorns/Defensive glitch.
//Data gathered from https://www.hiveworkshop.com/threads/repo-in-progress-mapping-damage-types-to-their-abilities.316271/
set attacksImmune[0] = false //ATTACK_TYPE_NORMAL
set attacksImmune[1] = true //ATTACK_TYPE_MELEE
set attacksImmune[2] = true //ATTACK_TYPE_PIERCE
set attacksImmune[3] = true //ATTACK_TYPE_SIEGE
set attacksImmune[4] = false //ATTACK_TYPE_MAGIC
set attacksImmune[5] = true //ATTACK_TYPE_CHAOS
set attacksImmune[6] = true //ATTACK_TYPE_HERO
set damagesImmune[0] = true //DAMAGE_TYPE_UNKNOWN
set damagesImmune[4] = true //DAMAGE_TYPE_NORMAL
set damagesImmune[5] = true //DAMAGE_TYPE_ENHANCED
set damagesImmune[8] = false //DAMAGE_TYPE_FIRE
set damagesImmune[9] = false //DAMAGE_TYPE_COLD
set damagesImmune[10] = false //DAMAGE_TYPE_LIGHTNING
set damagesImmune[11] = true //DAMAGE_TYPE_POISON
set damagesImmune[12] = true //DAMAGE_TYPE_DISEASE
set damagesImmune[13] = false //DAMAGE_TYPE_DIVINE
set damagesImmune[14] = false //DAMAGE_TYPE_MAGIC
set damagesImmune[15] = false //DAMAGE_TYPE_SONIC
set damagesImmune[16] = true //DAMAGE_TYPE_ACID
set damagesImmune[17] = false //DAMAGE_TYPE_FORCE
set damagesImmune[18] = false //DAMAGE_TYPE_DEATH
set damagesImmune[19] = false //DAMAGE_TYPE_MIND
set damagesImmune[20] = false //DAMAGE_TYPE_PLANT
set damagesImmune[21] = false //DAMAGE_TYPE_DEFENSIVE
set damagesImmune[22] = true //DAMAGE_TYPE_DEMOLITION
set damagesImmune[23] = true //DAMAGE_TYPE_SLOW_POISON
set damagesImmune[24] = false //DAMAGE_TYPE_SPIRIT_LINK
set damagesImmune[25] = false //DAMAGE_TYPE_SHADOW_STRIKE
set damagesImmune[26] = true //DAMAGE_TYPE_UNIVERSAL
endmethod
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_DMGPKG()
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_05()
endstruct
public function DebugStr takes nothing returns nothing
local integer i = 0
loop
set udg_CONVERTED_ATTACK_TYPE[i] = ConvertAttackType(i)
exitwhen i == 6
set i = i + 1
endloop
set i = 0
loop
set udg_CONVERTED_DAMAGE_TYPE[i] = ConvertDamageType(i)
exitwhen i == 26
set i = i + 1
endloop
set udg_AttackTypeDebugStr[0] = "SPELLS" //ATTACK_TYPE_NORMAL in JASS
set udg_AttackTypeDebugStr[1] = "NORMAL" //ATTACK_TYPE_MELEE in JASS
set udg_AttackTypeDebugStr[2] = "PIERCE"
set udg_AttackTypeDebugStr[3] = "SIEGE"
set udg_AttackTypeDebugStr[4] = "MAGIC"
set udg_AttackTypeDebugStr[5] = "CHAOS"
set udg_AttackTypeDebugStr[6] = "HERO"
set udg_DamageTypeDebugStr[0] = "UNKNOWN"
set udg_DamageTypeDebugStr[4] = "NORMAL"
set udg_DamageTypeDebugStr[5] = "ENHANCED"
set udg_DamageTypeDebugStr[8] = "FIRE"
set udg_DamageTypeDebugStr[9] = "COLD"
set udg_DamageTypeDebugStr[10] = "LIGHTNING"
set udg_DamageTypeDebugStr[11] = "POISON"
set udg_DamageTypeDebugStr[12] = "DISEASE"
set udg_DamageTypeDebugStr[13] = "DIVINE"
set udg_DamageTypeDebugStr[14] = "MAGIC"
set udg_DamageTypeDebugStr[15] = "SONIC"
set udg_DamageTypeDebugStr[16] = "ACID"
set udg_DamageTypeDebugStr[17] = "FORCE"
set udg_DamageTypeDebugStr[18] = "DEATH"
set udg_DamageTypeDebugStr[19] = "MIND"
set udg_DamageTypeDebugStr[20] = "PLANT"
set udg_DamageTypeDebugStr[21] = "DEFENSIVE"
set udg_DamageTypeDebugStr[22] = "DEMOLITION"
set udg_DamageTypeDebugStr[23] = "SLOW_POISON"
set udg_DamageTypeDebugStr[24] = "SPIRIT_LINK"
set udg_DamageTypeDebugStr[25] = "SHADOW_STRIKE"
set udg_DamageTypeDebugStr[26] = "UNIVERSAL"
set udg_WeaponTypeDebugStr[0] = "NONE" //WEAPON_TYPE_WHOKNOWS in JASS
set udg_WeaponTypeDebugStr[1] = "METAL_LIGHT_CHOP"
set udg_WeaponTypeDebugStr[2] = "METAL_MEDIUM_CHOP"
set udg_WeaponTypeDebugStr[3] = "METAL_HEAVY_CHOP"
set udg_WeaponTypeDebugStr[4] = "METAL_LIGHT_SLICE"
set udg_WeaponTypeDebugStr[5] = "METAL_MEDIUM_SLICE"
set udg_WeaponTypeDebugStr[6] = "METAL_HEAVY_SLICE"
set udg_WeaponTypeDebugStr[7] = "METAL_MEDIUM_BASH"
set udg_WeaponTypeDebugStr[8] = "METAL_HEAVY_BASH"
set udg_WeaponTypeDebugStr[9] = "METAL_MEDIUM_STAB"
set udg_WeaponTypeDebugStr[10] = "METAL_HEAVY_STAB"
set udg_WeaponTypeDebugStr[11] = "WOOD_LIGHT_SLICE"
set udg_WeaponTypeDebugStr[12] = "WOOD_MEDIUM_SLICE"
set udg_WeaponTypeDebugStr[13] = "WOOD_HEAVY_SLICE"
set udg_WeaponTypeDebugStr[14] = "WOOD_LIGHT_BASH"
set udg_WeaponTypeDebugStr[15] = "WOOD_MEDIUM_BASH"
set udg_WeaponTypeDebugStr[16] = "WOOD_HEAVY_BASH"
set udg_WeaponTypeDebugStr[17] = "WOOD_LIGHT_STAB"
set udg_WeaponTypeDebugStr[18] = "WOOD_MEDIUM_STAB"
set udg_WeaponTypeDebugStr[19] = "CLAW_LIGHT_SLICE"
set udg_WeaponTypeDebugStr[20] = "CLAW_MEDIUM_SLICE"
set udg_WeaponTypeDebugStr[21] = "CLAW_HEAVY_SLICE"
set udg_WeaponTypeDebugStr[22] = "AXE_MEDIUM_CHOP"
set udg_WeaponTypeDebugStr[23] = "ROCK_HEAVY_BASH"
set udg_DefenseTypeDebugStr[0] = "LIGHT"
set udg_DefenseTypeDebugStr[1] = "MEDIUM"
set udg_DefenseTypeDebugStr[2] = "HEAVY"
set udg_DefenseTypeDebugStr[3] = "FORTIFIED"
set udg_DefenseTypeDebugStr[4] = "NORMAL" //Typically deals flat damage to all armor types
set udg_DefenseTypeDebugStr[5] = "HERO"
set udg_DefenseTypeDebugStr[6] = "DIVINE"
set udg_DefenseTypeDebugStr[7] = "UNARMORED"
set udg_ArmorTypeDebugStr[0] = "NONE" //ARMOR_TYPE_WHOKNOWS in JASS, added in 1.31
set udg_ArmorTypeDebugStr[1] = "FLESH"
set udg_ArmorTypeDebugStr[2] = "METAL"
set udg_ArmorTypeDebugStr[3] = "WOOD"
set udg_ArmorTypeDebugStr[4] = "ETHEREAL"
set udg_ArmorTypeDebugStr[5] = "STONE"
endfunction
//===========================================================================
//
// Setup of automatic events from GUI and custom ones from JASS alike
//
//===========================================================================
public function RegisterFromHook takes trigger whichTrig, string var, limitop op, real value returns nothing
call DamageTrigger.registerVerbose(whichTrig, var, value, true, GetHandleId(op))
endfunction
hook TriggerRegisterVariableEvent RegisterFromHook
function TriggerRegisterDamageEngineEx takes trigger whichTrig, string eventName, real value, integer f returns DamageTrigger
return DamageTrigger.registerVerbose(whichTrig, DamageTrigger.getVerboseStr(eventName), value, false, f)
endfunction
function TriggerRegisterDamageEngine takes trigger whichTrig, string eventName, real value returns DamageTrigger
return DamageTrigger.registerTrigger(whichTrig, eventName, value)
endfunction
function RegisterDamageEngineEx takes code c, string eventName, real value, integer f returns DamageTrigger
return TriggerRegisterDamageEngineEx(DamageTrigger[c], eventName, value, f)
endfunction
//Similar to TriggerRegisterDamageEvent, although takes code instead of trigger as the first argument.
function RegisterDamageEngine takes code c, string eventName, real value returns DamageTrigger
return RegisterDamageEngineEx(c, eventName, value, FILTER_OTHER)
endfunction
//For GUI to tap into more powerful vJass event filtering:
//! textmacro DAMAGE_TRIGGER_CONFIG
if not DamageTrigger.eventIndex.configured then
//! endtextmacro
//! textmacro DAMAGE_TRIGGER_CONFIG_END
call DamageTrigger.eventIndex.configure()
if not DamageTrigger.eventIndex.checkConfiguration() then
return
endif
endif
//! endtextmacro
endlibrary
// GUI-Friendly Damage Detection -- v1.2.1 -- by Weep
// http:// www.thehelper.net/forums/showthread.php?t=137957
//
// Requires: only this trigger and its variables.
//
// -- What? --
// This snippet provides a leak-free, GUI-friendly implementation of an "any unit takes
// damage" event. It requires no JASS knowledge to use.
//
// It uses the Game - Value Of Real Variable event as its method of activating other
// triggers, and passes the event responses through a few globals.
//
// -- Why? --
// The traditional GUI method of setting up a trigger than runs when any unit is damaged
// leaks trigger events. This snippet is easy to implement and removes the need to do
// you own GUI damage detection setup.
//
// -- How To Implement --
// 0. Before you copy triggers that use GDD into a new map, you need to copy over GDD
// with its GDD Variable Creator trigger, or there will be a problem: the variables
// won't be automatically created correctly.
//
// 1. Be sure "Automatically create unknown variables while pasting trigger data" is
// enabled in the World Editor general preferences.
// 2. Copy this trigger category ("GDD") and paste it into your map.
// (Alternately: create the variables listed in the globals block below, create a
// trigger named "GUI Friendly Damage Detection", and paste in this entire text.)
// 3. Create your damage triggers using Game - Value Of Real Variable as the event,
// select GDD_Event as the variable, and leave the rest of the settings to the default
// "becomes Equal to 0.00".
// The event responses are the following variables:
// GDD_Damage is the amount of damage, replacing Event Response - Damage Taken.
// GDD_DamagedUnit is the damaged unit, replacing Event Response - Triggering Unit.
// Triggering Unit can still be used, if you need to use waits.
// Read the -- Notes -- section below for more info.
// GDD_DamageSource is the damaging unit, replacing Event Response - Damage Source.
//
// -- Notes --
// GDD's event response variables are not wait-safe; you can't use them after a wait in
// a trigger. If you need to use waits, Triggering Unit (a.k.a. GetTriggerUnit()) can
// be used in place of GDD_DamageSource. There is no usable wait-safe equivalent to
// Event Damage or Damage Source; you'll need to save the values yourself.
//
// Don't write any values to the variables used as the event responses, or it will mess
// up any other triggers using this snippet for their triggering. Only use their values.
//
// This uses arrays, so can detect damage for a maximum of 8190 units at a time, and
// cleans up data at a rate of 33.33 per second, by default. This should be enough for
// most maps, but if you want to change the rate, change the value returned in the
// GDD_RecycleRate function at the top of the code, below.
//
// By default, GDD will not register units that have Locust at the moment of their
// entering the game, and will not recognize when they take damage (which can only
// happen if the Locust ability is later removed from the unit.) To allow a unit to have
// Locust yet still cause GDD damage events if Locust is removed, you can either design
// the unit to not have Locust by default and add it via triggers after creation, or
// edit the GDD_Filter function at the top of the code, below.
//
// -- Credits --
// Captain Griffin on wc3c.net for the research and concept of GroupRefresh.
//
// Credit in your map not needed, but please include this README.
//
// -- Version History --
// 1.2.1: Minor code cleaning. Added configuration functions. Updated documentation.
// 1.2.0: Made this snippet work properly with recursive damage.
// 1.1.1: Added a check in order to not index units with the Locust ability (dummy units).
// If you wish to check for damage taken by a unit that is unselectable, do not
// give the unit-type Locust in the object editor; instead, add the Locust ability
// 'Aloc' via a trigger after its creation, then remove it.
// 1.1.0: Added a check in case a unit gets moved out of the map and back.
// 1.0.0: First release.
//===================================================================
// Configurables.
function GDD_RecycleRate takes nothing returns real //The rate at which the system checks units to see if they've been removed from the game
return 0.03
endfunction
function GDD_Filter takes unit u returns boolean //The condition a unit has to pass to have it registered for damage detection
return GetUnitAbilityLevel(u, 'Aloc') == 0 //By default, the system ignores Locust units, because they normally can't take damage anyway
endfunction
//===================================================================
// This is just for reference.
// If you use JassHelper, you could uncomment this section instead of creating the variables in the trigger editor.
// globals
// real udg_GDD_Event = 0.
// real udg_GDD_Damage = 0.
// unit udg_GDD_DamagedUnit
// unit udg_GDD_DamageSource
// trigger array udg_GDD__TriggerArray
// integer array udg_GDD__Integers
// unit array udg_GDD__UnitArray
// group udg_GDD__LeftMapGroup = CreateGroup()
// endglobals
//===================================================================
// System code follows. Don't touch!
function GDD_Event takes nothing returns boolean
local unit damagedcache = udg_GDD_DamagedUnit
local unit damagingcache = udg_GDD_DamageSource
local real damagecache = udg_GDD_Damage
set udg_GDD_DamagedUnit = GetTriggerUnit()
set udg_GDD_DamageSource = GetEventDamageSource()
set udg_GDD_Damage = GetEventDamage()
set udg_GDD_Event = 1.
set udg_GDD_Event = 0.
set udg_GDD_DamagedUnit = damagedcache
set udg_GDD_DamageSource = damagingcache
set udg_GDD_Damage = damagecache
set damagedcache = null
set damagingcache = null
return false
endfunction
function GDD_AddDetection takes nothing returns boolean
// if(udg_GDD__Integers[0] > 8190) then
// call BJDebugMsg("GDD: Too many damage events! Decrease number of units present in the map or increase recycle rate.")
// ***Recycle rate is specified in the GDD_RecycleRate function at the top of the code. Smaller is faster.***
// return
// endif
if(IsUnitInGroup(GetFilterUnit(), udg_GDD__LeftMapGroup)) then
call GroupRemoveUnit(udg_GDD__LeftMapGroup, GetFilterUnit())
elseif(GDD_Filter(GetFilterUnit())) then
set udg_GDD__Integers[0] = udg_GDD__Integers[0]+1
set udg_GDD__UnitArray[udg_GDD__Integers[0]] = GetFilterUnit()
set udg_GDD__TriggerArray[udg_GDD__Integers[0]] = CreateTrigger()
call TriggerRegisterUnitEvent(udg_GDD__TriggerArray[udg_GDD__Integers[0]], udg_GDD__UnitArray[udg_GDD__Integers[0]], EVENT_UNIT_DAMAGED)
call TriggerAddCondition(udg_GDD__TriggerArray[udg_GDD__Integers[0]], Condition(function GDD_Event))
endif
return false
endfunction
function GDD_PreplacedDetection takes nothing returns nothing
local group g = CreateGroup()
local integer i = 0
loop
call GroupEnumUnitsOfPlayer(g, Player(i), Condition(function GDD_AddDetection))
set i = i+1
exitwhen i == bj_MAX_PLAYER_SLOTS
endloop
call DestroyGroup(g)
set g = null
endfunction
function GDD_GroupRefresh takes nothing returns nothing
// Based on GroupRefresh by Captain Griffen on wc3c.net
if (bj_slotControlUsed[5063] == true) then
call GroupClear(udg_GDD__LeftMapGroup)
set bj_slotControlUsed[5063] = false
endif
call GroupAddUnit(udg_GDD__LeftMapGroup, GetEnumUnit())
endfunction
function GDD_Recycle takes nothing returns nothing
if(udg_GDD__Integers[0] <= 0) then
return
elseif(udg_GDD__Integers[1] <= 0) then
set udg_GDD__Integers[1] = udg_GDD__Integers[0]
endif
if(GetUnitTypeId(udg_GDD__UnitArray[udg_GDD__Integers[1]]) == 0) then
call DestroyTrigger(udg_GDD__TriggerArray[udg_GDD__Integers[1]])
set udg_GDD__TriggerArray[udg_GDD__Integers[1]] = null
set udg_GDD__TriggerArray[udg_GDD__Integers[1]] = udg_GDD__TriggerArray[udg_GDD__Integers[0]]
set udg_GDD__UnitArray[udg_GDD__Integers[1]] = udg_GDD__UnitArray[udg_GDD__Integers[0]]
set udg_GDD__UnitArray[udg_GDD__Integers[0]] = null
set udg_GDD__Integers[0] = udg_GDD__Integers[0]-1
endif
set udg_GDD__Integers[1] = udg_GDD__Integers[1]-1
endfunction
function GDD_LeaveMap takes nothing returns boolean
local boolean cached = bj_slotControlUsed[5063]
if(udg_GDD__Integers[2] < 64) then
set udg_GDD__Integers[2] = udg_GDD__Integers[2]+1
else
set bj_slotControlUsed[5063] = true
call ForGroup(udg_GDD__LeftMapGroup, function GDD_GroupRefresh)
set udg_GDD__Integers[2] = 0
endif
call GroupAddUnit(udg_GDD__LeftMapGroup, GetFilterUnit())
set bj_slotControlUsed[5063] = cached
return false
endfunction
// ===========================================================================
function InitTrig_GUI_Friendly_Damage_Detection takes nothing returns nothing
local region r = CreateRegion()
call RegionAddRect(r, GetWorldBounds())
call TriggerRegisterEnterRegion(CreateTrigger(), r, Condition(function GDD_AddDetection))
call TriggerRegisterLeaveRegion(CreateTrigger(), r, Condition(function GDD_LeaveMap))
call GDD_PreplacedDetection()
call TimerStart(CreateTimer(), GDD_RecycleRate(), true, function GDD_Recycle)
set r = null
endfunction
/*
Key : player
0 : Deconcentration timer
1 : Tier 1 unlock
2 : Tier 2 unlock
3 : Tier 3 unlock
4 : Amplificator group
5 : Juggernaut group
6 : Hype train group
7 : Experimentor group
8 : Dictator
9 : Oiligarch
10 : Mind network attacked timer
11 : Mind node group
12 : Mind neuron
Key : Mind node
-2 : Visibility modifier
-1: Finished to build
0 : Attached effect
1 : Builder
2 : Attached mind neurons group
3 : Gatherer
4 : Deconcentration timer
5 : Juggernaut group
6 : Action effect dummy
7 : Mind node dummy attacker
8 : Mind node dummy target
9 : Repaired building
10 : Repaired building timer check
11 : Action feedback dummy
100+ : Special effect zone array
Key : Mind node builder / gatherer
0 : Mind node
Key : Mind neuron
-2 : Visibility modifier
-1: Finished to build
0 : Attached mind nodes
1 : Nearby mind neurons
2 : Effect array size
3 : Effect array start
4 : Node link
5 : Linked main nodes
100+ : Special effect zone array
Key : Incrementower
0 : Attack boost
1 : Armor boost
2 : Attack speed boost
3 : HP boost
4 : Range boost
5 : Total boost
Key : Silver plate
0 : Attention timer
Key : Concentrator
0 : Is rooted
1 : Affected units
2 : Amount of units
Key : Youngster
0 :
Key : Silgolem
0 :
1 : Boiling heart timer
2 : Overburst dummy caster
Key : Elder
0 :
1 : Damage buffer
2 : Overburst dummy
Key : Juggernaut
0 : Take off timer
Key : Deconcentration timer
0 : Unit
Key : Hype train
0 : Caster dummy
1 : Barge in reload
2 : Barge in target point
3 : Barge in move timer
4 :
5 : Hop in duration timer
Key : Hype train responsive plating timer
0 : Hype train
1 : amount to heal every second
2 : remaining iterations
Key : Experimentor
0 : Caster dummy
1 : Charges
2 : Number of speed boost
3 : Boosted units
4 : Sqrt shield timer
Key : Caster dummy
0 : Root unit
Key : Dictator
0 : Caster dummy
1 : Grace last target
2 : Grace targets
3 : Grace loop timer
4 : Mad king essence duration
Key : Meme lord
0 : Caster dummy
1 : Caster dummy 2 (for mimetism level 2)
Key : Oiligarch
0 : Hound target group
Key : Station master
0 : Caster dummy
1 : Remaining projectiles
Key : building
-1 : Finished to build
Key : any unit
High color : number of charges
High color : Refresh timer
Sacrifice : Spell reduction expiration timer
Hop-in : Invulnerable timer
Hop-in+1 : Invulerable reload
Personnal gr. : Last Dictator
Mimetism : Mana cap
Mimetism+1 : Mana reduction level
Hound guard : Group of hounds targeting it
Coffee : Expiration timer
Overclock : Remaining attacks
Possession : Previous owner
Possession+1: Duration timer
ADHD : Attack buffer
Synapse Inh. : persistance timer
*/
library LocalHelper
globals
private boolean array Is_for_player
group array WarpUnit
player array gp //group player
endglobals
function IsForPlayer takes player which_player returns boolean
return Is_for_player[GetPlayerId(which_player)]
endfunction
function IsForPlayerId takes integer which_player_id returns boolean
return Is_for_player[which_player_id]
endfunction
struct Local
readonly static player p//=GetLocalPlayer()
readonly static integer id//=GetPlayerId(thistype.p)
readonly static string s//=I2S(thistype.id)
boolean bool //no need to set it to false, since it's an array in the background (vjass -> jass)
static method create takes nothing returns thistype
return thistype.allocate()
endmethod
method destroy takes nothing returns nothing
set this.bool=false
call this.deallocate()
endmethod
method addPlayer takes player which_player returns nothing
if which_player==thistype.p then
set this.bool=true
endif
endmethod
method addPlayerId takes integer which_player_id returns nothing
if which_player_id==thistype.id then
set this.bool=true
endif
endmethod
method removePlayer takes player which_player returns nothing
if which_player==thistype.p then
set this.bool=false
endif
endmethod
method removePlayerId takes integer which_player_id returns nothing
if which_player_id==thistype.id then
set this.bool=false
endif
endmethod
method addAllPlayers takes nothing returns nothing
set this.bool=true
endmethod
method removeAllPlayers takes nothing returns nothing
set this.bool=false
endmethod
static method onInit takes nothing returns nothing
//you can't use GetLocalPlayer() in a global variable initial value, or wc3 will crash
set thistype.p=GetLocalPlayer()
set thistype.id=GetPlayerId(thistype.p)
set thistype.s=I2S(thistype.id)
set Is_for_player[thistype.id]=true
endmethod
endstruct
endlibrary
library ADHD
globals
group Gug=CreateGroup()
endglobals
function madnessEnd takes nothing returns nothing
local timer t=GetExpiredTimer()
local integer kT=GetHandleId(t)
local unit u=LoadUnitHandle(udg_HashAnorar,kT,0)
local integer ut=GetUnitTypeId(u)
// Default
//if ut=='h006' or ut=='h00F' or ut=='h008' or ut=='h009' or ut=='h00J' then
if GetUnitAbilityLevel(u,'A011')==1 then
call UnitAddAbility(u,'A003')
call UnitRemoveAbility(u,'A011')
endif
call FlushChildHashtable(udg_HashAnorar,kT)
call DestroyTimer(t)
set u=null
set t=null
endfunction
function juggernautTakeOff takes nothing returns nothing
local timer t=GetExpiredTimer()
local integer kT=GetHandleId(t)
local unit u=LoadUnitHandle(udg_HashAnorar,kT,0)
call UnitAddAbility(u,'S001')
set u=null
set t=null
endfunction
function colorLoop takes nothing returns nothing
local timer t=GetExpiredTimer()
local integer kT=GetHandleId(t)
local unit u=LoadUnitHandle(udg_HashAnorar,kT,0)
local integer kU=GetHandleId(u)
local integer x=LoadInteger(udg_HashAnorar,kU,'A028'+1)
call SaveInteger(udg_HashAnorar,x-1,kU,'A028'+1)
if x<=0 then
call DestroyTimer(t)
call FlushChildHashtable(udg_HashAnorar,kT)
endif
set u=null
set t=null
endfunction
function deconcentrationEnd takes nothing returns nothing
local timer t=GetExpiredTimer()
local integer kT=GetHandleId(t)
local unit u=LoadUnitHandle(udg_HashAnorar,kT,0)
local integer kU=GetHandleId(u)
call PauseUnit(u,false)
call PauseUnit(LoadUnitHandle(udg_HashAnorar,kU,1),false)
call PauseUnit(LoadUnitHandle(udg_HashAnorar,kU,3),false)
call FogModifierStart(LoadFogModifierHandle(udg_HashAnorar,kU,-2))
set u=null
set t=null
endfunction
function sacrificeBonusEnd takes nothing returns nothing
local timer t=GetExpiredTimer()
local integer kT=GetHandleId(t)
local unit u=LoadUnitHandle(udg_HashAnorar,kT,0)
local integer kU=GetHandleId(u)
call UnitRemoveAbility(u,'A00N')
call DestroyTimer(t)
call FlushChildHashtable(udg_HashAnorar,kT)
set u=null
set t=null
endfunction
function bargeInLoop takes nothing returns nothing
local timer t=GetExpiredTimer()
local integer kT=GetHandleId(t)
local unit u=LoadUnitHandle(udg_HashAnorar,kT,0)
local integer kU=GetHandleId(u)
local real r=(udg_BargeInRange/udg_BargeInTime)*udg_BargeInPeriod
local player p=GetOwningPlayer(u)
local location l=GetUnitLoc(u)
local location l3=LoadLocationHandle(udg_HashAnorar,kU,2)
local location l2=PolarProjectionBJ(l,AngleBetweenPoints(l,l3),r)
local real r2=DistanceBetweenPoints(l2,l3)
local unit u2
call GroupEnumUnitsInRange(Gug,GetUnitX(u),GetUnitY(u),udg_BargeInArea,null)
loop
set u2=FirstOfGroup(Gug)
exitwhen u2==null
if IsUnitEnemy(u,p) and GetWidgetLife(u2)>0 and (IsUnitType(u2,UNIT_TYPE_STRUCTURE) or IsUnitType(u2,UNIT_TYPE_GROUND)) then
call SetWidgetLife(u2,GetWidgetLife(u2)-udg_BargeInDamage)
endif
call GroupRemoveUnit(Gug,u2)
endloop
if r>r2 then
call SetUnitPositionLoc(u,l3)
call RemoveLocation(l3)
call PauseTimer(t)
call PauseUnit(u,false)
call SetUnitPathing(u,true)
else
call SetUnitPositionLoc(u,l2)
endif
call RemoveLocation(udg_l)
call RemoveLocation(udg_l2)
set u=null
set l=null
set l2=null
set l3=null
set t=null
endfunction
function hopInEnd takes nothing returns nothing
local timer t=GetExpiredTimer()
local integer kT=GetHandleId(t)
local unit u=LoadUnitHandle(udg_HashAnorar,kT,0)
call UnitRemoveAbility(u,'A00S')
set u=null
set t=null
endfunction
function hopInProtectionEnd takes nothing returns nothing
local timer t=GetExpiredTimer()
local integer kT=GetHandleId(t)
local unit u=LoadUnitHandle(udg_HashAnorar,kT,0)
call UnitRemoveAbility(u,'A02K')
call FlushChildHashtable(udg_HashAnorar,kT)
call DestroyTimer(t)
set u=null
set t=null
endfunction
function hopInReload takes nothing returns nothing
local timer t=GetExpiredTimer()
local integer kT=GetHandleId(t)
local unit u=LoadUnitHandle(udg_HashAnorar,kT,0)
call FlushChildHashtable(udg_HashAnorar,kT)
call DestroyTimer(t)
set u=null
set t=null
endfunction
function reaperClaw takes unit what, string color returns nothing
// by Vinz alias Mythic (hiveworkshop)
local unit u = what
local effect fx
local real x = GetUnitX(u)
local real y = GetUnitY(u)
local real face = Deg2Rad(GetUnitFacing(u))
local real tilt
local string path="ReapersClawsOrange.mdx" // default in case of wrong parametter
if color=="orange" then
set path="ReapersClawsOrange.mdx"
endif
if color=="purple" then
set path="ReapersClawsPurple.mdx"
endif
if color=="blue" then
set path="ReapersClawsBlue.mdx"
endif
set tilt = 0
set fx = AddSpecialEffect(path, x, y)
call BlzSetSpecialEffectOrientation( fx, face, 0, Deg2Rad(tilt))
call BlzSetSpecialEffectHeight(fx, 90 + BlzGetUnitZ(u))
call BlzSetSpecialEffectTimeScale(fx, 2)
call DestroyEffect(fx)
set tilt = -45
set fx = AddSpecialEffect(path, x, y)
call BlzSetSpecialEffectOrientation( fx, face, 0, Deg2Rad(tilt))
call BlzSetSpecialEffectHeight(fx, 110 + BlzGetUnitZ(u))
call BlzSetSpecialEffectTimeScale(fx, 1.6)
call DestroyEffect(fx)
set tilt = -135
set fx = AddSpecialEffect(path, x, y)
call BlzSetSpecialEffectOrientation( fx, face, 0, Deg2Rad(tilt))
call BlzSetSpecialEffectHeight(fx, 110 + BlzGetUnitZ(u))
call BlzSetSpecialEffectTimeScale(fx, 1.4)
call DestroyEffect(fx)
set u = null
set fx = null
endfunction
function silgolemCooldown takes nothing returns nothing
local timer t=GetExpiredTimer()
local integer kT=GetHandleId(t)
local unit u=LoadUnitHandle(udg_HashAnorar,kT,0)
local integer kU=GetHandleId(u)
if GetUnitAbilityLevel(u,'A00E')>1 then
call DecUnitAbilityLevel(u,'A00E')
call DecUnitAbilityLevel(u,'A02S')
call TimerStart(t,udg_CooldownNext,true,function silgolemCooldown)
else
call DestroyTimer(t)
call SetUnitAbilityLevel(u,'A02S',1)
call UnitRemoveAbility(u,'A00E')
call FlushChildHashtable(udg_HashAnorar,kT)
endif
set u=null
set t=null
endfunction
function personnalGraceLoop takes nothing returns nothing
local timer t=GetExpiredTimer()
local integer kT=GetHandleId(t)
local unit u=LoadUnitHandle(udg_HashAnorar,kT,0)
local integer kU=GetHandleId(u)
local group ug=LoadGroupHandle(udg_HashAnorar,kU,2)
local group ug2=CreateGroup()
local unit u2
local unit u3=null
local boolean b=false
// reset the principal target
call SaveUnitHandle(udg_HashAnorar,kU,1,null)
loop
set u2=FirstOfGroup(ug)
exitwhen u2==null
set b=true
call GroupRemoveUnit(ug,u2)
if GetUnitAbilityLevel(u2,'B007')>0 then
if u3==null then
set u3=u2
call SaveUnitHandle(udg_HashAnorar,kU,1,u3)
endif
call GroupAddUnit(ug2,u2)
// List all silence effects here to remove
call UnitRemoveAbility(u2,'BNsi')
else
// If not longer affected, delete his link to the Dictator
call SaveUnitHandle(udg_HashAnorar,GetHandleId(u2),'A00Z',null)
endif
endloop
call SaveGroupHandle(udg_HashAnorar,kU,2,ug2)
call DestroyGroup(ug)
if not b then
call PauseTimer(t)
endif
set ug=null
set ug2=null
set u=null
set u2=null
set u3=null
set t=null
endfunction
function madKingEnd takes nothing returns nothing
local timer t=GetExpiredTimer()
local integer kT=GetHandleId(t)
local unit u=LoadUnitHandle(udg_HashAnorar,kT,0)
call UnitRemoveAbility(u,'A014')
call UnitRemoveAbility(u,'A01A')
set u=null
set t=null
endfunction
function coffeeEnd takes nothing returns nothing
local timer t=GetExpiredTimer()
local integer kT=GetHandleId(t)
local unit u=LoadUnitHandle(udg_HashAnorar,kT,0)
// Remove all default attention deficit
call UnitRemoveAbility(u,'A003')
call UnitRemoveAbility(u,'A010')
call UnitRemoveAbility(u,'A011')
// And the focus effect
call UnitRemoveAbility(u,'B00P')
call DestroyTimer(t)
call FlushChildHashtable(udg_HashAnorar,kT)
set u=null
set t=null
endfunction
function derrickGold takes nothing returns nothing
local timer t=GetExpiredTimer()
local integer kT=GetHandleId(t)
local unit u=LoadUnitHandle(udg_HashAnorar,kT,0)
local integer kU=GetHandleId(u)
local integer current=LoadInteger(udg_HashAnorar,kU,1)
local player p=LoadPlayerHandle(udg_HashAnorar,kT,1)
if current<500 then
call SetPlayerState(p,PLAYER_STATE_RESOURCE_GOLD,GetPlayerState(p,PLAYER_STATE_RESOURCE_GOLD)+5)
call SaveInteger(udg_HashAnorar,kU,1,current+5)
else
call DestroyTimer(t)
call FlushChildHashtable(udg_HashAnorar,kT)
endif
set p=null
set u=null
set t=null
endfunction
function possessionEnd takes nothing returns nothing
local timer t=GetExpiredTimer()
local integer kT=GetHandleId(t)
local unit u=LoadUnitHandle(udg_HashAnorar,kT,0)
local integer kU=GetHandleId(u)
local player p=LoadPlayerHandle(udg_HashAnorar,kU,0)
call GroupRemoveUnit(udg_PossessionGroup,u)
call SetUnitOwner(u,p,true)
call FlushChildHashtable(udg_HashAnorar,kT)
call UnitRemoveAbility(u,'B00J')
call DestroyTimer(t)
set u=null
set t=null
set p=null
endfunction
function responsivePlatingLoop takes nothing returns nothing
local timer t=GetExpiredTimer()
local integer kT=GetHandleId(t)
local unit u=LoadUnitHandle(udg_HashAnorar,kT,0)
local real heal=LoadReal(udg_HashAnorar,kT,1)
local integer left=LoadInteger(udg_HashAnorar,kT,2)-1
if u==null or GetWidgetLife(u)<0.451 or left<=0 then
call FlushChildHashtable(udg_HashAnorar,kT)
call DestroyTimer(t)
else
call SetWidgetLife(u,GetWidgetLife(u)+heal)
call SaveInteger(udg_HashAnorar,kT,2,left)
endif
set u=null
set t=null
endfunction
function sqrtShieldOn takes nothing returns nothing
local timer t=GetExpiredTimer()
local integer kT=GetHandleId(t)
local unit u=LoadUnitHandle(udg_HashAnorar,kT,0)
call UnitAddAbility(u,'A02I')
set u=null
set t=null
endfunction
function trainDeath takes nothing returns nothing
local timer t=GetExpiredTimer()
local integer kT=GetHandleId(t)
local unit u=LoadUnitHandle(udg_HashAnorar,kT,0)
local string path="ExplosionBig.mdl"
local effect e
local integer x=4
loop
exitwhen x==0
set x=x-1
set e=AddSpecialEffect(path,GetUnitX(u),GetUnitY(u))
call BlzSetSpecialEffectOrientation(e,GetRandomReal(-0.5,0.5),GetRandomReal(-0.5,0.5),GetRandomReal(-0.5,0.5))
call BlzSetSpecialEffectTimeScale(e, GetRandomReal(0.4,0.9))
call BlzSetSpecialEffectScale(e,GetRandomReal(0.7,0.9))
call DestroyEffect(e)
endloop
call RemoveUnit(u)
call FlushChildHashtable(udg_HashAnorar,kT)
call DestroyTimer(t)
set u=null
set t=null
endfunction
function grenadeSpawn takes nothing returns nothing
local timer t=GetExpiredTimer()
local integer kT=GetHandleId(t)
local location l=LoadLocationHandle(udg_HashAnorar,kT,0)
local player p=LoadPlayerHandle(udg_HashAnorar,kT,1)
local unit u=CreateUnit(p,'o006',GetLocationX(l),GetLocationY(l),0)
call SetUnitPathing(u,false)
call SetUnitX(u,GetLocationX(l))
call SetUnitY(u,GetLocationY(l))
call FlushChildHashtable(udg_HashAnorar,kT)
call DestroyTimer(t)
call RemoveLocation(l)
set u=null
set p=null
set t=null
set l=null
endfunction
function liquifiedSteamEnd takes nothing returns nothing
local timer t=GetExpiredTimer()
local integer kT=GetHandleId(t)
local unit u=LoadUnitHandle(udg_HashAnorar,kT,0)
call UnitRemoveAbility(u,'A02Y')
call DestroyTimer(t)
call FlushChildHashtable(udg_HashAnorar,kT)
set u=null
set t=null
endfunction
function inhibitorEnd takes nothing returns nothing
local timer t=GetExpiredTimer()
local integer kT=GetHandleId(t)
local unit u=LoadUnitHandle(udg_HashAnorar,kT,0)
// default
if GetUnitAbilityLevel(u,'A010')==1 then
call UnitRemoveAbility(u,'A010')
call UnitAddAbility(u,'A003')
endif
// building
if GetUnitAbilityLevel(u,'A032')==1 then
call UnitRemoveAbility(u,'A032')
call UnitAddAbility(u,'A031')
endif
// experimentor
if GetUnitAbilityLevel(u,'A034')==1 then
call UnitRemoveAbility(u,'A034')
call UnitAddAbility(u,'A036')
endif
// silver plate
if GetUnitAbilityLevel(u,'A037')==1 then
call UnitRemoveAbility(u,'A037')
call UnitAddAbility(u,'A038')
endif
// sildiver
if GetUnitAbilityLevel(u,'A03B')==1 then
call UnitRemoveAbility(u,'A03B')
call UnitAddAbility(u,'A03A')
endif
// severe
if GetUnitAbilityLevel(u,'A012')==1 then
call UnitRemoveAbility(u,'A012')
call UnitAddAbility(u,'A00D')
endif
call DestroyTimer(t)
call FlushChildHashtable(udg_HashAnorar,kT)
set u=null
set t=null
endfunction
function sacrificeLoop takes nothing returns nothing
local timer t=GetExpiredTimer()
local integer kT=GetHandleId(t)
local unit u=LoadUnitHandle(udg_HashAnorar,kT,0)
local real x=GetUnitX(u)
local real y=GetUnitY(u)
local player p=GetOwningPlayer(u)
local integer i=0
local unit u2
local group ug
local effect e
//call DisplayTextToForce(GetPlayersAll(),"LOOP")
if GetUnitAbilityLevel(u,'A037')==0 and ((GetRandomInt(1,10)<= 4 and GetUnitAbilityLevel(u,'A038')==1) or (GetRandomInt(1,10)<=8 and GetUnitAbilityLevel(u,'A039')==1)) then
//call DisplayTextToForce(GetPlayersAll(),"ADHD")
set ug=CreateGroup()
call GroupEnumUnitsInRange(Gug,x,y,500,null)
loop
set u2=FirstOfGroup(Gug)
exitwhen u2==null
if not IsUnitType(u2,UNIT_TYPE_STRUCTURE) and IsUnitAlly(u2,p) and u!=u2 and UnitAlive(u2) then
call GroupAddUnit(ug,u2)
set i=i+1
endif
call GroupRemoveUnit(Gug,u2)
endloop
if i>0 then
set i=GetRandomInt(1,i)
loop
set u2=FirstOfGroup(ug)
exitwhen i==1
call GroupRemoveUnit(ug,u2)
set i=i-1
endloop
//call DisplayTextToForce(GetPlayersAll(),"SWITCH")
call IssueTargetOrderBJ(u,"bloodlust",u2)
if GetUnitAbilityLevel(u,'A039')==1 then
set e=AddSpecialEffect("Blink Red Caster.mdx",x,y)
else
set e=AddSpecialEffect("Blink Purple Caster.mdx",x,y)
endif
call BlzSetSpecialEffectScale(e,.5)
call BlzSetSpecialEffectZ(e,200)
call DestroyEffect(e)
endif
call DestroyGroup(ug)
endif
set u=null
set t=null
set e=null
set ug=null
set p=null
endfunction
function possessionSwitch takes nothing returns nothing
local timer t=GetExpiredTimer()
local integer kT=GetHandleId(t)
local unit u=LoadUnitHandle(udg_HashAnorar,kT,0)
local real x=GetUnitX(u)
local real y=GetUnitY(u)
local player p=GetOwningPlayer(u)
local integer i=0
local unit u2
local group ug
local effect e
//call DisplayTextToForce(GetPlayersAll(),"LOOP")
// TODO check specific ADHD
if GetUnitAbilityLevel(u,'A03B')==0 and ((GetRandomInt(1,10)<= 4 and GetUnitAbilityLevel(u,'A03A')==1) or (GetRandomInt(1,10)<=8 and GetUnitAbilityLevel(u,'A03C')==1)) then
//call DisplayTextToForce(GetPlayersAll(),"ADHD")
set ug=CreateGroup()
call GroupEnumUnitsInRange(Gug,x,y,500,null)
loop
set u2=FirstOfGroup(Gug)
exitwhen u2==null
if IsUnitType(u2,UNIT_TYPE_FLYING) and not IsUnitAlly(u2,p) and u!=u2 and UnitAlive(u2) then
call GroupAddUnit(ug,u2)
set i=i+1
endif
call GroupRemoveUnit(Gug,u2)
endloop
if i>0 then
set i=GetRandomInt(1,i)
loop
set u2=FirstOfGroup(ug)
exitwhen i==1
call GroupRemoveUnit(ug,u2)
set i=i-1
endloop
//call DisplayTextToForce(GetPlayersAll(),"SWITCH")
call IssueTargetOrderBJ(u,"bloodlust",u2)
if GetUnitAbilityLevel(u,'A03C')==1 then
set e=AddSpecialEffect("Blink Red Caster.mdx",x,y)
else
set e=AddSpecialEffect("Blink Purple Caster.mdx",x,y)
endif
call BlzSetSpecialEffectScale(e,.5)
call BlzSetSpecialEffectZ(e,200)
call DestroyEffect(e)
endif
call DestroyGroup(ug)
endif
set u=null
set t=null
set e=null
set ug=null
set p=null
endfunction
endlibrary