Name | Type | is_array | initial_value |
AffinityVoidGroup | group | No | |
AfterDamageEvent | real | No | |
AMSAmount | real | Yes | |
AOEDamageEvent | real | No | |
ApostateGroup | group | No | |
ArchNethermanerGroup | group | No | |
AstroPlateGroup | group | No | |
AttackingUnitDamageType | attacktype | No | |
AugurAura | unit | No | |
AugurAuraGroup | group | No | |
BaneHavoc | unit | No | |
BaneHavocInt | integer | No | |
BlackHunter | unit | No | |
BlackStrike | unit | Yes | |
BlashFlier | integer | No | |
BloodCord | integer | No | |
BloodCordUnit | unit | No | |
BrightlanceGroup | group | No | |
CaptiveBondDummy | unit | Yes | |
CargoEvent | real | No | |
CargoTransportGroup | group | Yes | |
CargoTransportUnit | unit | Yes | |
CenturionGroup | group | No | |
ChancellorAoEBuffUnit | unit | No | |
ChancellorAuraUnit | unit | No | |
ChancellorHeroGroup | group | No | |
ChannelDemonfire | integer | No | |
CheckDeathList | integer | Yes | |
CheckDeathTimer | timer | No | |
Choice | dialog | Yes | |
ClearDamageEvent | trigger | No | |
CosmicAura | integer | No | |
CrimsonVale | integer | No | |
CrimsonValeBonusChance | integer | No | |
CrimsonValeUnit | unit | No | |
CurseFragileDummy | unit | No | |
CurseFragility | integer | No | |
DAMAGE_FACTOR_BRACERS | real | No | |
DAMAGE_FACTOR_ELUNES | real | No | |
DAMAGE_FACTOR_ETHEREAL | real | No | |
DamageBlockingAbility | abilcode | No | |
DamageEvent | real | No | |
DamageEventAmount | real | No | |
DamageEventAOE | integer | No | |
DamageEventAOEGroup | group | No | |
DamageEventLevel | integer | No | |
DamageEventOverride | boolean | No | |
DamageEventPrevAmt | real | No | |
DamageEventSource | unit | No | |
DamageEventsWasted | integer | No | |
DamageEventTarget | unit | No | |
DamageEventTrigger | trigger | No | |
DamageEventType | integer | No | |
DamageModifierEvent | real | No | |
DamageToVoyager | real | No | |
DamageTypeBlocked | integer | No | |
DamageTypeCriticalStrike | integer | No | |
DamageTypeExplosive | integer | No | |
DamageTypeHeal | integer | No | |
DamageTypeReduced | integer | No | |
DamageTypeVoid | integer | No | |
DeathEvent | real | No | |
DemonfireEffect | effect | Yes | |
DemonfireGroup | group | No | |
DetectRemoveAbility | abilcode | No | |
DetectTransformAbility | abilcode | No | |
DisArmor | integer | No | |
DisArmUnit | unit | No | |
DistrustDummy | unit | No | |
DistrustInt | integer | No | |
DmgEvBracers | itemcode | No | |
DmgEvMana | real | No | |
DmgEvManaMult | real | No | |
DmgEvMSlvl | integer | No | |
DmgEvRecursionN | integer | No | |
DmgEvRunning | boolean | No | |
DmgEvStarted | boolean | No | |
DmgEvTimer | timer | No | |
DmgEvTrig | trigger | No | |
DOT_Attack_Type | attacktype | No | |
DOT_Damage | real | No | |
DOT_Damage_Type | damagetype | No | |
DragoonGroup | group | No | |
EnhancedDamageTarget | unit | No | |
EOT_Amount | integer | No | |
EOT_Array_Ability | abilcode | Yes | |
EOT_Array_Ability_Level | integer | Yes | |
EOT_Array_Buff | buffcode | Yes | |
EOT_Array_Buff_Holder | abilcode | Yes | |
EOT_Array_Buff_Holder_Level | integer | Yes | |
EOT_Array_Can_Dispell | boolean | Yes | |
EOT_Array_Duration | real | Yes | |
EOT_Array_Hidden | boolean | Yes | |
EOT_Array_Id | integer | Yes | |
EOT_Array_Interval | real | Yes | |
EOT_Array_Is_Passive | boolean | Yes | |
EOT_Array_On_Period_Trigger | trigger | Yes | |
EOT_Array_Positive | boolean | Yes | |
EOT_Array_Remaining_Duration | real | Yes | |
EOT_Array_Remaining_Interval | real | Yes | |
EOT_Array_Source | unit | Yes | |
EOT_Array_Special_Effect | effect | Yes | |
EOT_Array_Special_Effect_Model | string | Yes | |
EOT_Array_Special_Effect_Point | string | Yes | |
EOT_Array_Subtype | integer | Yes | |
EOT_Array_Subtype2 | integer | Yes | |
EOT_Array_Target | unit | Yes | |
EOT_Array_Type | integer | Yes | |
EOT_Event_An_EOT_Has_Expired | real | No | |
EOT_Event_An_EOT_Is_Created | real | No | |
EOT_Event_An_EOT_Is_Destroyed | real | No | |
EOT_Event_An_EOT_Is_Dispelled | real | No | |
EOT_Event_Creation_After | real | No | |
EOT_Event_Creation_Before | real | No | |
EOT_Event_Destruction_After | real | No | |
EOT_Event_Destruction_Before | real | No | |
EOT_Event_Dispell_After | real | No | |
EOT_Event_Dispell_Before | real | No | |
EOT_Event_Expire_After | real | No | |
EOT_Event_Expire_Before | real | No | |
EOT_Event_Get_Data | real | No | |
EOT_Event_Interval_After | real | No | |
EOT_Event_Interval_Before | real | No | |
EOT_Event_Null_Variables | real | No | |
EOT_Event_On_Interval | real | No | |
EOT_Event_Save_Data | real | No | |
EOT_Hashtable | hashtable | No | |
EOT_Index | integer | No | |
EOT_Param_Ability | abilcode | No | |
EOT_Param_Ability_Level | integer | No | |
EOT_Param_Buff | buffcode | No | |
EOT_Param_Buff_Holder | abilcode | No | |
EOT_Param_Buff_Holder_Level | integer | No | |
EOT_Param_Can_Dispell | boolean | No | |
EOT_Param_Destroy | boolean | No | |
EOT_Param_Destroy_Passive | boolean | No | |
EOT_Param_Duration | real | No | |
EOT_Param_Expire | boolean | No | |
EOT_Param_Force_Destroy | boolean | No | |
EOT_Param_Hidden | boolean | No | |
EOT_Param_Id | integer | No | |
EOT_Param_Interval | real | No | |
EOT_Param_Is_Passive | boolean | No | |
EOT_Param_Negative | boolean | No | |
EOT_Param_Positive | boolean | No | |
EOT_Param_Remaining_Duration | real | No | |
EOT_Param_Remaining_Interval | real | No | |
EOT_Param_Source | unit | No | |
EOT_Param_Special_Effect | effect | No | |
EOT_Param_Special_Effect_Model | string | No | |
EOT_Param_Special_Effect_Point | string | No | |
EOT_Param_Subtype | integer | No | |
EOT_Param_Subtype2 | integer | No | |
EOT_Param_Target | unit | No | |
EOT_Param_Type | integer | No | |
EOT_Timer | timer | No | |
EOT_Trigger_Create_EOT | trigger | No | |
EOT_Trigger_Destroy_EOT | trigger | No | |
EOT_Trigger_Get_Data | trigger | No | |
EOT_Trigger_Remove_EOTs | trigger | No | |
EOT_Trigger_Save_Data | trigger | No | |
EOT_Unique_Id | integer | No | |
FaithfulGroup | group | No | |
FeedingStrike | integer | No | |
FelBarrage | integer | No | |
FelbloodElves | button | Yes | |
FelcrusherGroup | group | No | |
FelReaver | unit | No | |
FelReaverShadow | unit | No | |
FiendishShell | unit | No | |
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 | |
HideDamageFrom | boolean | Yes | |
IsDamageSpell | boolean | No | |
IsUnitAlive | boolean | Yes | |
IsUnitBeingUnloaded | boolean | Yes | |
IsUnitNew | boolean | Yes | |
IsUnitPreplaced | boolean | Yes | |
IsUnitReincarnating | boolean | Yes | |
IsUnitRemoved | boolean | Yes | |
IsUnitTransforming | boolean | Yes | |
KillerOfUnit | unit | Yes | |
LastDamageHP | real | No | |
LastDmgPrevAmount | real | Yes | |
LastDmgPrevType | integer | Yes | |
LastDmgSource | unit | Yes | |
LastDmgTarget | unit | Yes | |
LastDmgValue | real | Yes | |
LastDmgWasSpell | boolean | Yes | |
LegionGroup | group | No | |
MainStructureGroup | group | No | |
MurderousChamp | unit | No | |
NebulasHasteGroup | group | No | |
NeophyteDeath | group | No | |
NetherTurn | unit | No | |
NextDamageOverride | boolean | No | |
NextDamageType | integer | No | |
OblivionDummy | unit | No | |
Other | button | No | |
ParagonAuraGroup | group | No | |
PlayerColour | player | Yes | |
PlayerNum | integer | Yes | |
PlayerStructure | boolean | Yes | |
Portal_active | boolean | Yes | |
Portal_activeFX | string | Yes | |
Portal_arrivalFX | string | Yes | |
Portal_ConfigIndex | integer | Yes | |
Portal_delay | real | Yes | |
Portal_delayFXAbil | abilcode | Yes | |
Portal_departureFX | string | Yes | |
Portal_dummy | unit | No | |
Portal_FX | effect | Yes | |
Portal_group | group | No | |
Portal_INDEX_CASTER | integer | No | |
Portal_INDEX_TARGET | integer | No | |
Portal_INDEX_TRAVELLER | integer | No | |
Portal_isTeleporting | boolean | Yes | |
Portal_loc1 | location | No | |
Portal_loc2 | location | No | |
Portal_loc3 | location | No | |
Portal_loc4 | location | No | |
Portal_missileDummy | unitcode | Yes | |
Portal_missileFXAbil | abilcode | Yes | |
Portal_missileHeight | real | Yes | |
Portal_missileSpeed | real | Yes | |
Portal_missileTargetable | boolean | Yes | |
Portal_missileUseOwnMovement | boolean | Yes | |
Portal_portal | unit | Yes | |
Portal_preventAllies | boolean | Yes | |
Portal_range | real | Yes | |
Portal_SeverAbility | abilcode | No | |
Portal_targeted | unit | Yes | |
Portal_teleMissiles | group | No | |
Portal_traveller | unit | No | |
ProfusionGroup | group | No | |
ProphetAuraGroup | group | No | |
RallyPoint | location | No | |
RangerUltFacade | unit | No | |
RangerUltUnit | unit | No | |
Reaperstep | unit | No | |
RectorGroup | group | No | |
RelishInPain | integer | No | |
RelishPain | unit | No | |
RemainingManaCaster | integer | No | |
RemainingManaTarget | integer | No | |
ReverseAura | integer | No | |
Rush_Hash | hashtable | No | |
SalamderLGroup | group | No | |
ShifterGroup | group | No | |
ShiiningForce_Dummy | unit | No | |
ShiningShockTarget | unit | No | |
ShockBolt | effect | No | |
SpellDamageAbility | abilcode | No | |
StarBinderAura | unit | No | |
StarBinderHeroGroup | group | No | |
StolenPowerDummy | unit | No | |
StrikeAtTheHeart | unit | No | |
SummonerOfUnit | unit | Yes | |
TempAbility | abilcode | No | |
TempInteger | integer | No | |
tempLoc | location | Yes | |
TempLocation | location | No | |
TempUnit | 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 | |
UmbralRangerFacing | location | No | |
UMovNext | integer | Yes | |
UMovPrev | integer | Yes | |
UnitDamageRegistered | boolean | Yes | |
UnitInAction | boolean | Yes | |
UnitInActionEvent | real | No | |
UnitIndexerEnabled | boolean | No | |
UnitIndexEvent | real | No | |
UnitIndexLock | integer | Yes | |
UnitMovementInterval | real | No | |
UnitMoving | boolean | Yes | |
UnitMovingEvent | real | No | |
UnitMovingX | real | Yes | |
UnitMovingY | real | Yes | |
UnitTypeEvent | real | No | |
UnitTypeOf | unitcode | Yes | |
VanguardsGroup | group | No | |
VoidElvenGroup | group | No | |
VoidstrandDummy | unit | No | |
VoyagerCount | integer | No | |
VoyagerCountGroup | group | No | |
VoyagerGroup | group | No | |
VoyagerUnit | unit | No | |
WarlordGroupAcro | group | No | |
WarlordHero | unit | No | |
WarlordHeroAcro | unit | No | |
WaveOfSoul | unit | No | |
WorldMaxX | real | No | |
WorldMaxY | real | No |
//===========================================================================
// Damage Engine lets you detect, amplify, block or nullify damage. It even
// lets you detect if the damage was physical or from a spell. Just reference
// DamageEventAmount/Source/Target or the boolean IsDamageSpell, to get the
// necessary damage event data.
//
// - Detect damage: use the event "DamageEvent Equal to 1.00"
// - To change damage before it's dealt: use the event "DamageModifierEvent Equal to 1.00"
// - Detect damage after it was applied, use the event "AfterDamageEvent Equal to 1.00"
// - Detect spell damage: use the condition "IsDamageSpell Equal to True"
// - Detect zero-damage: use the event "DamageEvent Equal to 2.00" (an AfterDamageEvent will not fire for this)
//
// You can specify the DamageEventType before dealing triggered damage. To prevent an already-improbable error, I recommend running the trigger "ClearDamageEvent (Checking Conditions)" after dealing triggered damage from within a damage event:
// - Set NextDamageType = DamageTypeWhatever
// - Unit - Cause...
// - Trigger - Run ClearDamageEvent (Checking Conditions)
//
// You can modify the DamageEventAmount and the DamageEventType from a "DamageModifierEvent Equal to 1.00" trigger.
// - If the amount is modified to negative, it will count as a heal.
// - If the amount is set to 0, no damage will be dealt.
//
// If you need to reference the original in-game damage, use the variable "DamageEventPrevAmt".
//
//===========================================================================
// Programming note about "integer i" and "udg_DmgEvRecursionN": integer i
// ranges from -1 upwards. "udg_DmgEvRecursionN" ranges from 0 upwards.
// "integer i" is always 1 less than "udg_DmgEvRecursionN"
//
function DmgEvResetVars takes nothing returns nothing
local integer i = udg_DmgEvRecursionN - 2
set udg_DmgEvRecursionN = i + 1
if i >= 0 then
set udg_DamageEventPrevAmt = udg_LastDmgPrevAmount[i]
set udg_DamageEventAmount = udg_LastDmgValue[i]
set udg_DamageEventSource = udg_LastDmgSource[i]
set udg_DamageEventTarget = udg_LastDmgTarget[i]
set udg_IsDamageSpell = udg_LastDmgWasSpell[i]
set udg_DamageEventType = udg_LastDmgPrevType[i]
endif
endfunction
function CheckDamagedLifeEvent takes boolean clear returns nothing
if clear then
set udg_NextDamageOverride = false
set udg_NextDamageType = 0
endif
if udg_DmgEvTrig != null then
call DestroyTrigger(udg_DmgEvTrig)
set udg_DmgEvTrig = null
if udg_IsDamageSpell then
call SetWidgetLife(udg_DamageEventTarget, RMaxBJ(udg_LastDamageHP, 0.41))
if udg_LastDamageHP <= 0.405 then
if udg_DamageEventType < 0 then
call SetUnitExploded(udg_DamageEventTarget, true)
endif
//Kill the unit
call DisableTrigger(udg_DamageEventTrigger)
call UnitDamageTarget(udg_DamageEventSource, udg_DamageEventTarget, -999, false, false, null, DAMAGE_TYPE_UNIVERSAL, null)
call EnableTrigger(udg_DamageEventTrigger)
endif
elseif GetUnitAbilityLevel(udg_DamageEventTarget, udg_DamageBlockingAbility) > 0 then
call UnitRemoveAbility(udg_DamageEventTarget, udg_DamageBlockingAbility)
call SetWidgetLife(udg_DamageEventTarget, udg_LastDamageHP)
endif
if udg_DamageEventAmount != 0.00 and not udg_HideDamageFrom[GetUnitUserData(udg_DamageEventSource)] then
set udg_AfterDamageEvent = 0.00
set udg_AfterDamageEvent = 1.00
set udg_AfterDamageEvent = 0.00
endif
call DmgEvResetVars()
endif
endfunction
function DmgEvOnAOEEnd takes nothing returns nothing
if udg_DamageEventAOE > 1 then
set udg_AOEDamageEvent = 0.00
set udg_AOEDamageEvent = 1.00
set udg_AOEDamageEvent = 0.00
set udg_DamageEventAOE = 1
endif
set udg_DamageEventLevel = 1
set udg_EnhancedDamageTarget = null
call GroupClear(udg_DamageEventAOEGroup)
endfunction
function DmgEvOnExpire takes nothing returns nothing
set udg_DmgEvStarted = false
call CheckDamagedLifeEvent(true)
//Reset things so they don't perpetuate for AoE/Level target detection
call DmgEvOnAOEEnd()
set udg_DamageEventTarget = null
set udg_DamageEventSource = null
endfunction
function PreCheckDamagedLifeEvent takes nothing returns boolean
call CheckDamagedLifeEvent(true)
return false
endfunction
function OnUnitDamage takes nothing returns boolean
local boolean override = udg_DamageEventOverride
local integer i
local integer e = udg_DamageEventLevel
local integer a = udg_DamageEventAOE
local string s
local real prevAmount
local real life
local real prevLife
local unit u
local unit f
call CheckDamagedLifeEvent(false) //in case the unit state event failed and the 0.00 second timer hasn't yet expired
set i = udg_DmgEvRecursionN - 1 //Had to be moved here due to false recursion tracking
if i < 0 then
//Added 25 July 2017 to detect AOE damage or multiple single-target damage
set u = udg_DamageEventTarget
set f = udg_DamageEventSource
elseif i < 16 then
set udg_LastDmgPrevAmount[i]= udg_DamageEventPrevAmt
set udg_LastDmgValue[i] = udg_DamageEventAmount
set udg_LastDmgSource[i] = udg_DamageEventSource
set udg_LastDmgTarget[i] = udg_DamageEventTarget
set udg_LastDmgWasSpell[i] = udg_IsDamageSpell
set udg_LastDmgPrevType[i] = udg_DamageEventType
else
set s = "WARNING: Recursion error when dealing damage! Make sure when you deal damage from within a DamageEvent trigger, do it like this:\n\n"
set s = s + "Trigger - Turn off (This Trigger)\n"
set s = s + "Unit - Cause...\n"
set s = s + "Trigger - Turn on (This Trigger)"
//Delete the next couple of lines to disable the in-game recursion crash warnings
call ClearTextMessages()
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0.00, 0.00, 999.00, s)
return false
endif
set udg_DmgEvRecursionN = i + 2
set prevAmount = GetEventDamage()
set udg_DamageEventTarget = GetTriggerUnit()
set udg_DamageEventSource = GetEventDamageSource()
set udg_DamageEventAmount = prevAmount
set udg_DamageEventType = udg_NextDamageType
set udg_NextDamageType = 0
set udg_DamageEventOverride = udg_NextDamageOverride
set udg_NextDamageOverride = false
if i < 0 then
//Added 25 July 2017 to detect AOE damage or multiple single-target damage
if udg_DamageEventType == 0 then
if f == udg_DamageEventSource then
//Source has damaged more than once
if IsUnitInGroup(udg_DamageEventTarget, udg_DamageEventAOEGroup) then
//Added 5 August 2017 to improve tracking of enhanced damage against, say, Pulverize
set udg_DamageEventLevel = udg_DamageEventLevel + 1
set udg_EnhancedDamageTarget = udg_DamageEventTarget
else
//Multiple targets hit by this source - flag as AOE
set udg_DamageEventAOE = udg_DamageEventAOE + 1
endif
else
//New damage source - unflag everything
set u = udg_DamageEventSource
set udg_DamageEventSource = f
call DmgEvOnAOEEnd()
set udg_DamageEventSource = u
endif
call GroupAddUnit(udg_DamageEventAOEGroup, udg_DamageEventTarget)
endif
if not udg_DmgEvStarted then
set udg_DmgEvStarted = true
call TimerStart(udg_DmgEvTimer, 0.00, false, function DmgEvOnExpire)
endif
endif
if prevAmount == 0.00 then
if not udg_HideDamageFrom[GetUnitUserData(udg_DamageEventSource)] then
set udg_DamageEventPrevAmt = 0.00
set udg_DamageEvent = 0.00
set udg_DamageEvent = 2.00
set udg_DamageEvent = 0.00
endif
call DmgEvResetVars()
else
set u = udg_DamageEventTarget
set udg_IsDamageSpell = prevAmount < 0.00
if udg_IsDamageSpell then
set prevAmount = -udg_DamageEventAmount
set life = 1.00
if IsUnitType(u, UNIT_TYPE_ETHEREAL) and not IsUnitType(u, UNIT_TYPE_HERO) then
set life = life*udg_DAMAGE_FACTOR_ETHEREAL //1.67
endif
if GetUnitAbilityLevel(u, 'Aegr') > 0 then
set life = life*udg_DAMAGE_FACTOR_ELUNES //0.80
endif
if udg_DmgEvBracers != 0 and IsUnitType(u, UNIT_TYPE_HERO) then
//Inline of UnitHasItemOfTypeBJ without the potential handle ID leak.
set i = 6
loop
set i = i - 1
if GetItemTypeId(UnitItemInSlot(u, i)) == udg_DmgEvBracers then
set life = life*udg_DAMAGE_FACTOR_BRACERS //0.67
exitwhen true
endif
exitwhen i == 0
endloop
endif
set udg_DamageEventAmount = prevAmount*life
endif
set udg_DamageEventPrevAmt = prevAmount
set udg_DamageModifierEvent = 0.00
if not udg_DamageEventOverride then
set udg_DamageModifierEvent = 1.00
if not udg_DamageEventOverride then
set udg_DamageModifierEvent = 2.00
set udg_DamageModifierEvent = 3.00
endif
endif
set udg_DamageEventOverride = override
if udg_DamageEventAmount > 0.00 then
set udg_DamageModifierEvent = 4.00
endif
set udg_DamageModifierEvent = 0.00
if not udg_HideDamageFrom[GetUnitUserData(udg_DamageEventSource)] then
set udg_DamageEvent = 0.00
set udg_DamageEvent = 1.00
set udg_DamageEvent = 0.00
endif
call CheckDamagedLifeEvent(true) //in case the unit state event failed from a recursive damage event
//All events have run and the damage amount is finalized.
set life = GetWidgetLife(u)
set udg_DmgEvTrig = CreateTrigger()
call TriggerAddCondition(udg_DmgEvTrig, Filter(function PreCheckDamagedLifeEvent))
if not udg_IsDamageSpell then
if udg_DamageEventAmount != prevAmount then
set life = life + prevAmount - udg_DamageEventAmount
if GetUnitState(u, UNIT_STATE_MAX_LIFE) < life then
set udg_LastDamageHP = life - prevAmount
call UnitAddAbility(u, udg_DamageBlockingAbility)
endif
call SetWidgetLife(u, RMaxBJ(life, 0.42))
endif
call TriggerRegisterUnitStateEvent(udg_DmgEvTrig, u, UNIT_STATE_LIFE, LESS_THAN, RMaxBJ(0.41, life - prevAmount/2.00))
else
set udg_LastDamageHP = GetUnitState(u, UNIT_STATE_MAX_LIFE)
set prevLife = life
if life + prevAmount*0.75 > udg_LastDamageHP then
set life = RMaxBJ(udg_LastDamageHP - prevAmount/2.00, 1.00)
call SetWidgetLife(u, life)
set life = (life + udg_LastDamageHP)/2.00
else
set life = life + prevAmount*0.50
endif
set udg_LastDamageHP = prevLife - (prevAmount - (prevAmount - udg_DamageEventAmount))
call TriggerRegisterUnitStateEvent(udg_DmgEvTrig, u, UNIT_STATE_LIFE, GREATER_THAN, life)
endif
endif
set u = null
set f = null
return false
endfunction
function CreateDmgEvTrg takes nothing returns nothing
set udg_DamageEventTrigger = CreateTrigger()
call TriggerAddCondition(udg_DamageEventTrigger, Filter(function OnUnitDamage))
endfunction
function SetupDmgEv takes nothing returns boolean
local integer i = udg_UDex
local unit u
if udg_UnitIndexEvent == 1.00 then
set u = udg_UDexUnits[i]
if GetUnitAbilityLevel(u, 'Aloc') == 0 and TriggerEvaluate(gg_trg_Damage_Engine_Config) then
set udg_UnitDamageRegistered[i] = true
call TriggerRegisterUnitEvent(udg_DamageEventTrigger, u, EVENT_UNIT_DAMAGED)
call UnitAddAbility(u, udg_SpellDamageAbility)
call UnitMakeAbilityPermanent(u, true, udg_SpellDamageAbility)
endif
set u = null
else
set udg_HideDamageFrom[i] = false
if udg_UnitDamageRegistered[i] then
set udg_UnitDamageRegistered[i] = false
set udg_DamageEventsWasted = udg_DamageEventsWasted + 1
if udg_DamageEventsWasted == 32 then //After 32 registered units have been removed...
set udg_DamageEventsWasted = 0
//Rebuild the mass EVENT_UNIT_DAMAGED trigger:
call DestroyTrigger(udg_DamageEventTrigger)
call CreateDmgEvTrg()
set i = udg_UDexNext[0]
loop
exitwhen i == 0
if udg_UnitDamageRegistered[i] then
call TriggerRegisterUnitEvent(udg_DamageEventTrigger, udg_UDexUnits[i], EVENT_UNIT_DAMAGED)
endif
set i = udg_UDexNext[i]
endloop
endif
endif
endif
return false
endfunction
//===========================================================================
function InitTrig_Damage_Engine takes nothing returns nothing
local unit u = CreateUnit(Player(bj_PLAYER_NEUTRAL_EXTRA), 'uloc', 0, 0, 0)
local integer i = bj_MAX_PLAYERS //Fixed in 3.8
//Create this trigger with UnitIndexEvents in order add and remove units
//as they are created or removed.
local trigger t = CreateTrigger()
call TriggerRegisterVariableEvent(t, "udg_UnitIndexEvent", EQUAL, 1.00)
call TriggerRegisterVariableEvent(t, "udg_UnitIndexEvent", EQUAL, 2.00)
call TriggerAddCondition(t, Filter(function SetupDmgEv))
set t = null
//Run the configuration trigger to set all configurables:
if gg_trg_Damage_Engine_Config == null then
//It's possible this InitTrig_ function ran first, in which case use ExecuteFunc.
call ExecuteFunc("Trig_Damage_Engine_Config_Actions")
else
call TriggerExecute(gg_trg_Damage_Engine_Config)
endif
//Create trigger for storing all EVENT_UNIT_DAMAGED events.
call CreateDmgEvTrg()
//Create GUI-friendly trigger for cleaning up after UnitDamageTarget.
set udg_ClearDamageEvent = CreateTrigger()
call TriggerAddCondition(udg_ClearDamageEvent, Filter(function PreCheckDamagedLifeEvent))
//Disable SpellDamageAbility for every player.
loop
set i = i - 1
call SetPlayerAbilityAvailable(Player(i), udg_SpellDamageAbility, false)
exitwhen i == 0
endloop
//Preload abilities.
call UnitAddAbility(u, udg_DamageBlockingAbility)
call UnitAddAbility(u, udg_SpellDamageAbility)
call RemoveUnit(u)
set u = null
endfunction
//TESH.scrollpos=12
//TESH.alwaysfold=0
constant function GetAMSBuffId takes nothing returns integer
return 'Bams'
endfunction
constant function GetAMSAbilId takes nothing returns integer
return 'A03R'
endfunction
constant function GetAMSShieldVal takes nothing returns real
return 300.00
endfunction
function Trig_Anti_Magic_Shield_Fix_Actions takes nothing returns nothing
local integer id = GetUnitUserData(udg_DamageEventTarget)
local real shield = udg_AMSAmount[id]- udg_DamageEventAmount
if shield <= 0.00 then
set udg_DamageEventAmount = -shield
set shield = 0.00
call UnitRemoveAbility(udg_DamageEventTarget, GetAMSBuffId())
else
set udg_DamageEventAmount = 0.00
if udg_DamageEventType == 0 then
set udg_DamageEventType = udg_DamageTypeBlocked
endif
endif
set udg_AMSAmount[id] = shield
endfunction
function Trig_Anti_Magic_Shield_Fix_Conditions takes nothing returns boolean
if udg_IsDamageSpell then
if GetUnitAbilityLevel(udg_DamageEventTarget, GetAMSBuffId()) > 0 then
call Trig_Anti_Magic_Shield_Fix_Actions()
else
set udg_AMSAmount[GetUnitUserData(udg_DamageEventTarget)] = 0.00
endif
endif
return false
endfunction
function AMS_Refresh_Conditions takes nothing returns boolean
if GetSpellAbilityId() == GetAMSAbilId() then
set udg_AMSAmount[GetUnitUserData(GetSpellTargetUnit())] = GetAMSShieldVal()
endif
return false
endfunction
function InitTrig_Anti_Magic_Shield_Fix takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterVariableEvent(t, "udg_DamageModifierEvent", EQUAL, 4.00)
call TriggerAddCondition(t, Condition(function Trig_Anti_Magic_Shield_Fix_Conditions))
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Filter(function AMS_Refresh_Conditions))
endfunction
//===========================================================================
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 = udg_CheckDeathList[0]
local integer j
set udg_CheckDeathList[0] = -1
loop
exitwhen i == -1
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 j = udg_CheckDeathList[i]
set udg_CheckDeathList[i] = -1
set i = j
endloop
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 udg_CheckDeathList[i] == -1 then
set udg_CheckDeathList[i] = udg_CheckDeathList[0]
set udg_CheckDeathList[0] = i
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_CheckDeathList[i] = -1
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] = -1
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
//TESH.scrollpos=24
//TESH.alwaysfold=0
globals
unit array spellCaster
unit array spellTargetUnit
group array spellGroupVictims
integer array spellCounter
real array spellDuration
group array spellGroup
timer array spellTimer
real array spellRadius
integer array spellLevel
group ug=CreateGroup()
constant integer DUMMY = 'n00A' //universal dummy for many spells
unit g_tempTarget = null
hashtable g_hash1
endglobals
function Trig_Vars_Actions takes nothing returns nothing
set spellGroup[1] = CreateGroup()
set spellTimer[1] = CreateTimer()
set spellGroup[2] = CreateGroup()
set spellTimer[2] = CreateTimer()
endfunction
//===========================================================================
function InitTrig_Vars takes nothing returns nothing
set g_hash1 = InitHashtable()
// save FelFevor data:
call SaveInteger(g_hash1, 'h001', 1, 'A001') // Initiate unit , ABI_FEL_BARRAGE
call SaveInteger(g_hash1, 'h004', 1, 'A02L') // Vanguard unit , ABI_LINGERING_STRENGTH new
call SaveInteger(g_hash1, 'h00S', 1, 'A00H') // Neophyte unit , ABI_BLOOD_CORD
call SaveInteger(g_hash1, 'h00V', 1, 'A00J') // Doomguard unit , ABI_UNLEASH_POWER
call SaveInteger(g_hash1, 'h00R', 1, 'A00J') // Doomguard unit - Demonsight , ABI_UNLEASH_POWER
call SaveInteger(g_hash1, 'h003', 1, 'A005') // Falconeer unit , ABI_SHADOW_PASSERINE
call SaveInteger(g_hash1, 'h00A', 1, 'A00W') // Oculist unit , ABI_OCULIST_ATTACK_RATE
call SaveInteger(g_hash1, 'h002', 1, 'A008') // Bloodwarder unit , ABI_CHAOTIC_ENERGIES
call SaveInteger(g_hash1, 'h002', 2, 'A007') // Bloodwarder unit , ABI_ACURSED_AEGIS
call SaveInteger(g_hash1, 'h002', 3, 'A006') // Bloodwarder unit , ABI_WRITHE_OF_AGONY
call SaveInteger(g_hash1, 'h007', 1, 'A00O') // Cabalist unit , ABI_STOLEN_POWER
call SaveInteger(g_hash1, 'h007', 2, 'A00M') // Cabalist unit , ABI_CURSE_OF_FRAGILITY
call SaveInteger(g_hash1, 'h007', 3, 'A00N') // Cabalist unit , ABI_DESTRUCTIVE_FIRES
call SaveInteger(g_hash1, 'h008', 1, 'A00E') // Demonologist unit , ABI_HAND_OF_DOOM
call SaveInteger(g_hash1, 'h008', 2, 'A00F') // Demonologist unit , ABI_FIENDISH_SHELL
call SaveInteger(g_hash1, 'h008', 3, 'A00C') // Demonologist unit , ABI_ENSLAVE_DEMON
call SaveInteger(g_hash1, 'h005', 1, 'A013') // Reclaimer unit , ABI_ABSOLUTION_CIRCLE
call SaveInteger(g_hash1, 'h005', 2, 'A014') // Reclaimer unit , ABI_DARK_LESSONS
call SaveInteger(g_hash1, 'h00B', 1, 'A011') // Reconnoiteirer unit , ABI_SPAWN_DECREP
call SaveInteger(g_hash1, 'h00B', 2, 'A00Y') // Reconnoiteirer unit , ABI_UNGODLY_CHAINS
call SaveInteger(g_hash1, 'h006', 1, 'A01E') // Siphoner unit , ABI_SLEEPING_MANA
call Trig_Vars_Actions()
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
globals
constant integer ABI_BANEOFHAVOC = 'A00V' //"bloodlust" based, 30sec
constant integer ABI_FELFERVOR = 'A01N' //30sec
constant integer ABI_FELFERVOR_ITEM = 'A02V' //120sec <---
constant integer ABI_FELFERVOR_WREATHING = 'A01C' //30sec
constant integer BUFF_FELFERVOR = 'B000'
endglobals
//----------------------------------------------------------------------------------
//----------------------------------------------------------------------------------
function Trig_FelFevor_Conditions takes nothing returns boolean
local integer s=GetSpellAbilityId()
return s==ABI_BANEOFHAVOC or s==ABI_FELFERVOR or s==ABI_FELFERVOR_ITEM or s==ABI_FELFERVOR_WREATHING
endfunction
//----------------------------------------------------------------------------------
function FelFevor_LoopEnum takes nothing returns nothing
local unit d = GetEnumUnit()
local integer id = GetUnitUserData(d)
local integer unitId
if (spellCounter[id]>1) and GetUnitAbilityLevel(spellTargetUnit[id], BUFF_FELFERVOR)==0 then
set spellDuration[id] = 0.00
endif
//---
set spellCounter[id] = spellCounter[id] + 1
set spellDuration[id] = spellDuration[id] - 1.00
if spellDuration[id] <= 0.00 then // Clean up any data attached to this spell
//set bonuses to level 1
set unitId=GetUnitTypeId(spellTargetUnit[id])
call SetUnitAbilityLevel(spellTargetUnit[id], LoadInteger(g_hash1, unitId, 1), 1)
call SetUnitAbilityLevel(spellTargetUnit[id], LoadInteger(g_hash1, unitId, 2), 1)
call SetUnitAbilityLevel(spellTargetUnit[id], LoadInteger(g_hash1, unitId, 3), 1)
set spellTargetUnit[id]=null
call GroupRemoveUnit(spellGroup[1], d)
call RemoveUnit(d)
if FirstOfGroup(spellGroup[1]) == null then
call PauseTimer(spellTimer[1])
endif
endif
set d=null
endfunction
//---
function FelFevor_Loop takes nothing returns nothing
call ForGroup(spellGroup[1], function FelFevor_LoopEnum)
endfunction
//----------------------------------------------------------------------------------
//----------------------------------------------------------------------------------
function FelFevor_UpdateDuration takes nothing returns nothing
local integer id = GetUnitUserData(GetEnumUnit())
if spellTargetUnit[id]==g_tempTarget then
set spellDuration[id] = 120.00 //longest duration possible
endif
endfunction
//----------------------------------------------------------------------------------
function FelFevor_OnCast takes nothing returns nothing
local unit target=GetSpellTargetUnit()
local integer id
local integer unitId
set g_tempTarget = target
if GetUnitAbilityLevel(g_tempTarget, BUFF_FELFERVOR)>0 then
call ForGroup(spellGroup[1], function FelFevor_UpdateDuration)
else //start new instance:
set bj_lastCreatedUnit = CreateUnit(GetOwningPlayer(GetTriggerUnit()), DUMMY, GetUnitX(target), GetUnitY(target), 0.00)
set id = GetUnitUserData(bj_lastCreatedUnit)
set spellCounter[id] = 0
set spellDuration[id] = 120.00 //longest possible duration
set spellTargetUnit[id] = target
//set bonuses to level 2
set unitId=GetUnitTypeId(spellTargetUnit[id])
call SetUnitAbilityLevel(spellTargetUnit[id], LoadInteger(g_hash1, unitId, 1), 2)
call SetUnitAbilityLevel(spellTargetUnit[id], LoadInteger(g_hash1, unitId, 2), 2)
call SetUnitAbilityLevel(spellTargetUnit[id], LoadInteger(g_hash1, unitId, 3), 2)
//---
if FirstOfGroup(spellGroup[1]) == null then
call TimerStart(spellTimer[1], 1.00, true, function FelFevor_Loop)
endif
call GroupAddUnit(spellGroup[1], bj_lastCreatedUnit)
endif
set target=null
endfunction
//===========================================================================
function InitTrig_FelFevor takes nothing returns nothing
set gg_trg_FelFevor = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_FelFevor, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_FelFevor, Condition( function Trig_FelFevor_Conditions ) )
call TriggerAddAction( gg_trg_FelFevor, function FelFevor_OnCast)
endfunction
//TESH.scrollpos=-1
//TESH.alwaysfold=0
//This part is where you can configure the spell.
scope Dash initializer Init
globals
//Configurables
integer Rush = 'A05W' //This is the ability id the spell uses. Change it after copying the trigger.
real Speed = 1150 //This is the speed of the caster when he uses the spell.
real Interval = .03 //How often you want the timer to run.
real Range = 175 //How close units should be to be damaged by the spell.
boolean UnitOrSfx = false //This decides if you want to use a dummy unit or sfx as the well...sfx of the spell. False for sfx, true for dummy unit.
integer Transparency = 80 //How transparent you want the dummy to be.
integer RushDummy = 'e00V' // This is the id of the dummy unit created.
real Lifespan = 0.5 // Life span of the dummy.
string Sfx = "Valiant Charge Void.mdx" //The sfx that appears when the caster dashes.
string Animation = "attack 2" //What animation plays when the caster dashes.
real DamageBase = 75 //This is the base damage which will be multiplied by the ability level.
integer R = 255 //This is the red value for the dummy unit.
integer G = 255 //This is the blue value for the dummy unit.
integer B = 255 //This is the green value for the dummy unit.
real AbilDist = 200 //This is the distance that scales per level of ability. Set BonusDist to 0 if you want a pure level based distance.
real BonusDist = 100 // This is the bonus distance. Set AbilDist to 0 if you want constant distant.
attacktype AttackType = ATTACK_TYPE_CHAOS //The attack type.
damagetype DamageType = DAMAGE_TYPE_UNIVERSAL //The damage type. They're both currently set to these configurations to allow easy testing.
//Non-configurables
group RushGroup = CreateGroup() //Don't touch this. Don't null or destroy this.
real Offset = Speed * Interval //How far the caster moves per interval.
endglobals
//------Configurable functions------//
//Configure the conditions for group check here
function UnitCheck takes unit caster, unit u returns boolean
return IsUnitEnemy(u, GetOwningPlayer(caster)) and not (IsUnitType(u, UNIT_TYPE_DEAD) and GetUnitTypeId(u) != 0) and IsUnitType(u, UNIT_TYPE_GROUND) and not IsUnitType(u, UNIT_TYPE_STRUCTURE)
endfunction
//The Damage formula for the ability.
function Damage takes unit caster, integer Rush, real BaseDamage returns real
return GetUnitAbilityLevel(caster, Rush) * BaseDamage
endfunction
//Formula for the maximum distance. If you only want the ability to affect distance, set BonusDist to 0.
function MaximumDistance takes unit caster, integer Rush, real AbilDist, real BonusDist returns real
return GetUnitAbilityLevel(caster, Rush) * AbilDist + BonusDist
endfunction
//---End of Configurable functions---//
function Rush_Periodic takes nothing returns nothing
//Local Variable Setup
local timer t = GetExpiredTimer()
local integer id = GetHandleId(t)
local unit caster = LoadUnitHandle(udg_Rush_Hash, id, 0)
local real facing = LoadReal(udg_Rush_Hash, id, 1)
local real cur_dist = LoadReal(udg_Rush_Hash, id, 2)
local group g = LoadGroupHandle(udg_Rush_Hash, id, 3)
local real x = GetUnitX(caster)
local real y = GetUnitY(caster)
local real x1 = x + Offset * Cos(facing)
local real y1 = y + Offset * Sin(facing)
local player owner = GetOwningPlayer(caster)
local unit dummy
local unit u
local real damage = Damage(caster, Rush, DamageBase) //You can change this to whatever you want.
local real MaxDistance = MaximumDistance(caster, Rush, AbilDist, BonusDist) //This makes the distance you dash scale with the level.
if cur_dist < MaxDistance then
call SetUnitAnimation(caster, Animation)
if not UnitOrSfx then
call DestroyEffect(AddSpecialEffect(Sfx, x, y))
else
set dummy = CreateUnit(owner, RushDummy, x, y, facing)
call SetUnitAnimation(dummy, Animation)
call SetUnitVertexColor(dummy, R, G, B, Transparency)
call UnitApplyTimedLife(dummy, 'BTLF', Lifespan)
set dummy = null
endif
call GroupEnumUnitsInRange(RushGroup, x, y, Range, null)
loop //What we do here is check if the target is in g. If not, then we damage it and add it to g to prevent it from being damaged again.
set u = FirstOfGroup(RushGroup)
exitwhen u == null
if not IsUnitInGroup(u, g) and UnitCheck(caster, u) then
call UnitDamageTarget(caster, u, damage, false, false, AttackType, DamageType, null)
call GroupAddUnit(g, u)
endif
call GroupRemoveUnit(RushGroup, u)
endloop
if IsTerrainWalkable(x1, y1) then //If the terrain is passable the you'll dash, if not then trigger ends.
call SetUnitX(caster, x1)
call SetUnitY(caster, y1)
set cur_dist = cur_dist + Offset //This counts how many times you've moved.
call SaveReal(udg_Rush_Hash, id, 2, cur_dist)
else
call PauseTimer(t)
call DestroyTimer(t)
call DestroyGroup(g)
call SetUnitAnimation(caster, "stand") //Resets the animation.
call FlushChildHashtable(udg_Rush_Hash, id)
endif
else
call PauseTimer(t)
call DestroyTimer(t)
call DestroyGroup(g)
call SetUnitAnimation(caster, "stand") //Resets the animation.
call FlushChildHashtable(udg_Rush_Hash, id)
endif
//Nulling
set t = null
set caster = null
set g = null
endfunction
function Rush_Actions takes nothing returns nothing
//Local Variable Setup
local timer t = CreateTimer()
local integer id = GetHandleId(t)
local unit caster = GetTriggerUnit()
local real dx = GetSpellTargetX() - GetUnitX(caster)
local real dy = GetSpellTargetY() - GetUnitY(caster)
local real dist_check = (dx*dx) + (dy*dy)
local real facing
//A little distance check to avoid bugs when you cast the spell in your current position.
if dist_check <= 100 * 100 then
set facing = GetUnitFacing(caster) * bj_DEGTORAD
else
set facing = (Atan2(dy, dx))
endif
//Hashtable Setup
call SaveUnitHandle(udg_Rush_Hash, id, 0, caster)
call SaveReal(udg_Rush_Hash, id, 1, facing)
call SaveReal(udg_Rush_Hash, id, 2, 0)
call SaveGroupHandle(udg_Rush_Hash, id, 3, CreateGroup())
//End Hashtable Setup
call TimerStart(t, Interval, true, function Rush_Periodic)
//Nulling
set t = null
set caster = null
endfunction
function Rush_Conditions takes nothing returns boolean
if GetSpellAbilityId() == Rush then
call Rush_Actions()
endif
return false
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger t = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( t, Condition( function Rush_Conditions) )
set udg_Rush_Hash = InitHashtable()
set t = null
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//
// PORTAL SYSTEM v2.5 by Spellbound
//
// The Portal System allows you to teleport your units from one portal to another. Use the Connect Portal skill to link two Portals - this means Portals are buildable.
// A Portal that is already connected can connect to one that is not active, thus disconnecting from it's current counterpart to connect to the new one. You can make teleportation
// work via missiles (that can be configured to be killable) or have delays before teleporting. Check out the Demo Portal folder for templates to use. Conncet Portal 1 has
// detailed explanation on each variable.
//
// Also, reciever Portals will make your units move to their rally points if they have one.
//
//
// REQUIRED:
// Unit Indexer, by Bribe http://www.hiveworkshop.com/forums/spells-569/gui-unit-indexer-1-2-0-2-a-197329/
//
//
// INSTALLATION:
// - Make sure that in File > Preferences > General, the box next to 'Automatically create unknown variables while pasting trigger data' is ticked.
// Then copy the Variable Creator trigger to your map so that the variables are automatically generated. You may then delete it.
// - Copy the Requirements folder to your map.
// - Copy the Sever Connection ability to you map.
// - Unless you already have a dummy unit, import the dummy.mdx model by Vexorian and copy one or all of the Portal Carrier (Dummy Unit - [type]) from this map to yours.
// - Your dummies must have storm crow form if you do not use GUI Auto Fly or Auto Fly
// - Copy the Portals folder to your map.
// - In Portal Connect, set Portal_SeverAbility to Sever Connection (Required) or any non-target spell you want your portals to use to disconnect from a sister portal.
// - Copy any of the four templates (recommended) alongside their corresponding abilities in the Object Editor (always copy units/abilities before triggers).
// For example, Connect Portal 1 uses delayFX - Connect Portal 1 and FX - Blue Energy in it's setup. It also uses a flying dummy unit, so copy that as well if
// you don't have a dummy unit.
// - Save your map.
// You're all done!
//
//
// CUSTOMISATION:
// - All customisation is done in the Connect Portal triggers in the Template folder. In there you may change the various special effects for departure/arrival
// fx, active portal fx, the range at which the portal may catch units to teleport, allowing allies through or not, the use of a missile to carry the units,
// it's height, and what unit will that missile be. The latter means you can chose to have a missile that can be shot down, effectively terminating the
// teleportation prematurely. Keep in mind while I have not put in conditions to prevent flying units from using the Portals, the special effect will display
// at their location, at ground level. If this bothers you, consider using flying dummy units to which you attach a special effect. You'll have to modify
// Portal Periodic for that.
// - Connect Portal 1 - 4 are template triggers. Consider copy/pasting them to your map, and then modifying their configurables.
//
//
// SPECIAL THANKS:
// Bribe, for his wonderful Unit Indexer and letting me know that detecting pathing would be very annoying to deal with in-game :P
//
//
// VARIABLES:
// Portal_activeFX - this is the special effect that will attach to your active Portals. The effect can be changed in Connect Portal.
// Portal_departureFX - this is the special effect that plays when a unit uses a Portal. The effect can be changed in Connect Portal.
// Portal_arrivalFX - this is the special effect that plays when a unit exits a Portal. The effect can be changed in Connect Portal.
// Portal_range - that's the range at which the Portals will pick unit for teleportation.
// Portal_delay - whether you Portals have a delay before they teleport units. Units that move outside their reach (like through knockback)
// will automatically reingage the Portal. If set to 0, the teleportation is instantaneous.
// Portal_delayFXAbil - this is an ability that carries the special effects to apply on your units when there is a delay, to indicate teleportation
// has started. I use an ability here instead of a special effect because abilities can have up to 6 effects, each with their own attachment
// points if you so desire.
// Portal_missileSpeed - if set to 0 or lower, the teleportation is instantaneous. Otherwise, will shoot a missile that will teleport
// units when it reaches the sister Portal. If sister Portal is destroyed before it's reached, the missile and unit is carries
// are both killed.
// Portal_missileDummy - this is the dummy unit that will serve as your missile. I made this configurable in case you would want to have missiles
// that can be destroyed or have missiles that have to walk to the sister Portal. Refer to Connect Portal 3 and 4.
// Portal_missileHeight - the height of your missile. If missile speed is 0 or lower, this does nothing.
// Portal_missileFXAbil - this is ability that carries the special effects of your missile. Can be overlooked if your dummy unit has a
// model already.
// Portal_preventAllies - setting this to TRUE will prevent allies from using your Portal.
// Portal_missileTargetable - setting this to TRUE will remove locust from your missile units, making them targetable.
// Portal_missileUseOwnMovement - setting this to TRUE will order the missile to move instead of moving them by triggers. This is useful if you want
// your missile to respect pathing.
//
// The rest of the variables should not be meddled with.
//
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library TerrainPathability initializer Init
//******************************************************************************
//* BY: Rising_Dusk
//*
//* This script can be used to detect the type of pathing at a specific point.
//* It is valuable to do it this way because the IsTerrainPathable is very
//* counterintuitive and returns in odd ways and aren't always as you would
//* expect. This library, however, facilitates detecting those things reliably
//* and easily.
//*
//******************************************************************************
//*
//* > function IsTerrainDeepWater takes real x, real y returns boolean
//* > function IsTerrainShallowWater takes real x, real y returns boolean
//* > function IsTerrainLand takes real x, real y returns boolean
//* > function IsTerrainPlatform takes real x, real y returns boolean
//* > function IsTerrainWalkable takes real x, real y returns boolean
//*
//* These functions return true if the given point is of the type specified
//* in the function's name and false if it is not. For the IsTerrainWalkable
//* function, the MAX_RANGE constant below is the maximum deviation range from
//* the supplied coordinates that will still return true.
//*
//* The IsTerrainPlatform works for any preplaced walkable destructable. It will
//* return true over bridges, destructable ramps, elevators, and invisible
//* platforms. Walkable destructables created at runtime do not create the same
//* pathing hole as preplaced ones do, so this will return false for them. All
//* other functions except IsTerrainWalkable return false for platforms, because
//* the platform itself erases their pathing when the map is saved.
//*
//* After calling IsTerrainWalkable(x, y), the following two global variables
//* gain meaning. They return the X and Y coordinates of the nearest walkable
//* point to the specified coordinates. These will only deviate from the
//* IsTerrainWalkable function arguments if the function returned false.
//*
//* Variables that can be used from the library:
//* [real] TerrainPathability_X
//* [real] TerrainPathability_Y
//*
globals
private constant real MAX_RANGE = 10.
private constant integer DUMMY_ITEM_ID = 'wolg'
endglobals
globals
private item Item = null
private rect Find = null
private item array Hid
private integer HidMax = 0
public real X = 0.
public real Y = 0.
endglobals
function IsTerrainDeepWater takes real x, real y returns boolean
return not IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY) and IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY)
endfunction
function IsTerrainShallowWater takes real x, real y returns boolean
return not IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY) and not IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY) and IsTerrainPathable(x, y, PATHING_TYPE_BUILDABILITY)
endfunction
function IsTerrainLand takes real x, real y returns boolean
return IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY)
endfunction
function IsTerrainPlatform takes real x, real y returns boolean
return not IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY) and not IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY) and not IsTerrainPathable(x, y, PATHING_TYPE_BUILDABILITY)
endfunction
private function HideItem takes nothing returns nothing
if IsItemVisible(GetEnumItem()) then
set Hid[HidMax] = GetEnumItem()
call SetItemVisible(Hid[HidMax], false)
set HidMax = HidMax + 1
endif
endfunction
function IsTerrainWalkable takes real x, real y returns boolean
//Hide any items in the area to avoid conflicts with our item
call MoveRectTo(Find, x, y)
call EnumItemsInRect(Find ,null, function HideItem)
//Try to move the test item and get its coords
call SetItemPosition(Item, x, y) //Unhides the item
set X = GetItemX(Item)
set Y = GetItemY(Item)
static if LIBRARY_IsTerrainWalkable then
//This is for compatibility with the IsTerrainWalkable library
set IsTerrainWalkable_X = X
set IsTerrainWalkable_Y = Y
endif
call SetItemVisible(Item, false)//Hide it again
//Unhide any items hidden at the start
loop
exitwhen HidMax <= 0
set HidMax = HidMax - 1
call SetItemVisible(Hid[HidMax], true)
set Hid[HidMax] = null
endloop
//Return walkability
return (X-x)*(X-x)+(Y-y)*(Y-y) <= MAX_RANGE*MAX_RANGE and not IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY)
endfunction
private function Init takes nothing returns nothing
set Find = Rect(0., 0., 128., 128.)
set Item = CreateItem(DUMMY_ITEM_ID, 0, 0)
call SetItemVisible(Item, false)
endfunction
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
//This part is where you can configure the spell.
globals
//Configurables
integer Rush = 'A05W' //This is the ability id the spell uses. Change it after copying the trigger.
real Speed = 1150 //This is the speed of the caster when he uses the spell.
real Interval = .03 //How often you want the timer to run.
real Range = 175 //How close units should be to be damaged by the spell.
boolean UnitOrSfx = false //This decides if you want to use a dummy unit or sfx as the well...sfx of the spell. False for sfx, true for dummy unit.
integer Transparency = 80 //How transparent you want the dummy to be.
integer RushDummy = 'e00V' // This is the id of the dummy unit created.
real Lifespan = 0.5 // Life span of the dummy.
string Sfx = "Abilities\\Spells\\Orc\\MirrorImage\\MirrorImageCaster.mdl" //The sfx that appears when the caster dashes.
string Animation = "spell special" //What animation plays when the caster dashes.
real DamageBase = 75 //This is the base damage which will be multiplied by the ability level.
integer R = 255 //This is the red value for the dummy unit.
integer G = 255 //This is the blue value for the dummy unit.
integer B = 255 //This is the green value for the dummy unit.
real AbilDist = 400 //This is the distance that scales per level of ability. Set BonusDist to 0 if you want a pure level based distance.
real BonusDist = 200 // This is the bonus distance. Set AbilDist to 0 if you want constant distant.
attacktype AttackType = ATTACK_TYPE_CHAOS //The attack type.
damagetype DamageType = DAMAGE_TYPE_UNIVERSAL //The damage type. They're both currently set to these configurations to allow easy testing.
//Non-configurables
group RushGroup = CreateGroup() //Don't touch this. Don't null or destroy this.
real Offset = Speed * Interval //How far the caster moves per interval.
endglobals
//------Configurable functions------//
//Configure the conditions for group check here
function UnitCheck takes unit caster, unit u returns boolean
return IsUnitEnemy(u, GetOwningPlayer(caster)) and not (IsUnitType(u, UNIT_TYPE_DEAD) and GetUnitTypeId(u) != 0) and IsUnitType(u, UNIT_TYPE_GROUND) and not IsUnitType(u, UNIT_TYPE_STRUCTURE)
endfunction
//The Damage formula for the ability.
function Damage takes unit caster, integer Rush, real BaseDamage returns real
return GetUnitAbilityLevel(caster, Rush) * BaseDamage
endfunction
//Formula for the maximum distance. If you only want the ability to affect distance, set BonusDist to 0.
function MaximumDistance takes unit caster, integer Rush, real AbilDist, real BonusDist returns real
return GetUnitAbilityLevel(caster, Rush) * AbilDist + BonusDist
endfunction
//---End of Configurable functions---//
function Rush_Periodic takes nothing returns nothing
//Local Variable Setup
local timer t = GetExpiredTimer()
local integer id = GetHandleId(t)
local unit caster = LoadUnitHandle(udg_Rush_Hash, id, 0)
local real facing = LoadReal(udg_Rush_Hash, id, 1)
local real cur_dist = LoadReal(udg_Rush_Hash, id, 2)
local group g = LoadGroupHandle(udg_Rush_Hash, id, 3)
local real x = GetUnitX(caster)
local real y = GetUnitY(caster)
local real x1 = x + Offset * Cos(facing)
local real y1 = y + Offset * Sin(facing)
local player owner = GetOwningPlayer(caster)
local unit dummy
local unit u
local real damage = Damage(caster, Rush, DamageBase) //You can change this to whatever you want.
local real MaxDistance = MaximumDistance(caster, Rush, AbilDist, BonusDist) //This makes the distance you dash scale with the level.
if cur_dist < MaxDistance then
call SetUnitAnimation(caster, Animation)
if not UnitOrSfx then
call DestroyEffect(AddSpecialEffect(Sfx, x, y))
else
set dummy = CreateUnit(owner, RushDummy, x, y, facing)
call SetUnitAnimation(dummy, Animation)
call SetUnitVertexColor(dummy, R, G, B, Transparency)
call UnitApplyTimedLife(dummy, 'BTLF', Lifespan)
set dummy = null
endif
call GroupEnumUnitsInRange(RushGroup, x, y, Range, null)
loop //What we do here is check if the target is in g. If not, then we damage it and add it to g to prevent it from being damaged again.
set u = FirstOfGroup(RushGroup)
exitwhen u == null
if not IsUnitInGroup(u, g) and UnitCheck(caster, u) then
call UnitDamageTarget(caster, u, damage, false, false, AttackType, DamageType, null)
call GroupAddUnit(g, u)
endif
call GroupRemoveUnit(RushGroup, u)
endloop
if IsTerrainPathable(x1, y1, PATHING_TYPE_WALKABILITY) then //If the terrain is passable the you'll dash, if not then trigger ends.
call SetUnitX(caster, x1)
call SetUnitY(caster, y1)
set cur_dist = cur_dist + Offset //This counts how many times you've moved.
call SaveReal(udg_Rush_Hash, id, 2, cur_dist)
else
call PauseTimer(t)
call DestroyTimer(t)
call DestroyGroup(g)
call SetUnitAnimation(caster, "stand") //Resets the animation.
call FlushChildHashtable(udg_Rush_Hash, id)
endif
else
call PauseTimer(t)
call DestroyTimer(t)
call DestroyGroup(g)
call SetUnitAnimation(caster, "stand") //Resets the animation.
call FlushChildHashtable(udg_Rush_Hash, id)
endif
//Nulling
set t = null
set caster = null
set g = null
endfunction
function Rush_Actions takes nothing returns nothing
//Local Variable Setup
local timer t = CreateTimer()
local integer id = GetHandleId(t)
local unit caster = GetTriggerUnit()
local real dx = GetSpellTargetX() - GetUnitX(caster)
local real dy = GetSpellTargetY() - GetUnitY(caster)
local real dist_check = (dx*dx) + (dy*dy)
local real facing
//A little distance check to avoid bugs when you cast the spell in your current position.
if dist_check <= 100 * 100 then
set facing = GetUnitFacing(caster) * bj_DEGTORAD
else
set facing = (Atan2(dy, dx))
endif
//Hashtable Setup
call SaveUnitHandle(udg_Rush_Hash, id, 0, caster)
call SaveReal(udg_Rush_Hash, id, 1, facing)
call SaveReal(udg_Rush_Hash, id, 2, 0)
call SaveGroupHandle(udg_Rush_Hash, id, 3, CreateGroup())
//End Hashtable Setup
call TimerStart(t, Interval, true, function Rush_Periodic)
//Nulling
set t = null
set caster = null
endfunction
function Rush_Conditions takes nothing returns boolean
if GetSpellAbilityId() == Rush then
call Rush_Actions()
endif
return false
endfunction
//===========================================================================
function InitTrig_Rush takes nothing returns nothing
local trigger t = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( t, Condition( function Rush_Conditions) )
set udg_Rush_Hash = InitHashtable()
set t = null
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
// 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
//TESH.scrollpos=0
//TESH.alwaysfold=0
function IsUnitMovementTracked takes integer i returns boolean
return udg_UMovPrev[i] != 0 or udg_UMovNext[0] == i
endfunction
function UnitMovementRegister takes nothing returns boolean
local integer i = udg_UDex
if not IsUnitMovementTracked(i) and TriggerEvaluate(gg_trg_Is_Unit_Moving_Config) then
set udg_UMovPrev[udg_UMovNext[0]] = i
set udg_UMovNext[i] = udg_UMovNext[0]
set udg_UMovNext[0] = i
set udg_UnitMovingX[i] = GetUnitX(udg_UDexUnits[i])
set udg_UnitMovingY[i] = GetUnitY(udg_UDexUnits[i])
endif
return false
endfunction
function UnitMovementUnregister takes nothing returns boolean
local integer i = udg_UDex
if IsUnitMovementTracked(i) then
set udg_UnitMoving[i] = false
set udg_UMovNext[udg_UMovPrev[i]] = udg_UMovNext[i]
set udg_UMovPrev[udg_UMovNext[i]] = udg_UMovPrev[i]
set udg_UMovPrev[i] = 0
endif
return false
endfunction
function RunUnitMovementEvent takes integer i, real e returns nothing
local integer pdex = udg_UDex
if e == 1.00 then
set udg_UnitMoving[i] = true
else
set udg_UnitMoving[i] = false
endif
set udg_UDex = i
set udg_UnitMovingEvent = e
set udg_UnitMovingEvent = 0.00
set udg_UDex = pdex
endfunction
//===========================================================================
// This function runs periodically to check if units are actually moving.
//
function UnitMovementTracker takes nothing returns nothing
local integer i = 0
local integer n
local real x
local real y
loop
set i = udg_UMovNext[i]
exitwhen i == 0
set x = GetUnitX(udg_UDexUnits[i])
set y = GetUnitY(udg_UDexUnits[i])
if x != udg_UnitMovingX[i] or y != udg_UnitMovingY[i] then
set udg_UnitMovingX[i] = x
set udg_UnitMovingY[i] = y
if not udg_UnitMoving[i] then
if GetUnitTypeId(udg_UDexUnits[i]) != 0 then
call RunUnitMovementEvent(i, 1.00)
else
set n = udg_UDex
set udg_UDex = i
set i = udg_UMovPrev[i] //avoid skipping checks
call UnitMovementUnregister()
set udg_UDex = n
endif
endif
elseif udg_UnitMoving[i] then
call RunUnitMovementEvent(i, 2.00)
endif
endloop
endfunction
//===========================================================================
function InitTrig_Is_Unit_Moving takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterVariableEvent(t, "udg_UnitIndexEvent", EQUAL, 1.00)
call TriggerAddCondition(t, Filter(function UnitMovementRegister))
set t = CreateTrigger()
call TriggerRegisterVariableEvent(t, "udg_UnitIndexEvent", EQUAL, 2.00)
call TriggerAddCondition(t, Filter(function UnitMovementUnregister))
if gg_trg_Is_Unit_Moving_Config != null then
call TriggerExecute(gg_trg_Is_Unit_Moving_Config)
else
call ExecuteFunc("Trig_Is_Unit_Moving_Config_Actions")
endif
call TimerStart(CreateTimer(), udg_UnitMovementInterval, true, function UnitMovementTracker)
endfunction
library SetupHumans uses CustomVictoryDefeat
globals
// CONFIG
private race RACE = RACE_HUMAN
private string CHOICE_STRING = "Play as Felblood Elves?"
private integer BASE_WORKER = 'hpea'
private integer NEW_WORKER = 'h000'
private integer BASE_HALL = 'htow'
private integer NEW_HALL = 'h00C'
// END CONFIG
private dialog array Choice
private button array Yes
private button array No
private trigger array DialogTrigger
private hashtable Hash = InitHashtable()
endglobals
private function DialogClicked takes nothing returns nothing
local trigger trig = GetTriggeringTrigger()
local integer trigId = GetHandleId(trig)
local integer i = LoadInteger(Hash, trigId, 0)
local player play = Player(i)
local group g
local unit u
if GetClickedButton() == Yes[i] then
set g = CreateGroup()
call GroupEnumUnitsOfPlayer(g, play, null)
loop
set u = FirstOfGroup(g)
exitwhen u == null
call GroupRemoveUnit(g, u)
if GetUnitTypeId(u) == BASE_WORKER and GetOwningPlayer(u) == play then
call ReplaceUnitBJ(u, NEW_WORKER, bj_UNIT_STATE_METHOD_RELATIVE)
elseif GetUnitTypeId(u) == BASE_HALL and GetOwningPlayer(u) == play then
call RemoveUnit(u)
call CreateUnit(play, NEW_HALL, GetPlayerStartLocationX(play), GetPlayerStartLocationY(play), bj_UNIT_FACING)
endif
endloop
call DestroyGroup(g)
endif
call FlushChildHashtable(Hash, trigId)
call DialogDestroy(Choice[i])
endfunction
public function Actions takes nothing returns nothing
local integer i = 0 // player 1 starts at 0 in JASS
local player play
local dialog diag
loop
set play = Player(i)
if GetPlayerController(play) == MAP_CONTROL_USER and GetPlayerRace(play) == RACE then
set diag = DialogCreate()
set Choice[i] = diag
call DialogSetMessage(diag, CHOICE_STRING)
set Yes[i] = DialogAddButton(diag, "Yes", 0)
set No[i] = DialogAddButton(diag, "No", 0)
set DialogTrigger[i] = CreateTrigger()
call TriggerRegisterDialogEvent(DialogTrigger[i], diag)
call TriggerAddAction(DialogTrigger[i], function DialogClicked)
call SaveInteger(Hash, GetHandleId(DialogTrigger[i]), 0, i)
call DialogDisplay(play, diag, true)
endif
call SetPlayerMaxHeroesAllowed(3, play)
set i = i + 1
exitwhen i > bj_MAX_PLAYER_SLOTS
endloop
call MeleeInitVictoryDefeatCustomized()
call MeleeStartingAI()
call MeleeStartingVisibility()
set diag = null
endfunction
endlibrary
library SetupNightElves uses CustomVictoryDefeat
globals
// CONFIG
private race RACE = RACE_NIGHTELF
private string CHOICE_STRING = "Play as Void Elves?"
private integer BASE_WORKER = 'ewsp'
private integer NEW_WORKER = 'e00E'
private integer BASE_HALL = 'etol'
private integer NEW_HALL = 'h014'
private integer NEW_SCION = 'e00J'
// END CONFIG
private dialog array Choice
private button array Yes
private button array No
private trigger array DialogTrigger
private hashtable Hash = InitHashtable()
endglobals
private function DialogClicked takes nothing returns nothing
local trigger trig = GetTriggeringTrigger()
local integer trigId = GetHandleId(trig)
local integer i = LoadInteger(Hash, trigId, 0)
local player play = Player(i)
local group g
local unit u
if GetClickedButton() == Yes[i] then
set g = CreateGroup()
call GroupEnumUnitsOfPlayer(g, play, null)
loop
set u = FirstOfGroup(g)
exitwhen u == null
call GroupRemoveUnit(g, u)
if GetUnitTypeId(u) == BASE_WORKER and GetOwningPlayer(u) == play then
call ReplaceUnitBJ(u, NEW_WORKER, bj_UNIT_STATE_METHOD_RELATIVE)
elseif GetUnitTypeId(u) == BASE_HALL and GetOwningPlayer(u) == play then
call RemoveUnit(u)
call CreateUnit(play, NEW_HALL, GetPlayerStartLocationX(play), GetPlayerStartLocationY(play), bj_UNIT_FACING)
call CreateUnit(play, NEW_SCION, GetPlayerStartLocationX(play), GetPlayerStartLocationY(play), bj_UNIT_FACING)
endif
endloop
call DestroyGroup(g)
endif
call FlushChildHashtable(Hash, trigId)
call DialogDestroy(Choice[i])
endfunction
public function Actions takes nothing returns nothing
local integer i = 0 // player 1 starts at 0 in JASS
local player play
local dialog diag
loop
set play = Player(i)
if GetPlayerController(play) == MAP_CONTROL_USER and GetPlayerRace(play) == RACE then
set diag = DialogCreate()
set Choice[i] = diag
call DialogSetMessage(diag, CHOICE_STRING)
set Yes[i] = DialogAddButton(diag, "Yes", 0)
set No[i] = DialogAddButton(diag, "No", 0)
set DialogTrigger[i] = CreateTrigger()
call TriggerRegisterDialogEvent(DialogTrigger[i], diag)
call TriggerAddAction(DialogTrigger[i], function DialogClicked)
call SaveInteger(Hash, GetHandleId(DialogTrigger[i]), 0, i)
call DialogDisplay(play, diag, true)
endif
call SetPlayerMaxHeroesAllowed(3, play)
set i = i + 1
exitwhen i > bj_MAX_PLAYER_SLOTS
endloop
call MeleeInitVictoryDefeatCustomized()
call MeleeStartingAI()
call MeleeStartingVisibility()
set diag = null
endfunction
endlibrary
scope PrimeSetup
private function Actions takes nothing returns nothing
call SetupHumans_Actions()
call SetupNightElves_Actions()
//call SetupUndead_Actions()
//call SetupOrcs_Actions()
endfunction
private module init
private static method onInit takes nothing returns nothing
local trigger trig = CreateTrigger()
call MeleeClearExcessUnits()
call MeleeStartingUnits()
call MeleeStartingHeroLimit()
call MeleeGrantHeroItems()
call MeleeStartingResources()
call TriggerRegisterTimerEventSingle(trig, 0.01 )
call TriggerAddAction(trig, function Actions)
endmethod
endmodule
private struct Setup
implement init
endstruct
endscope
library CustomVictoryDefeat
globals
private constant string RevealWarning = "You will be revealed to your opponents unless you build a town-hall type structure."
endglobals
//===========================================================================
// Counts key structures owned by a player and his or her allies, including
// structures currently upgrading or under construction.
//
// Key structures: Town Hall, Great Hall, Tree of Life, Necropolis
//
private function LivingPlayerHallsFilter takes nothing returns boolean
return (IsUnitAliveBJ(GetFilterUnit()) and IsUnitType(GetFilterUnit(),UNIT_TYPE_TOWNHALL))
endfunction
private function CountLivingPlayerTownHalls takes player whichPlayer returns integer
local group g
local integer matchedCount
local boolexpr b=Filter(function LivingPlayerHallsFilter)
set g = CreateGroup()
call GroupEnumUnitsOfPlayer(g, whichPlayer, b)
set matchedCount = CountUnitsInGroup(g)
call DestroyGroup(g)
call DestroyBoolExpr(b)
set b=null
set g=null
return matchedCount
endfunction
private function Custom_MeleeGetAllyKeyStructureCount takes player whichPlayer returns integer
local integer playerIndex
local player indexPlayer
local integer keyStructs
// Count the number of buildings controlled by all not-yet-defeated co-allies.
set keyStructs = 0
set playerIndex = 0
loop
set indexPlayer = Player(playerIndex)
if (PlayersAreCoAllied(whichPlayer, indexPlayer)) then
set keyStructs = keyStructs + CountLivingPlayerTownHalls(indexPlayer)
// set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "townhall", true, true)
// set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "greathall", true, true)
// set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "treeoflife", true, true)
// set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "necropolis", true, true)
// set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "custom_h030", true, true)
// set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "custom_h01C", true, true)
// set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "custom_h012", true, true)
// set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "custom_h013", true, true)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h013',indexPlayer)//Never use group functions for this, just count living units for player. Much better idea.
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h014',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h015',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h01C',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h01E',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h01F',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h012',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h02F',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h02J',indexPlayer)
// set keyStructs = keySructs + CountLivingPlayerUnitsOfTypeId('h030',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h000',indexPlayer)//Non-modded human custom ids
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h00D',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h00E',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('o00C',indexPlayer)//Non-modded orc custom ids
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('o00D',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('o00E',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('e00M',indexPlayer)//Non-modded night elf custom ids
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('e00N',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('e00O',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('u00C',indexPlayer)//Non-modded undead custom ids
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('u00D',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('u00E',indexPlayer)
endif
set playerIndex = playerIndex + 1
exitwhen playerIndex == bj_MAX_PLAYERS
endloop
return keyStructs
endfunction
//===========================================================================
private function Custom_MeleePlayerIsCrippled takes player whichPlayer returns boolean
local integer allyStructures = MeleeGetAllyStructureCount(whichPlayer)
local integer allyKeyStructures = Custom_MeleeGetAllyKeyStructureCount(whichPlayer)
// Dead teams are not considered to be crippled.
return (allyStructures > 0) and (allyKeyStructures <= 0)
endfunction
//===========================================================================
// Test each player to determine if anyone has become crippled.
//
private function Custom_MeleeCheckForCrippledPlayers takes nothing returns nothing
local integer playerIndex
local player indexPlayer
local force crippledPlayers = CreateForce()
local boolean isNowCrippled
local race indexRace
// The "finish soon" exposure of all players overrides any "crippled" exposure
if bj_finishSoonAllExposed then
return
endif
// Check each player to see if he or she has been crippled or uncrippled.
set playerIndex = 0
loop
set indexPlayer = Player(playerIndex)
set isNowCrippled = Custom_MeleePlayerIsCrippled(indexPlayer)
if (not bj_playerIsCrippled[playerIndex] and isNowCrippled) then
// Player became crippled; start their cripple timer.
set bj_playerIsCrippled[playerIndex] = true
call TimerStart(bj_crippledTimer[playerIndex], bj_MELEE_CRIPPLE_TIMEOUT, false, function MeleeCrippledPlayerTimeout)
if (GetLocalPlayer() == indexPlayer) then
// Use only local code (no net traffic) within this block to avoid desyncs.
// Show the timer window.
call TimerDialogDisplay(bj_crippledTimerWindows[playerIndex], true)
// Display a warning message.
call DisplayTimedTextToPlayer(indexPlayer, 0, 0, bj_MELEE_CRIPPLE_MSG_DURATION, "|cffffcc00"+RevealWarning+"|r")
endif
elseif (bj_playerIsCrippled[playerIndex] and not isNowCrippled) then
// Player became uncrippled; stop their cripple timer.
set bj_playerIsCrippled[playerIndex] = false
call PauseTimer(bj_crippledTimer[playerIndex])
if (GetLocalPlayer() == indexPlayer) then
// Use only local code (no net traffic) within this block to avoid desyncs.
// Hide the timer window for this player.
call TimerDialogDisplay(bj_crippledTimerWindows[playerIndex], false)
// Display a confirmation message if the player's team is still alive.
if (MeleeGetAllyStructureCount(indexPlayer) > 0) then
if (bj_playerIsExposed[playerIndex]) then
call DisplayTimedTextToPlayer(indexPlayer, 0, 0, bj_MELEE_CRIPPLE_MSG_DURATION, GetLocalizedString("CRIPPLE_UNREVEALED"))
else
call DisplayTimedTextToPlayer(indexPlayer, 0, 0, bj_MELEE_CRIPPLE_MSG_DURATION, GetLocalizedString("CRIPPLE_UNCRIPPLED"))
endif
endif
endif
// If the player granted shared vision, deny that vision now.
call MeleeExposePlayer(indexPlayer, false)
endif
set playerIndex = playerIndex + 1
exitwhen playerIndex == bj_MAX_PLAYERS
endloop
endfunction
//===========================================================================
// Determine if the lost unit should result in any defeats or victories.
//
private function Custom_MeleeCheckLostUnit takes unit lostUnit returns nothing
local player lostUnitOwner = GetOwningPlayer(lostUnit)
// We only need to check for mortality if this was the last building.
if (GetPlayerStructureCount(lostUnitOwner, true) <= 0) then
call MeleeCheckForLosersAndVictors()
endif
// Check if the lost unit has crippled or uncrippled the player.
// (A team with 0 units is dead, and thus considered uncrippled.)
call Custom_MeleeCheckForCrippledPlayers()
endfunction
//===========================================================================
// Determine if the gained unit should result in any defeats, victories,
// or cripple-status changes.
//
private function Custom_MeleeCheckAddedUnit takes unit addedUnit returns nothing
local player addedUnitOwner = GetOwningPlayer(addedUnit)
// If the player was crippled, this unit may have uncrippled him/her.
if (bj_playerIsCrippled[GetPlayerId(addedUnitOwner)]) then
call Custom_MeleeCheckForCrippledPlayers()
endif
endfunction
//===========================================================================
private function Custom_MeleeTriggerActionConstructCancel takes nothing returns nothing
call Custom_MeleeCheckLostUnit(GetCancelledStructure())
endfunction
//===========================================================================
private function Custom_MeleeTriggerActionUnitDeath takes nothing returns nothing
if (IsUnitType(GetDyingUnit(), UNIT_TYPE_STRUCTURE)) then
call Custom_MeleeCheckLostUnit(GetDyingUnit())
endif
endfunction
//===========================================================================
private function Custom_MeleeTriggerActionUnitConstructionStart takes nothing returns nothing
call Custom_MeleeCheckAddedUnit(GetConstructingStructure())
endfunction
//===========================================================================
private function Custom_MeleeTriggerActionAllianceChange takes nothing returns nothing
call MeleeCheckForLosersAndVictors()
call Custom_MeleeCheckForCrippledPlayers()
endfunction
//===========================================================================
function MeleeInitVictoryDefeatCustomized takes nothing returns nothing
local trigger trig
local integer index
local player indexPlayer
// Create a timer window for the "finish soon" timeout period, it has no timer
// because it is driven by real time (outside of the game state to avoid desyncs)
set bj_finishSoonTimerDialog = CreateTimerDialog(null)
// Set a trigger to fire when we receive a "finish soon" game event
set trig = CreateTrigger()
call TriggerRegisterGameEvent(trig , EVENT_GAME_TOURNAMENT_FINISH_SOON)
call TriggerAddAction(trig , function MeleeTriggerTournamentFinishSoon)
// Set a trigger to fire when we receive a "finish now" game event
set trig = CreateTrigger()
call TriggerRegisterGameEvent(trig , EVENT_GAME_TOURNAMENT_FINISH_NOW)
call TriggerAddAction(trig , function MeleeTriggerTournamentFinishNow)
// Set up each player's mortality code.
set index = 0
loop
set indexPlayer = Player(index)
// Make sure this player slot is playing.
if ( GetPlayerSlotState(indexPlayer) == PLAYER_SLOT_STATE_PLAYING ) then
set bj_meleeDefeated[index]=false
set bj_meleeVictoried[index]=false
// Create a timer and timer window in case the player is crippled.
set bj_playerIsCrippled[index]=false
set bj_playerIsExposed[index]=false
set bj_crippledTimer[index]=CreateTimer()
set bj_crippledTimerWindows[index]=CreateTimerDialog(bj_crippledTimer[index])
call TimerDialogSetTitle(bj_crippledTimerWindows[index] , MeleeGetCrippledTimerMessage(indexPlayer))
// Set a trigger to fire whenever a building is cancelled for this player.
set trig = CreateTrigger()
call TriggerRegisterPlayerUnitEvent(trig , indexPlayer , EVENT_PLAYER_UNIT_CONSTRUCT_CANCEL , null)
call TriggerAddAction(trig , function Custom_MeleeTriggerActionConstructCancel)
// Set a trigger to fire whenever a unit dies for this player.
set trig = CreateTrigger()
call TriggerRegisterPlayerUnitEvent(trig , indexPlayer , EVENT_PLAYER_UNIT_DEATH , null)
call TriggerAddAction(trig , function Custom_MeleeTriggerActionUnitDeath)
// Set a trigger to fire whenever a unit begins construction for this player
set trig = CreateTrigger()
call TriggerRegisterPlayerUnitEvent(trig , indexPlayer , EVENT_PLAYER_UNIT_CONSTRUCT_START , null)
call TriggerAddAction(trig , function Custom_MeleeTriggerActionUnitConstructionStart)
// Set a trigger to fire whenever this player defeats-out
set trig = CreateTrigger()
call TriggerRegisterPlayerEvent(trig , indexPlayer , EVENT_PLAYER_DEFEAT)
call TriggerAddAction(trig , function MeleeTriggerActionPlayerDefeated)
// Set a trigger to fire whenever this player leaves
set trig = CreateTrigger()
call TriggerRegisterPlayerEvent(trig , indexPlayer , EVENT_PLAYER_LEAVE)
call TriggerAddAction(trig , function MeleeTriggerActionPlayerLeft)
// Set a trigger to fire whenever this player changes his/her alliances.
set trig = CreateTrigger()
call TriggerRegisterPlayerAllianceChange(trig , indexPlayer , ALLIANCE_PASSIVE)
call TriggerRegisterPlayerStateEvent(trig , indexPlayer , PLAYER_STATE_ALLIED_VICTORY , EQUAL , 1)
call TriggerAddAction(trig , function Custom_MeleeTriggerActionAllianceChange)
else
set bj_meleeDefeated[index]=true
set bj_meleeVictoried[index]=false
// Handle leave events for observers
if ( IsPlayerObserver(indexPlayer) ) then
// Set a trigger to fire whenever this player leaves
set trig = CreateTrigger()
call TriggerRegisterPlayerEvent(trig , indexPlayer , EVENT_PLAYER_LEAVE)
call TriggerAddAction(trig , function MeleeTriggerActionPlayerLeft)
endif
endif
set index = index + 1
exitwhen index == bj_MAX_PLAYERS
endloop
// Test for victory / defeat at startup, in case the user has already won / lost.
// Allow for a short time to pass first, so that the map can finish loading.
call TimerStart(CreateTimer() , 2.0 , false , function Custom_MeleeTriggerActionAllianceChange)
endfunction
endlibrary