//===========================================================================
// 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
//
function LivingPlayerHallsFilter takes nothing returns boolean
return (IsUnitAliveBJ(GetFilterUnit()) and IsUnitType(GetFilterUnit(),UNIT_TYPE_TOWNHALL))
endfunction
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
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
//===========================================================================
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.
//
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"+udg_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.
//
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.
//
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
//===========================================================================
function Custom_MeleeTriggerActionConstructCancel takes nothing returns nothing
call Custom_MeleeCheckLostUnit(GetCancelledStructure())
endfunction
//===========================================================================
function Custom_MeleeTriggerActionUnitDeath takes nothing returns nothing
if (IsUnitType(GetDyingUnit(), UNIT_TYPE_STRUCTURE)) then
call Custom_MeleeCheckLostUnit(GetDyingUnit())
endif
endfunction
//===========================================================================
function Custom_MeleeTriggerActionUnitConstructionStart takes nothing returns nothing
call Custom_MeleeCheckAddedUnit(GetConstructingStructure())
endfunction
//===========================================================================
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
Name | Type | is_array | initial_value |
A_AoE | real | No | |
A_Duration | real | No | |
A_Real | real | No | |
A_UType | unitcode | No | |
Ability_Picked | unit | No | |
AfterDamageEvent | real | No | |
AIQuilboar | string | Yes | |
AIQuilName | string | Yes | |
AIRandomizer | integer | No | |
AOEDamageEvent | real | No | |
AOEDamageSource | unit | No | |
ARMOR_TYPE_ETHEREAL | integer | No | |
ARMOR_TYPE_FLESH | integer | No | |
ARMOR_TYPE_METAL | integer | No | |
ARMOR_TYPE_NONE | integer | No | |
ARMOR_TYPE_STONE | integer | No | |
ARMOR_TYPE_WOOD | integer | No | |
ArmorDamageEvent | real | No | |
ArmorTypeDebugStr | string | Yes | |
ATTACK_TYPE_CHAOS | integer | No | |
ATTACK_TYPE_HERO | integer | No | |
ATTACK_TYPE_MAGIC | integer | No | |
ATTACK_TYPE_NORMAL | integer | No | |
ATTACK_TYPE_PIERCE | integer | No | |
ATTACK_TYPE_SIEGE | integer | No | |
ATTACK_TYPE_SPELLS | integer | No | |
AttackTypeDebugStr | string | Yes | |
AvatarAiPoint | location | Yes | |
BE_Ability | abilcode | No | |
BE_AbilityIndex | integer | Yes | |
BE_Angle | real | Yes | |
BE_AttackType | attacktype | No | |
BE_Bounces | integer | Yes | |
BE_Caster | unit | Yes | |
BE_CDamage | real | Yes | |
BE_CHeal | real | Yes | |
BE_CSizeIncrement | real | No | |
BE_CurrentBounces | integer | Yes | |
BE_Damage | real | Yes | |
BE_DamageAddition | real | Yes | |
BE_DamageType | damagetype | No | |
BE_Distance | real | Yes | |
BE_DistanceTravelled | real | Yes | |
BE_Dummy | unit | Yes | |
BE_DummyType | unitcode | No | |
BE_FX | effect | Yes | |
BE_Group | group | No | |
BE_Heal | real | Yes | |
BE_HealAddition | real | Yes | |
BE_Height | real | Yes | |
BE_MaxIndex | integer | No | |
BE_Model | string | No | |
BE_NegAbility | abilcode | No | |
BE_NegSpecialEffect | string | No | |
BE_PickedUnits | unit | No | |
BE_Player | player | Yes | |
BE_PosAbility | abilcode | No | |
BE_PosSpecialEffect | string | No | |
BE_PreloadUnit | unit | No | |
BE_SearchAoE | real | Yes | |
BE_SizeIncrement | real | Yes | |
BE_Speed | real | Yes | |
BE_Target | unit | Yes | |
BE_TempIndex | integer | No | |
BE_TempPoint | location | No | |
BE_TempPoint2 | location | No | |
BE_TempPoint3 | location | No | |
BE_TotalDistance | real | No | |
Behavior_OnAllyAttacked | trigger | No | |
Behavior_OnAllyAttacks | trigger | No | |
Behavior_OnAllyCasts | trigger | No | |
Behavior_OnAllyDeath | trigger | No | |
Behavior_OnAllyDmgDealt | trigger | No | |
Behavior_OnAllyDmgTaken | trigger | No | |
Behavior_OnAllyKills | trigger | No | |
Behavior_OnAllyTargeted | trigger | No | |
Behavior_OnAttack | trigger | No | |
Behavior_OnAttacked | trigger | No | |
Behavior_OnCast | trigger | No | |
Behavior_OnDamageDealt | trigger | No | |
Behavior_OnDamageTaken | trigger | No | |
Behavior_OnEnemyAttacked | trigger | No | |
Behavior_OnEnemyAttacks | trigger | No | |
Behavior_OnEnemyCasts | trigger | No | |
Behavior_OnEnemyDeath | trigger | No | |
Behavior_OnEnemyDmgDealt | trigger | No | |
Behavior_OnEnemyDmgTaken | trigger | No | |
Behavior_OnEnemyKills | trigger | No | |
Behavior_OnEnemyTargeted | trigger | No | |
Behavior_OnKill | trigger | No | |
Behavior_OnPeriod | trigger | No | |
Behavior_OnTargeted | trigger | No | |
Behavior_Unit | unit | No | |
Behavior_UnitType | unitcode | No | |
BldgCent | unit | No | |
Bli_C | unit | No | |
Blight_Loc | location | No | |
BlightTC_Convert | unit | No | |
Blo_C | unit | No | |
Blood_Boar | unitcode | Yes | |
BloodTC_Convert | unit | No | |
BUFF_unit | unit | No | |
Burrow_Point | location | Yes | |
CargoEvent | real | No | |
CargoTransportGroup | group | Yes | |
CargoTransportUnit | unit | Yes | |
Caster | unit | No | |
CB_angle | real | No | |
CB_attacked_Loc | location | No | |
CB_attacking_Loc | location | No | |
CB_BOOOM | boolean | No | |
CB_Caster | unit | No | |
CB_chance_to_knockback | integer | Yes | |
CB_distance | real | No | |
CB_distance_setup | real | Yes | |
CB_effectOnCast | string | No | |
CB_effectOnLoop | string | No | |
CB_group | group | No | |
CB_hash | hashtable | No | |
CB_Target | unit | No | |
CB_temp_unit | unit | No | |
CB_temploc | location | No | |
CB_temploc_2 | location | No | |
CB_time | real | No | |
CB_tusk | unit | No | |
CB_victim | unit | No | |
CBall_Angle | real | No | |
CBall_Caster_Unit | unit | No | |
CBall_Damage | real | No | |
CBall_Damaged_UnitGroup | group | No | |
CBall_Hashtable | hashtable | No | |
CBall_Speed | real | No | |
CBall_Travel_Range | real | No | |
CBall_UnitGroup | group | No | |
CBallKey | integer | No | |
CBallPoint1 | location | No | |
CBallPoint2 | location | No | |
CBallPoint3 | location | No | |
CBallUnit | unit | No | |
CE_Ability_Level | integer | No | |
CE_Area_of_Effect | real | No | |
CE_Base_Damage | real | No | |
CE_Caster | unit | No | |
CE_Damage_Group | group | No | |
CE_Destroy_Trees | boolean | No | |
CE_Knock_Angle | real | No | |
CE_Knock_Distance | real | No | |
CE_Knock_Group | group | No | |
CE_Knock_Loc1 | location | No | |
CE_Knock_Loc2 | location | No | |
CE_Knock_Speed | real | No | |
CE_Knocktable | hashtable | No | |
CE_Location | location | No | |
CE_Location2 | location | No | |
CE_Pathing_On | boolean | No | |
CE_Special_Effect | effect | No | |
CE_Special_Effect1 | effect | No | |
CE_Total_Damage | real | No | |
CheckDeathInList | boolean | Yes | |
CheckDeathList | integer | Yes | |
CheckDeathTimer | timer | No | |
CL_AbilityLevel | integer | Yes | |
CL_AOE | real | Yes | |
CL_Caster | unit | Yes | |
CL_Count | integer | Yes | |
CL_Damage | integer | Yes | |
CL_FirstTarget | boolean | Yes | |
CL_Group | group | Yes | |
CL_Loc | location | Yes | |
CL_Player | player | Yes | |
CL_Slashes | integer | Yes | |
CL_Special | effect | Yes | |
CL_Target | unit | Yes | |
CL_Victim | unit | Yes | |
CONVERTED_ATTACK_TYPE | attacktype | Yes | |
CONVERTED_DAMAGE_TYPE | damagetype | Yes | |
Converter | unit | No | |
CoreHound_Group | group | No | |
CoreHound_Loc | location | Yes | |
CustomO_Cooldown | real | No | |
CustomO_IsInCooldown | boolean | No | |
CustomO_Location | location | No | |
CustomO_ManaCost | integer | No | |
CustomO_Order | string | No | |
CustomO_OrderId | integer | No | |
CustomO_Priority | integer | No | |
CustomO_Target | unit | No | |
CustomO_Unit | unit | No | |
DAMAGE_TYPE_ACID | integer | No | |
DAMAGE_TYPE_COLD | integer | No | |
DAMAGE_TYPE_DEATH | integer | No | |
DAMAGE_TYPE_DEFENSIVE | integer | No | |
DAMAGE_TYPE_DEMOLITION | integer | No | |
DAMAGE_TYPE_DISEASE | integer | No | |
DAMAGE_TYPE_DIVINE | integer | No | |
DAMAGE_TYPE_ENHANCED | integer | No | |
DAMAGE_TYPE_FIRE | integer | No | |
DAMAGE_TYPE_FORCE | integer | No | |
DAMAGE_TYPE_LIGHTNING | integer | No | |
DAMAGE_TYPE_MAGIC | integer | No | |
DAMAGE_TYPE_MIND | integer | No | |
DAMAGE_TYPE_NORMAL | integer | No | |
DAMAGE_TYPE_PLANT | integer | No | |
DAMAGE_TYPE_POISON | integer | No | |
DAMAGE_TYPE_SHADOW_STRIKE | integer | No | |
DAMAGE_TYPE_SLOW_POISON | integer | No | |
DAMAGE_TYPE_SONIC | integer | No | |
DAMAGE_TYPE_SPIRIT_LINK | integer | No | |
DAMAGE_TYPE_UNIVERSAL | integer | No | |
DAMAGE_TYPE_UNKNOWN | integer | No | |
DamageEvent | real | No | |
DamageEventAmount | real | No | |
DamageEventAOE | integer | No | |
DamageEventAOEGroup | group | No | |
DamageEventArmorPierced | real | No | |
DamageEventArmorT | integer | No | |
DamageEventAttackT | integer | No | |
DamageEventDamageT | integer | No | |
DamageEventDefenseT | integer | No | |
DamageEventLevel | integer | No | |
DamageEventOverride | boolean | No | |
DamageEventPrevAmt | real | No | |
DamageEventSource | unit | No | |
DamageEventTarget | unit | No | |
DamageEventType | integer | No | |
DamageEventWeaponT | integer | No | |
DamageFilterAttackT | integer | No | |
DamageFilterDamageT | integer | No | |
DamageFilterFailChance | real | No | |
DamageFilterMinAmount | real | No | |
DamageFilterRunChance | real | No | |
DamageFilterSource | unit | No | |
DamageFilterSourceA | abilcode | No | |
DamageFilterSourceB | buffcode | No | |
DamageFilterSourceC | integer | No | |
DamageFilterSourceI | itemcode | No | |
DamageFilterSourceT | unitcode | No | |
DamageFilterTarget | unit | No | |
DamageFilterTargetA | abilcode | No | |
DamageFilterTargetB | buffcode | No | |
DamageFilterTargetC | integer | No | |
DamageFilterTargetI | itemcode | No | |
DamageFilterTargetT | unitcode | No | |
DamageFilterType | integer | No | |
DamageModifierEvent | real | No | |
DamageScalingUser | real | No | |
DamageScalingWC3 | real | No | |
DamageTypeBlocked | integer | No | |
DamageTypeCode | integer | No | |
DamageTypeCriticalStrike | integer | No | |
DamageTypeDebugStr | string | Yes | |
DamageTypeExplosive | integer | No | |
DamageTypeHeal | integer | No | |
DamageTypePure | integer | No | |
DamageTypePureExplosive | integer | No | |
DamageTypeReduced | integer | No | |
DeathEvent | real | No | |
Defeated | player | No | |
DEFENSE_TYPE_DIVINE | integer | No | |
DEFENSE_TYPE_FORTIFIED | integer | No | |
DEFENSE_TYPE_HEAVY | integer | No | |
DEFENSE_TYPE_HERO | integer | No | |
DEFENSE_TYPE_LIGHT | integer | No | |
DEFENSE_TYPE_MEDIUM | integer | No | |
DEFENSE_TYPE_NORMAL | integer | No | |
DEFENSE_TYPE_UNARMORED | integer | No | |
DefenseTypeDebugStr | string | Yes | |
DetectRemoveAbility | abilcode | No | |
DetectTransformAbility | abilcode | No | |
DT_Attacktype | attacktype | Yes | |
DT_Damage | real | Yes | |
DT_DamagePerInterval | real | Yes | |
DT_DamageTypes | damagetype | Yes | |
DT_Dealers | unit | Yes | |
DT_Effects | effect | Yes | |
DT_Integers | integer | Yes | |
DT_IntervalReals | real | Yes | |
DT_ReachedDamage | real | Yes | |
DT_ReachedInterval | real | Yes | |
DT_Targets | unit | Yes | |
DTA_Attacktype | attacktype | No | |
DTA_DamageType | damagetype | No | |
DTA_DmgDealer | unit | No | |
DTA_EffectAttachmentPoint | string | No | |
DTA_Interval | real | No | |
DTA_SpecialEffect | string | No | |
DTA_Target | unit | No | |
DTA_Time | real | No | |
DTA_TotalDamageDealt | real | No | |
Echoing_U | unit | No | |
Echoing_XY | location | No | |
EnemyBlue | force | No | |
EnemyGreen | force | No | |
EnemyOrange | force | No | |
EnemyPink | force | No | |
EnemyPurple | force | No | |
EnemyRed | force | No | |
EnemyTeal | force | No | |
EnemyYellow | force | No | |
EnhancedDamageTarget | unit | No | |
EntaglingDummy | group | No | |
Event_Ally | unit | No | |
Event_Attacker | unit | No | |
Event_Caster | unit | No | |
Event_Enemy | unit | No | |
Event_Killer | unit | No | |
Event_Source | unit | No | |
Event_Target | unit | No | |
Event_Unit | unit | No | |
Event_Victim | unit | No | |
ExGroup | group | No | |
ExTemppoint | location | No | |
FD | integer | No | |
FD_Angle | real | Yes | |
FD_Distance | real | Yes | |
FD_Hero | unit | Yes | |
FD_Off | boolean | Yes | |
FD_Point | location | Yes | |
FD_Skip | integer | No | |
FD_Spam | integer | Yes | |
FD_Speed | real | Yes | |
FD_Times | integer | No | |
Ground_Staff | location | No | |
GroupThorn | group | No | |
GS_Unit | unit | No | |
heal_amount | real | No | |
heal_check | boolean | No | |
HEAL_CHECK_INTERVAL | real | No | |
heal_count | integer | No | |
heal_diff | real | No | |
heal_exitwhen | integer | No | |
heal_indexRef | integer | Yes | |
heal_indices | integer | Yes | |
heal_inSys | boolean | Yes | |
heal_integer | integervar | No | |
heal_lastLife | real | Yes | |
heal_life | real | No | |
heal_regen | real | Yes | |
heal_source | unit | No | |
heal_target | unit | No | |
HEAL_THRESHOLD | real | No | |
heal_timer | timer | No | |
HealEvent | real | No | |
Hound | unit | Yes | |
Hound_Group | group | No | |
Houndmaster | unit | No | |
Houndmaster_MPI | unit | Yes | |
HW_Caster | unit | No | |
HW_Pick | unit | No | |
IsDamageAttack | boolean | No | |
IsDamageCode | boolean | No | |
IsDamageMelee | boolean | No | |
IsDamageRanged | boolean | No | |
IsDamageSpell | boolean | No | |
IsUnitAlive | boolean | Yes | |
IsUnitBeingUnloaded | boolean | Yes | |
IsUnitNew | boolean | Yes | |
IsUnitPreplaced | boolean | Yes | |
IsUnitReincarnating | boolean | Yes | |
IsUnitRemoved | boolean | Yes | |
IsUnitTransforming | boolean | Yes | |
JD_Angle | real | Yes | |
JD_Animations | string | Yes | |
JD_Distances | real | Yes | |
JD_Effect | string | Yes | |
JD_Group | group | No | |
JD_HighSettings | real | Yes | |
JD_Integers | integer | Yes | |
JD_JumpHigh | real | Yes | |
JD_ReachedDistance | real | Yes | |
JD_RealTimer | real | Yes | |
JD_SpeedUnits | real | Yes | |
JD_TempPoint | location | Yes | |
JD_TreesDestroy | boolean | Yes | |
JD_Unit | unit | Yes | |
JDA_Animation | string | No | |
JDA_AnimationSpeed | real | No | |
JDA_DestroyTrees_Dash | boolean | No | |
JDA_JumpHigh_Distance | real | No | |
JDA_SpecialEffect | string | No | |
JDA_Speed | real | No | |
JDA_TargetPoint | location | No | |
JDA_Unit | unit | No | |
Jewl_Point | location | No | |
Jewl_Unit | unit | No | |
KillerOfUnit | unit | Yes | |
KUS_animation | animationname | No | |
KUS_effect | modelfile | No | |
KUS_group | group | No | |
KUS_hash | hashtable | No | |
KUS_height | real | No | |
KUS_knockup | boolean | No | |
KUS_speed | real | No | |
KUS_target | unit | No | |
KUS_temp_loc | location | No | |
KUS_temp_speed | real | No | |
LethalDamageEvent | real | No | |
LethalDamageHP | real | No | |
LocBirth | location | No | |
MangerGroup | group | No | |
MangerPoint | location | No | |
Max_Index | integer | No | |
MCS_AttachmentPoint1 | string | No | |
MCS_AttachmentPoint2 | string | No | |
MCS_Caster1 | unit | No | |
MCS_Caster2 | unit | Yes | |
MCS_curDuration | real | Yes | |
MCS_Deadboolean | boolean | Yes | |
MCS_Duration1 | real | No | |
MCS_Duration2 | real | Yes | |
MCS_Integer | integer | Yes | |
MCS_MindControlledGroup | group | No | |
MCS_Player | player | Yes | |
MCS_SfxAtEndString | string | No | |
MCS_SfxAtEndString2 | string | Yes | |
MCS_SfxAtStartString | modelfile | No | |
MCS_SfxContinous1 | effect | Yes | |
MCS_SfxContinous1String | string | No | |
MCS_SfxContinous2 | effect | Yes | |
MCS_SfxContinous2String | string | No | |
MCS_Target1 | unit | No | |
MCS_Target2 | unit | Yes | |
MUI_1 | integer | No | |
MUI_2 | integer | Yes | |
MUI_3 | integer | No | |
NativeGroup | group | No | |
NativePoint | location | No | |
NextDamageIsAttack | boolean | No | |
NextDamageIsMelee | boolean | No | |
NextDamageIsRanged | boolean | No | |
NextDamageType | integer | No | |
NextDamageWeaponT | integer | No | |
NextHealAmount | real | No | |
NextHealSource | unit | No | |
NextHealTarget | unit | No | |
OnDamageEvent | real | No | |
Overcharge_Attacker | unit | No | |
Overcharge_Chance | integer | No | |
Overcharge_ChanceNumber | integer | No | |
Overcharge_Point | location | No | |
Overcharge_Unit_Group | group | No | |
Overlord | unit | No | |
PickedUnit | unit | No | |
Player_Picked | player | No | |
Playlist | string | No | |
PreDamageEvent | real | No | |
Random_Number | integer | No | |
regen_buildup | real | Yes | |
REGEN_EVENT_INTERVAL | real | No | |
REGEN_STRENGTH_VALUE | real | No | |
REGEN_THRESHOLD | real | No | |
regen_timeleft | real | Yes | |
RemoveDamageEvent | boolean | No | |
RevealWarning | string | No | You will be revealed to your opponents unless you build a town-hall type structure. |
RMX | integer | No | |
RMX_Angle | real | Yes | |
RMX_Distance | real | Yes | |
RMX_Equation | real | Yes | |
RMX_Fly | real | Yes | |
RMX_Fly_Distance | real | Yes | |
RMX_Formula | real | Yes | |
RMX_HERO | location | Yes | |
RMX_Hero_Unit | unit | Yes | |
RMX_Max_Height | real | Yes | |
RMX_Next | integer | Yes | |
RMX_Off | boolean | Yes | |
RMX_Point | location | Yes | |
RMX_Realistic_Air_Resistance | real | Yes | |
RMX_Skip | integer | No | |
RMX_Speed | real | Yes | |
RMX_Times | integer | No | |
RMX_Unit_Spear | unit | Yes | |
SacredCall_Point | location | No | |
Sample_Group | group | No | |
Sample_Point | location | No | |
SD | integer | No | |
SD_Angle | real | Yes | |
SD_Distance | real | Yes | |
SD_Equation | real | Yes | |
SD_FLY | real | Yes | |
SD_Fly_Distance | real | Yes | |
SD_Formula | real | Yes | |
SD_HERO | location | Yes | |
SD_Hero | unit | Yes | |
SD_Max_Height | real | Yes | |
SD_NexT | integer | Yes | |
SD_Off | boolean | Yes | |
SD_Point | location | Yes | |
SD_Realistic_Air_Resistance | real | Yes | |
SD_Skip | integer | No | |
SD_Speed | real | Yes | |
SD_Times | integer | No | |
SD_Unit_Spear | unit | Yes | |
Seed_Loc | location | No | |
SourceDamageEvent | real | No | |
Spell_Unit | unit | No | |
SpellLevel | integer | No | |
SummonerOfUnit | unit | Yes | |
Target | unit | No | |
Temp | integer | No | |
TempInteger | integer | No | |
TempPoint | location | No | |
TempPoint2 | location | No | |
TempUnit | unit | No | |
TempUnit2 | unit | No | |
ThornPoint | location | No | |
Torment | location | No | |
Tree | destructable | No | |
Tree_Loc | location | No | |
TrueHemoNum | integer | No | |
TuskmasterAiGroup | group | No | |
TuskmasterAiLoc | location | 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 | |
UMovNext | integer | Yes | |
UMovPrev | integer | Yes | |
UNIT_CLASS_ANCIENT | integer | No | |
UNIT_CLASS_ATTACKS_FLYING | integer | No | |
UNIT_CLASS_ATTACKS_GROUND | integer | No | |
UNIT_CLASS_DEAD | integer | No | |
UNIT_CLASS_ETHEREAL | integer | No | |
UNIT_CLASS_FLYING | integer | No | |
UNIT_CLASS_GIANT | integer | No | |
UNIT_CLASS_GROUND | integer | No | |
UNIT_CLASS_HERO | integer | No | |
UNIT_CLASS_MAGIC_IMMUNE | integer | No | |
UNIT_CLASS_MECHANICAL | integer | No | |
UNIT_CLASS_MELEE | integer | No | |
UNIT_CLASS_PEON | integer | No | |
UNIT_CLASS_PLAGUED | integer | No | |
UNIT_CLASS_POISONED | integer | No | |
UNIT_CLASS_POLYMORPHED | integer | No | |
UNIT_CLASS_RANGED | integer | No | |
UNIT_CLASS_RESISTANT | integer | No | |
UNIT_CLASS_SAPPER | integer | No | |
UNIT_CLASS_SLEEPING | integer | No | |
UNIT_CLASS_SNARED | integer | No | |
UNIT_CLASS_STRUCTURE | integer | No | |
UNIT_CLASS_STUNNED | integer | No | |
UNIT_CLASS_SUMMONED | integer | No | |
UNIT_CLASS_TAUREN | integer | No | |
UNIT_CLASS_TOWNHALL | integer | No | |
UNIT_CLASS_UNDEAD | integer | No | |
UnitIndexerEnabled | boolean | No | |
UnitIndexEvent | real | No | |
UnitMovementInterval | real | No | |
UnitMoving | boolean | Yes | |
UnitMovingEvent | real | No | |
UnitMovingX | real | Yes | |
UnitMovingY | real | Yes | |
UnitTypeEvent | real | No | |
UnitTypeOf | unitcode | Yes | |
WEAPON_TYPE_AM_CHOP | integer | No | |
WEAPON_TYPE_CH_SLICE | integer | No | |
WEAPON_TYPE_CL_SLICE | integer | No | |
WEAPON_TYPE_CM_SLICE | integer | No | |
WEAPON_TYPE_MH_BASH | integer | No | |
WEAPON_TYPE_MH_CHOP | integer | No | |
WEAPON_TYPE_MH_SLICE | integer | No | |
WEAPON_TYPE_MH_STAB | integer | No | |
WEAPON_TYPE_ML_CHOP | integer | No | |
WEAPON_TYPE_ML_SLICE | integer | No | |
WEAPON_TYPE_MM_BASH | integer | No | |
WEAPON_TYPE_MM_CHOP | integer | No | |
WEAPON_TYPE_MM_SLICE | integer | No | |
WEAPON_TYPE_MM_STAB | integer | No | |
WEAPON_TYPE_NONE | integer | No | |
WEAPON_TYPE_RH_BASH | integer | No | |
WEAPON_TYPE_WH_BASH | integer | No | |
WEAPON_TYPE_WH_SLICE | integer | No | |
WEAPON_TYPE_WL_BASH | integer | No | |
WEAPON_TYPE_WL_SLICE | integer | No | |
WEAPON_TYPE_WL_STAB | integer | No | |
WEAPON_TYPE_WM_BASH | integer | No | |
WEAPON_TYPE_WM_SLICE | integer | No | |
WEAPON_TYPE_WM_STAB | integer | No | |
WeaponTypeDebugStr | string | Yes | |
WOF_Attacked | unit | No | |
WOF_Attacking | unit | No | |
WOF_Chance | integer | No | |
WOF_Dummy | unit | No | |
WOF_Point | location | No | |
WOF_Target | unit | No | |
WorldMaxX | real | No | |
WorldMaxY | real | No | |
ZeroDamageEvent | real | No |
library MultidimensionalArray /* v1.2b
*/uses /*
*/Table /* http://www.hiveworkshop.com/threads/snippet-new-table.188084/
[Resource Link] - http://www.hiveworkshop.com/threads/snippet-multidimensional-array.289785/
*///! novjass
/* This snippet allows you to have array storage. Unlike default arrays, you can use an index beyond 8190
since this snippet uses Tables which uses hashtable. Therefore, saving data with a really large index
such as using GetHandleId(handle) as the index would not be a problem.
But you may ask, why would we want to use this when there is already the Table library which can support
any type that we want to store? First, this has a feature which supports multidimensions that allows you
to have up to 5-dimensional array. Table already allows you to create multidimensional storage if you do
proper nesting but this library removes the need for users to do it on their own and this also helps set
a standard instead of having redundant scripts that work for the same puspose. Secondly, unlike Table,
this implements a type specific storage i.e., you can create an array storage that is only exclusive for
a specific type but of course, this also provides a generic storage like Table but with a nicer API.
Furthermore, this includes some safety precautions such as compile time safety which throws an error if
you're using an incorrect number of dimensions, as well as preventing the use of an Array instance which
isn't allocated in DEBUG_MODE. lastly, this gives users a nice and intuitive syntax which resembles that
of the original vanilla Jass arrays (call KillUnit(u[1][3])) without having a need for an ugly keyword
at the end (ex: call KillUnit(u[1].unit[3])). */
|=========|
| Credits |
|=========|
/* AGD : Author
Bribe : For the Table library, and for the algorithm of making n-dimensional storage by nesting Tables */
|-----|
| API |
|-----|
Creating an Array:
/* Creates a new array for a specific type */
local Unit1D u = Array.create()
local Unit3D u3 = Unit3D.create()
local Unit5D u5 = Timer4D.create() //You could actually use any of the dimensional array creator
local Array4D a4 = Array.create()
Storing inside an Array:
/* Stores data inside an array */
set u[GetHandleId(timer)] = GetTriggerUnit()
set u3[0x2000]['AAAA'] = GetTriggerUnit() //Syntax error: number of indexes does not match with the number of dimensions
set u5[1][2][3][4][5] = GetTriggerUnit()
set a4[1][2][3][4].unit = GetTriggerUnit()
Retrieving from an Array:
/* Retrieves data from an array */
call KillUnit(u[1234567])
call KillUnit(u3['A']['B']['C'])
call KillUnit(u5[1][2][3][4]) //Syntax error: number of indexes does not match with the number of dimensions
call KillUnit(a4[1][2][3][4].unit)
Checking storage vacancy:
/* Checks if there is data stored inside an array index */
return u.has(index) //Similar to Table(u).unit.has(index)
return u3[1][2].has(3)
return u5[1].has(2) //Checks if the fourth dimension has index 2
return a4[1][2][3].hasHandle(4)
Removing an Array index:
/* Destroys the table instance of an index and clears all its child nodes if there are any */
call u.remove(1)
call u3[1].remove(2)
call u5[1][2][3][4][5].remove(6) //Syntax error: cannot use remove() on a node which has no children
call a4[1][2][3].removeHandle(4)
Flushing an Array Index:
/* Flushes all child nodes attached to the specific index */
call u.flush() //Flushes all data inside the array, analogous to flushing a parent hashtable
call u3[1][2][3].flush() //Syntax error: cannot clear a node which has no children, use u3[1][2].remove(3) instead
call u5[1][2].flush() //Flushes all child nodes attached to the index "2" of the second dimension
call a4[1][2].flush()
Destroying an Array:
/* Destroys an array instance, flushing all data inside it */
call u.destroy()
call u3.destroy()
call u5[1].destroy() //If destroy() is called upon a node which is not a root node, it will work like clear() instead
call a4.destroy()
//! endnovjass
static if DEBUG_MODE then
private struct S extends array
static key allocated
endstruct
private function Debug takes string msg returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "|CFFFFCC00[MultidimensionalArray] |R" + msg)
endfunction
endif
private function AllocateIndex takes integer this, integer index returns integer
debug if not Table(S.allocated).boolean[this] then
debug return 0
debug endif
debug set Table(S.allocated).boolean[HashTable(this)[index]] = true
return HashTable(this)[index]
endfunction
/*============= For a uniform allocator syntax =) ==============*/
struct Array extends array
static method create takes nothing returns thistype
static if DEBUG_MODE then
local Table t = Table.create()
set Table(S.allocated).boolean[t] = true
return t
else
return Table.create()
endif
endmethod
endstruct
/*==============================================================*/
/*====================== Struct methods ========================*/
private module Methods
static method create takes nothing returns thistype
return Array.create()
endmethod
static if not thistype.remove.exists then
method remove takes integer index returns nothing
call HashTable(this).remove(index)
endmethod
endif
static if not thistype.has.exists then
method has takes integer index returns boolean
return HashTable(this).has(index)
endmethod
endif
method flush takes nothing returns nothing
call Table(this).flush()
endmethod
method destroy takes nothing returns nothing
call Table(this).destroy()
debug set Table(S.allocated).boolean[this] = false
endmethod
endmodule
/*==============================================================*/
/*================= Generic Type Array Storage =================*/
private struct Type extends array
static key index
method operator agent= takes agent value returns nothing
debug if not Table(S.allocated).boolean[this] then
debug call Debug("|CFFFF0000[Operator agent= ERROR] : Attempted to use a non-allocated array instance|R")
debug return
debug endif
set Table(this).agent[Table(this)[index]] = value
endmethod
//! textmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS takes TYPE
method operator $TYPE$ takes nothing returns $TYPE$
return Table(this).$TYPE$[Table(this)[index]]
endmethod
method operator $TYPE$= takes $TYPE$ value returns nothing
debug if not Table(S.allocated).boolean[this] then
debug call Debug("|CFFFF0000[Operator $TYPE$= ERROR] : Attempted to use a non-allocated array instance|R")
debug return
debug endif
set Table(this).$TYPE$[Table(this)[index]] = value
endmethod
//! endtextmacro
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("integer")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("real")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("string")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("boolean")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("player")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("widget")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("destructable")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("item")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("unit")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("ability")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("timer")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("trigger")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("triggercondition")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("triggeraction")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("event")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("force")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("group")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("location")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("rect")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("boolexpr")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("sound")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("effect")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("unitpool")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("itempool")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("quest")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("questitem")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("defeatcondition")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("timerdialog")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("leaderboard")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("multiboard")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("multiboarditem")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("trackable")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("dialog")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("button")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("texttag")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("lightning")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("image")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("ubersplat")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("region")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("fogstate")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("fogmodifier")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("hashtable")
endstruct
struct Array1D extends array
//! textmacro GENERIC_DIMENSIONAL_ARRAY_METHODS takes NAME, TYPE
method has$NAME$ takes integer index returns boolean
return Table(this).$TYPE$.has(index)
endmethod
method remove$NAME$ takes integer index returns nothing
call Table(this).$TYPE$.remove(index)
endmethod
//! endtextmacro
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_METHODS("Integer", "integer")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_METHODS("Real", "real")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_METHODS("String", "string")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_METHODS("Boolean", "boolean")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_METHODS("Handle", "handle")
method has takes integer index returns boolean
return .hasInteger(index) /*
*/or .hasReal(index) /*
*/or .hasString(index) /*
*/or .hasBoolean(index) /*
*/or .hasHandle(index)
endmethod
method remove takes integer index returns nothing
call .removeInteger(index)
call .removeReal(index)
call .removeString(index)
call .removeBoolean(index)
call .removeHandle(index)
endmethod
implement Methods
method operator [] takes integer index returns Type
debug if not Table(S.allocated).boolean[this] then
debug return 0
debug endif
set Table(this)[Type.index] = index
return this
endmethod
endstruct
//! textmacro NEW_DIMENSIONAL_ARRAY_STRUCT takes DIM, RETURNED
struct Array$DIM$D extends array
implement Methods
method operator [] takes integer index returns Array$RETURNED$D
return AllocateIndex(this, index)
endmethod
endstruct
//! endtextmacro
//! runtextmacro NEW_DIMENSIONAL_ARRAY_STRUCT("2", "1")
//! runtextmacro NEW_DIMENSIONAL_ARRAY_STRUCT("3", "2")
//! runtextmacro NEW_DIMENSIONAL_ARRAY_STRUCT("4", "3")
//! runtextmacro NEW_DIMENSIONAL_ARRAY_STRUCT("5", "4")
// If you want to increase the maximum number of available
// dimensions, just run the textmacros above once again like:
// runtextmacro NEW_DIMENSIONAL_ARRAY_STRUCT("LAST_MAX_DIM + 1", "LAST_MAX_DIM")
/*==============================================================*/
/*================ Type Specific Array Storage =================*/
//! textmacro NEW_DIMENSIONAL_ARRAY takes NAME, TYPE
struct $NAME$1D extends array
method remove takes integer index returns nothing
call Table(this).$TYPE$.remove(index)
endmethod
method has takes integer index returns boolean
return Table(this).$TYPE$.has(index)
endmethod
implement Methods
method operator [] takes integer index returns $TYPE$
return Table(this).$TYPE$[index]
endmethod
method operator []= takes integer index, $TYPE$ value returns nothing
debug if not Table(S.allocated).boolean[this] then
debug call Debug("|CFFFFCC00[ArrayType: $NAME$]|R |CFFFF0000[Operator []= ERROR] : Attempted to use a non-allocated array instance|R")
debug return
debug endif
set Table(this).$TYPE$[index] = value
endmethod
endstruct
struct $NAME$2D extends array
implement Methods
method operator [] takes integer index returns $NAME$1D
return AllocateIndex(this, index)
endmethod
endstruct
struct $NAME$3D extends array
implement Methods
method operator [] takes integer index returns $NAME$2D
return AllocateIndex(this, index)
endmethod
endstruct
struct $NAME$4D extends array
implement Methods
method operator [] takes integer index returns $NAME$3D
return AllocateIndex(this, index)
endmethod
endstruct
struct $NAME$5D extends array
implement Methods
method operator [] takes integer index returns $NAME$4D
return AllocateIndex(this, index)
endmethod
endstruct
//! endtextmacro
// If you want to increase the maximum number of available
// dimensions, just copy the last struct above and increase the
// number of dimension in the struct name and the returned struct
// of the operator [] by 1.
/*==============================================================*/
/*======== Implement textmacros for every storage type =========*/
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Integer", "integer")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Real", "real")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Str", "string")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Boolean", "boolean")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Player", "player")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Widget", "widget")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Destructable", "destructable")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Item", "item")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Unit", "unit")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Ability", "ability")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Timer", "timer")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Trigger", "trigger")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("TriggerCondition", "triggercondition")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("TriggerAction", "triggeraction")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("TriggerEvent", "event")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Force", "force")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Group", "group")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Location", "location")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Rect", "rect")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("BooleanExpr", "boolexpr")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Sound", "sound")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Effect", "effect")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("UnitPool", "unitpool")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("ItemPool", "itempool")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Quest", "quest")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("QuestItem", "questitem")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("DefeatCondition", "defeatcondition")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("TimerDialog", "timerdialog")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Leaderboard", "leaderboard")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Multiboard", "multiboard")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("MultiboardItem", "multiboarditem")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Trackable", "trackable")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Dialog", "dialog")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Button", "button")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("TextTag", "texttag")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Lightning", "lightning")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Image", "image")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Ubersplat", "ubersplat")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Region", "region")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("FogState", "fogstate")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("FogModifier", "fogmodifier")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Hashtable", "hashtable")
/*==============================================================*/
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Table /* made by Bribe, special thanks to Vexorian & Nestharus, version 4.1.0.1.
One map, one hashtable. Welcome to NewTable 4.1.0.1
This newest iteration of Table introduces the new HashTable struct.
You can now instantiate HashTables which enables the use of large
parent and large child keys, just like a standard hashtable. Previously,
the user would have to instantiate a Table to do this on their own which -
while doable - is something the user should not have to do if I can add it
to this resource myself (especially if they are inexperienced).
This library was originally called NewTable so it didn't conflict with
the API of Table by Vexorian. However, the damage is done and it's too
late to change the library name now. To help with damage control, I
have provided an extension library called TableBC, which bridges all
the functionality of Vexorian's Table except for 2-D string arrays &
the ".flush(integer)" method. I use ".flush()" to flush a child hash-
table, because I wanted the API in NewTable to reflect the API of real
hashtables (I thought this would be more intuitive).
API
------------
struct Table
| static method create takes nothing returns Table
| create a new Table
|
| method destroy takes nothing returns nothing
| destroy it
|
| method flush takes nothing returns nothing
| flush all stored values inside of it
|
| method remove takes integer key returns nothing
| remove the value at index "key"
|
| method operator []= takes integer key, $TYPE$ value returns nothing
| assign "value" to index "key"
|
| method operator [] takes integer key returns $TYPE$
| load the value at index "key"
|
| method has takes integer key returns boolean
| whether or not the key was assigned
|
----------------
struct TableArray
| static method operator [] takes integer array_size returns TableArray
| create a new array of Tables of size "array_size"
|
| method destroy takes nothing returns nothing
| destroy it
|
| method flush takes nothing returns nothing
| flush and destroy it
|
| method operator size takes nothing returns integer
| returns the size of the TableArray
|
| method operator [] takes integer key returns Table
| returns a Table accessible exclusively to index "key"
*/
globals
private integer less = 0 //Index generation for TableArrays (below 0).
private integer more = 8190 //Index generation for Tables.
//Configure it if you use more than 8190 "key" variables in your map (this will never happen though).
private hashtable ht = InitHashtable()
private key sizeK
private key listK
endglobals
private struct dex extends array
static method operator size takes nothing returns Table
return sizeK
endmethod
static method operator list takes nothing returns Table
return listK
endmethod
endstruct
private struct handles extends array
method has takes integer key returns boolean
return HaveSavedHandle(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSavedHandle(ht, this, key)
endmethod
endstruct
private struct agents extends array
method operator []= takes integer key, agent value returns nothing
call SaveAgentHandle(ht, this, key, value)
endmethod
endstruct
//! textmacro NEW_ARRAY_BASIC takes SUPER, FUNC, TYPE
private struct $TYPE$s extends array
method operator [] takes integer key returns $TYPE$
return Load$FUNC$(ht, this, key)
endmethod
method operator []= takes integer key, $TYPE$ value returns nothing
call Save$FUNC$(ht, this, key, value)
endmethod
method has takes integer key returns boolean
return HaveSaved$SUPER$(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSaved$SUPER$(ht, this, key)
endmethod
endstruct
private module $TYPE$m
method operator $TYPE$ takes nothing returns $TYPE$s
return this
endmethod
endmodule
//! endtextmacro
//! textmacro NEW_ARRAY takes FUNC, TYPE
private struct $TYPE$s extends array
method operator [] takes integer key returns $TYPE$
return Load$FUNC$Handle(ht, this, key)
endmethod
method operator []= takes integer key, $TYPE$ value returns nothing
call Save$FUNC$Handle(ht, this, key, value)
endmethod
method has takes integer key returns boolean
return HaveSavedHandle(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSavedHandle(ht, this, key)
endmethod
endstruct
private module $TYPE$m
method operator $TYPE$ takes nothing returns $TYPE$s
return this
endmethod
endmodule
//! endtextmacro
//Run these textmacros to include the entire hashtable API as wrappers.
//Don't be intimidated by the number of macros - Vexorian's map optimizer is
//supposed to kill functions which inline (all of these functions inline).
//! runtextmacro NEW_ARRAY_BASIC("Real", "Real", "real")
//! runtextmacro NEW_ARRAY_BASIC("Boolean", "Boolean", "boolean")
//! runtextmacro NEW_ARRAY_BASIC("String", "Str", "string")
//New textmacro to allow table.integer[] syntax for compatibility with textmacros that might desire it.
//! runtextmacro NEW_ARRAY_BASIC("Integer", "Integer", "integer")
//! runtextmacro NEW_ARRAY("Player", "player")
//! runtextmacro NEW_ARRAY("Widget", "widget")
//! runtextmacro NEW_ARRAY("Destructable", "destructable")
//! runtextmacro NEW_ARRAY("Item", "item")
//! runtextmacro NEW_ARRAY("Unit", "unit")
//! runtextmacro NEW_ARRAY("Ability", "ability")
//! runtextmacro NEW_ARRAY("Timer", "timer")
//! runtextmacro NEW_ARRAY("Trigger", "trigger")
//! runtextmacro NEW_ARRAY("TriggerCondition", "triggercondition")
//! runtextmacro NEW_ARRAY("TriggerAction", "triggeraction")
//! runtextmacro NEW_ARRAY("TriggerEvent", "event")
//! runtextmacro NEW_ARRAY("Force", "force")
//! runtextmacro NEW_ARRAY("Group", "group")
//! runtextmacro NEW_ARRAY("Location", "location")
//! runtextmacro NEW_ARRAY("Rect", "rect")
//! runtextmacro NEW_ARRAY("BooleanExpr", "boolexpr")
//! runtextmacro NEW_ARRAY("Sound", "sound")
//! runtextmacro NEW_ARRAY("Effect", "effect")
//! runtextmacro NEW_ARRAY("UnitPool", "unitpool")
//! runtextmacro NEW_ARRAY("ItemPool", "itempool")
//! runtextmacro NEW_ARRAY("Quest", "quest")
//! runtextmacro NEW_ARRAY("QuestItem", "questitem")
//! runtextmacro NEW_ARRAY("DefeatCondition", "defeatcondition")
//! runtextmacro NEW_ARRAY("TimerDialog", "timerdialog")
//! runtextmacro NEW_ARRAY("Leaderboard", "leaderboard")
//! runtextmacro NEW_ARRAY("Multiboard", "multiboard")
//! runtextmacro NEW_ARRAY("MultiboardItem", "multiboarditem")
//! runtextmacro NEW_ARRAY("Trackable", "trackable")
//! runtextmacro NEW_ARRAY("Dialog", "dialog")
//! runtextmacro NEW_ARRAY("Button", "button")
//! runtextmacro NEW_ARRAY("TextTag", "texttag")
//! runtextmacro NEW_ARRAY("Lightning", "lightning")
//! runtextmacro NEW_ARRAY("Image", "image")
//! runtextmacro NEW_ARRAY("Ubersplat", "ubersplat")
//! runtextmacro NEW_ARRAY("Region", "region")
//! runtextmacro NEW_ARRAY("FogState", "fogstate")
//! runtextmacro NEW_ARRAY("FogModifier", "fogmodifier")
//! runtextmacro NEW_ARRAY("Hashtable", "hashtable")
struct Table extends array
// Implement modules for intuitive syntax (tb.handle; tb.unit; etc.)
implement realm
implement integerm
implement booleanm
implement stringm
implement playerm
implement widgetm
implement destructablem
implement itemm
implement unitm
implement abilitym
implement timerm
implement triggerm
implement triggerconditionm
implement triggeractionm
implement eventm
implement forcem
implement groupm
implement locationm
implement rectm
implement boolexprm
implement soundm
implement effectm
implement unitpoolm
implement itempoolm
implement questm
implement questitemm
implement defeatconditionm
implement timerdialogm
implement leaderboardm
implement multiboardm
implement multiboarditemm
implement trackablem
implement dialogm
implement buttonm
implement texttagm
implement lightningm
implement imagem
implement ubersplatm
implement regionm
implement fogstatem
implement fogmodifierm
implement hashtablem
method operator handle takes nothing returns handles
return this
endmethod
method operator agent takes nothing returns agents
return this
endmethod
//set this = tb[GetSpellAbilityId()]
method operator [] takes integer key returns Table
return LoadInteger(ht, this, key) //return this.integer[key]
endmethod
//set tb[389034] = 8192
method operator []= takes integer key, Table tb returns nothing
call SaveInteger(ht, this, key, tb) //set this.integer[key] = tb
endmethod
//set b = tb.has(2493223)
method has takes integer key returns boolean
return HaveSavedInteger(ht, this, key) //return this.integer.has(key)
endmethod
//call tb.remove(294080)
method remove takes integer key returns nothing
call RemoveSavedInteger(ht, this, key) //call this.integer.remove(key)
endmethod
//Remove all data from a Table instance
method flush takes nothing returns nothing
call FlushChildHashtable(ht, this)
endmethod
//local Table tb = Table.create()
static method create takes nothing returns Table
local Table this = dex.list[0]
if this == 0 then
set this = more + 1
set more = this
else
set dex.list[0] = dex.list[this]
call dex.list.remove(this) //Clear hashed memory
endif
debug set dex.list[this] = -1
return this
endmethod
// Removes all data from a Table instance and recycles its index.
//
// call tb.destroy()
//
method destroy takes nothing returns nothing
debug if dex.list[this] != -1 then
debug call BJDebugMsg("Table Error: Tried to double-free instance: " + I2S(this))
debug return
debug endif
call this.flush()
set dex.list[this] = dex.list[0]
set dex.list[0] = this
endmethod
//! runtextmacro optional TABLE_BC_METHODS()
endstruct
//! runtextmacro optional TABLE_BC_STRUCTS()
struct TableArray extends array
//Returns a new TableArray to do your bidding. Simply use:
//
// local TableArray ta = TableArray[array_size]
//
static method operator [] takes integer array_size returns TableArray
local Table tb = dex.size[array_size] //Get the unique recycle list for this array size
local TableArray this = tb[0] //The last-destroyed TableArray that had this array size
debug if array_size <= 0 then
debug call BJDebugMsg("TypeError: Invalid specified TableArray size: " + I2S(array_size))
debug return 0
debug endif
if this == 0 then
set this = less - array_size
set less = this
else
set tb[0] = tb[this] //Set the last destroyed to the last-last destroyed
call tb.remove(this) //Clear hashed memory
endif
set dex.size[this] = array_size //This remembers the array size
return this
endmethod
//Returns the size of the TableArray
method operator size takes nothing returns integer
return dex.size[this]
endmethod
//This magic method enables two-dimensional[array][syntax] for Tables,
//similar to the two-dimensional utility provided by hashtables them-
//selves.
//
//ta[integer a].unit[integer b] = unit u
//ta[integer a][integer c] = integer d
//
//Inline-friendly when not running in debug mode
//
method operator [] takes integer key returns Table
static if DEBUG_MODE then
local integer i = this.size
if i == 0 then
call BJDebugMsg("IndexError: Tried to get key from invalid TableArray instance: " + I2S(this))
return 0
elseif key < 0 or key >= i then
call BJDebugMsg("IndexError: Tried to get key [" + I2S(key) + "] from outside TableArray bounds: " + I2S(i))
return 0
endif
endif
return this + key
endmethod
//Destroys a TableArray without flushing it; I assume you call .flush()
//if you want it flushed too. This is a public method so that you don't
//have to loop through all TableArray indices to flush them if you don't
//need to (ie. if you were flushing all child-keys as you used them).
//
method destroy takes nothing returns nothing
local Table tb = dex.size[this.size]
debug if this.size == 0 then
debug call BJDebugMsg("TypeError: Tried to destroy an invalid TableArray: " + I2S(this))
debug return
debug endif
if tb == 0 then
//Create a Table to index recycled instances with their array size
set tb = Table.create()
set dex.size[this.size] = tb
endif
call dex.size.remove(this) //Clear the array size from hash memory
set tb[this] = tb[0]
set tb[0] = this
endmethod
private static Table tempTable
private static integer tempEnd
//Avoids hitting the op limit
private static method clean takes nothing returns nothing
local Table tb = .tempTable
local integer end = tb + 0x1000
if end < .tempEnd then
set .tempTable = end
call ForForce(bj_FORCE_PLAYER[0], function thistype.clean)
else
set end = .tempEnd
endif
loop
call tb.flush()
set tb = tb + 1
exitwhen tb == end
endloop
endmethod
//Flushes the TableArray and also destroys it. Doesn't get any more
//similar to the FlushParentHashtable native than this.
//
method flush takes nothing returns nothing
debug if this.size == 0 then
debug call BJDebugMsg("TypeError: Tried to flush an invalid TableArray instance: " + I2S(this))
debug return
debug endif
set .tempTable = this
set .tempEnd = this + this.size
call ForForce(bj_FORCE_PLAYER[0], function thistype.clean)
call this.destroy()
endmethod
endstruct
//NEW: Added in Table 4.0. A fairly simple struct but allows you to do more
//than that which was previously possible.
struct HashTable extends array
//Enables myHash[parentKey][childKey] syntax.
//Basically, it creates a Table in the place of the parent key if
//it didn't already get created earlier.
method operator [] takes integer index returns Table
local Table t = Table(this)[index]
if t == 0 then
set t = Table.create()
set Table(this)[index] = t //whoops! Forgot that line. I'm out of practice!
endif
return t
endmethod
//You need to call this on each parent key that you used if you
//intend to destroy the HashTable or simply no longer need that key.
method remove takes integer index returns nothing
local Table t = Table(this)[index]
if t != 0 then
call t.destroy()
call Table(this).remove(index)
endif
endmethod
//Added in version 4.1
method has takes integer index returns boolean
return Table(this).has(index)
endmethod
//HashTables are just fancy Table indices.
method destroy takes nothing returns nothing
call Table(this).destroy()
endmethod
//Like I said above...
static method create takes nothing returns thistype
return Table.create()
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library TimerUtils initializer init
//*********************************************************************
//* TimerUtils (red+blue+orange flavors for 1.24b+) 2.0
//* ----------
//*
//* To implement it , create a custom text trigger called TimerUtils
//* and paste the contents of this script there.
//*
//* To copy from a map to another, copy the trigger holding this
//* library to your map.
//*
//* (requires vJass) More scripts: htt://www.wc3c.net
//*
//* For your timer needs:
//* * Attaching
//* * Recycling (with double-free protection)
//*
//* set t=NewTimer() : Get a timer (alternative to CreateTimer)
//* set t=NewTimerEx(x) : Get a timer (alternative to CreateTimer), call
//* Initialize timer data as x, instead of 0.
//*
//* ReleaseTimer(t) : Relese a timer (alt to DestroyTimer)
//* SetTimerData(t,2) : Attach value 2 to timer
//* GetTimerData(t) : Get the timer's value.
//* You can assume a timer's value is 0
//* after NewTimer.
//*
//* Multi-flavor:
//* Set USE_HASH_TABLE to true if you don't want to complicate your life.
//*
//* If you like speed and giberish try learning about the other flavors.
//*
//********************************************************************
//================================================================
globals
//How to tweak timer utils:
// USE_HASH_TABLE = true (new blue)
// * SAFEST
// * SLOWEST (though hash tables are kind of fast)
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = true (orange)
// * kinda safe (except there is a limit in the number of timers)
// * ALMOST FAST
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = false (red)
// * THE FASTEST (though is only faster than the previous method
// after using the optimizer on the map)
// * THE LEAST SAFE ( you may have to tweak OFSSET manually for it to
// work)
//
private constant boolean USE_HASH_TABLE = false
private constant boolean USE_FLEXIBLE_OFFSET = true
private constant integer OFFSET = 0x100000
private integer VOFFSET = OFFSET
//Timers to preload at map init:
private constant integer QUANTITY = 256
//Changing this to something big will allow you to keep recycling
// timers even when there are already AN INCREDIBLE AMOUNT of timers in
// the stack. But it will make things far slower so that's probably a bad idea...
private constant integer ARRAY_SIZE = 8190
endglobals
//==================================================================================================
globals
private integer array data[ARRAY_SIZE]
private hashtable ht
endglobals
//It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
function SetTimerData takes timer t, integer value returns nothing
static if(USE_HASH_TABLE) then
// new blue
call SaveInteger(ht,0,GetHandleId(t), value)
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-VOFFSET]=value
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-OFFSET]=value
endif
endfunction
function GetTimerData takes timer t returns integer
static if(USE_HASH_TABLE) then
// new blue
return LoadInteger(ht,0,GetHandleId(t) )
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-VOFFSET]
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-OFFSET]
endif
endfunction
//==========================================================================================
globals
private timer array tT[ARRAY_SIZE]
private integer tN = 0
private constant integer HELD=0x28829022
//use a totally random number here, the more improbable someone uses it, the better.
private boolean didinit = false
endglobals
private keyword init
//==========================================================================================
// I needed to decide between duplicating code ignoring the "Once and only once" rule
// and using the ugly textmacros. I guess textmacros won.
//
//! textmacro TIMERUTIS_PRIVATE_NewTimerCommon takes VALUE
// On second thought, no.
//! endtextmacro
function NewTimerEx takes integer value returns timer
if (tN==0) then
if (not didinit) then
//This extra if shouldn't represent a major performance drawback
//because QUANTITY rule is not supposed to be broken every day.
call init.evaluate()
set tN = tN - 1
else
//If this happens then the QUANTITY rule has already been broken, try to fix the
// issue, else fail.
debug call BJDebugMsg("NewTimer: Warning, Exceeding TimerUtils_QUANTITY, make sure all timers are getting recycled correctly")
set tT[0]=CreateTimer()
static if( not USE_HASH_TABLE) then
debug call BJDebugMsg("In case of errors, please increase it accordingly, or set TimerUtils_USE_HASH_TABLE to true")
static if( USE_FLEXIBLE_OFFSET) then
if (GetHandleId(tT[0])-VOFFSET<0) or (GetHandleId(tT[0])-VOFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
else
if (GetHandleId(tT[0])-OFFSET<0) or (GetHandleId(tT[0])-OFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
endif
endif
endif
else
set tN=tN-1
endif
call SetTimerData(tT[tN],value)
return tT[tN]
endfunction
function NewTimer takes nothing returns timer
return NewTimerEx(0)
endfunction
//==========================================================================================
function ReleaseTimer takes timer t returns nothing
if(t==null) then
debug call BJDebugMsg("Warning: attempt to release a null timer")
return
endif
if (tN==ARRAY_SIZE) then
debug call BJDebugMsg("Warning: Timer stack is full, destroying timer!!")
//stack is full, the map already has much more troubles than the chance of bug
call DestroyTimer(t)
else
call PauseTimer(t)
if(GetTimerData(t)==HELD) then
debug call BJDebugMsg("Warning: ReleaseTimer: Double free!")
return
endif
call SetTimerData(t,HELD)
set tT[tN]=t
set tN=tN+1
endif
endfunction
private function init takes nothing returns nothing
local integer i=0
local integer o=-1
local boolean oops = false
if ( didinit ) then
return
else
set didinit = true
endif
static if( USE_HASH_TABLE ) then
set ht = InitHashtable()
loop
exitwhen(i==QUANTITY)
set tT[i]=CreateTimer()
call SetTimerData(tT[i], HELD)
set i=i+1
endloop
set tN = QUANTITY
else
loop
set i=0
loop
exitwhen (i==QUANTITY)
set tT[i] = CreateTimer()
if(i==0) then
set VOFFSET = GetHandleId(tT[i])
static if(USE_FLEXIBLE_OFFSET) then
set o=VOFFSET
else
set o=OFFSET
endif
endif
if (GetHandleId(tT[i])-o>=ARRAY_SIZE) then
exitwhen true
endif
if (GetHandleId(tT[i])-o>=0) then
set i=i+1
endif
endloop
set tN = i
exitwhen(tN == QUANTITY)
set oops = true
exitwhen not USE_FLEXIBLE_OFFSET
debug call BJDebugMsg("TimerUtils_init: Failed a initialization attempt, will try again")
endloop
if(oops) then
static if ( USE_FLEXIBLE_OFFSET) then
debug call BJDebugMsg("The problem has been fixed.")
//If this message doesn't appear then there is so much
//handle id fragmentation that it was impossible to preload
//so many timers and the thread crashed! Therefore this
//debug message is useful.
elseif(DEBUG_MODE) then
call BJDebugMsg("There were problems and the new timer limit is "+I2S(i))
call BJDebugMsg("This is a rare ocurrence, if the timer limit is too low:")
call BJDebugMsg("a) Change USE_FLEXIBLE_OFFSET to true (reduces performance a little)")
call BJDebugMsg("b) or try changing OFFSET to "+I2S(VOFFSET) )
endif
endif
endif
endfunction
endlibrary
library AIBehaviorController /* v1.3 by Riki
Special credits to Kingz for his Behaviour AI System, which inspired me and from which I
based to create this system.
Find it here: https://www.hiveworkshop.com/threads/behaviour-ai-system-v1-5.248639/
----------------------------
---NECESSARY REQUIREMENTS---
----------------------------
*/ requires /*
*/ MultidimensionalArray, /* by AGD: http://www.hiveworkshop.com/threads/snippet-multidimensional-array.289785/
*/ TimerUtils, /*
Others:
-Unit Indexer by Bribe: https://www.hiveworkshop.com/threads/gui-unit-indexer-1-4-0-0.197329/
-Damage Engine by Bribe: https://www.hiveworkshop.com/threads/damage-engine-5-7-1-2.201016/
-Table by Bribe: http://www.hiveworkshop.com/threads/snippet-new-table.188084/
---------------------------
---OPTIONAL REQUIREMENTS---
---------------------------
*/ optional /*
*/ UnitIndexerGUI, /* by Bribe: https://www.hiveworkshop.com/threads/snippet-gui-unit-indexer-vjass-plugin.268592/
*/ RegisterPlayerUnitEvent /* by Bannar: https://www.hiveworkshop.com/threads/snippet-registerevent-pack.250266/
Others:
-RegisterNativeEvent by Bannar: https://www.hiveworkshop.com/threads/snippet-registerevent-pack.250266/
*/
//! novjass
================================== AI Behavior Controller ==================================
/* A system designed to make it easy for users to create AI by giving them the option to */
/* define custom behaviors for specific units or unit types as required. These behaviors */
/* include following a specified order under certain circumstances, using custom spells */
/* and abilities (including those based on Channel), etc. */
/* */
/* Sometimes it is frustrating to have to deal with an AI that does not cast certain */
/* spells because they are based on Channel or some other ability that the AI would not */
/* use under normal circunstances. */
/* */
/* The goal of this system in principle is to provide a tool that allows AI units to use */
/* any spell that the user wishes to create, and it has been extended to include even */
/* more options. */
/* */
/* Please note that this system is not designed to directly create custom AI, but to */
/* support AI creation. */
/*----------------------------------------------------------------------------------------*/
=================
- HOW TO IMPORT -
=================
/*----------------------------------------------------------------------------------------*/
/* For users who want to use the system in vJass, follow steps from 1 to 3. */
/* Those users who need the GUI version must follow all the steps listed. */
/* */
/* 1. Copy all the Necessary Requirements into your map. If you have newer versions of */
/* one of the listed requirements, you can skip it, but remember that you will need all */
/* of them. */
/* */
/* 2. Copy this library into your map. After this you will be ready to use this system. */
/* */
/* 3. I recommend copying the Optional Requirements as well, but you can skip this step */
/* if you want. */
/* */
/* 4. To use the GUI version, you must first follow all the steps above. After that, you */
/* need to copy all the content within the AIBC GUI category to your map. */
/*----------------------------------------------------------------------------------------*/
=======
- API -
=======
struct Controller
|- static method registerBehavior takes unit u, Behavior b returns nothing
| // Adds a custom Behavior to a single unit.
|
|- static method registerBehaviorType takes integer uTypeId, Behavior b returns nothing
| // Adds a custom Behavior to an unit type.
|
|- static method removeBehavior takes unit u, Behavior b returns nothing
| // Removes a custom Behavior from a single unit.
|
|- static method removeBehaviorType takes integer uTypeId, Behavior b returns nothing
| // Removes a custom Behavior from an unit type.
struct Behavior
|- method onPeriod takes unit u returns nothing
| // Fires on every interval. Use u to access the unit.
|
|- method onCast takes unit caster, unit target returns nothing
| // Fires when the unit casts an ability. Use caster to access the unit.
|
|- method onTargeted takes unit target, unit caster returns nothing
| // Fires when the unit is targeted with an ability. Use target to access the unit.
|
|- method onAttack takes unit attacker, unit target returns nothing
| // Fires when the unit attacks. Use attacker to access the unit.
|
|- method onAttacked takes unit target, unit attacker returns nothing
| // Fires when the unit is attacked. Use target to access the unit.
|
|- method onDamageDealt takes unit source, unit target returns nothing
| // Fires when the unit deals damage. Use source to access the unit.
|
|- method onDamageTaken takes unit target, unit source returns nothing
| // Fires when the unit receives damage. Use target to access the unit.
|
|- method onKill takes unit killer, unit victim returns nothing
| // Fires when the unit kills another. Use killer to access the unit.
|
|- method onAllyCasts takes unit u, unit ally, unit target returns nothing
|- method onAllyTargeted takes unit u, unit ally, unit caster returns nothing
|- method onAllyAttacks takes unit u, unit ally, unit target returns nothing
|- method onAllyAttacked takes unit u, unit ally, unit attacker returns nothing
|- method onAllyDmgDealt takes unit u, unit ally, unit target returns nothing
|- method onAllyDmgTaken takes unit u, unit ally, unit source returns nothing
|- method onAllyKills takes unit u, unit ally, unit victim returns nothing
|- method onAllyDeath takes unit u, unit ally, unit killer returns nothing
| // Events that will fire when a nearby friendly unit performs a certain action.
| // These events will only activate if OTHER_UNITS_EVENTS is set to true.
| // Use u to access the unit with custom behavior.
| // Use ally to access the allied unit that fires the event.
|
|- method onEnemyCasts takes unit u, unit enemy, unit target returns nothing
|- method onEnemyTargeted takes unit u, unit enemy, unit caster returns nothing
|- method onEnemyAttacks takes unit u, unit enemy, unit target returns nothing
|- method onEnemyAttacked takes unit u, unit enemy, unit attacker returns nothing
|- method onEnemyDmgDealt takes unit u, unit enemy, unit target returns nothing
|- method onEnemyDmgTaken takes unit u, unit enemy, unit source returns nothing
|- method onEnemyKills takes unit u, unit enemy, unit victim returns nothing
|- method onEnemyDeath takes unit u, unit enemy, unit killer returns nothing
| // Events that will fire when a nearby enemy unit performs a certain action.
| // These events will only activate if OTHER_UNITS_EVENTS is set to true.
| // Use u to access the unit with custom behavior.
| // Use enemy to access the enemy unit that fires the event.
struct CustomOrder
|- method create takes unit u returns thistype
| // Registers the unit so it can use custom orders given by its Behavior.
|
|- method checkOrder takes string orderStr returns boolean
| // Checks if an orders is already registered.
|
|- method checkOrderById takes integer orderId returns boolean
| // Checks if an orders is already registered using integers for order id.
|
|- method isOrderInCooldown takes string orderStr returns boolean
| // Checks if an orders is in cooldown.
|
|- method isOrderInCooldownById takes integer orderId returns boolean
| // Checks if an orders is in cooldown using integers for order id.
|
|- method registerTargetOrder takes string orderStr, widget target, integer priority, real cooldown, integer manaCost returns nothing
|- method registerPointOrder takes string orderStr, real locX, real locY, integer priority, real cooldown, integer manaCost returns nothing
|- method registerInstantOrder takes string orderStr, integer priority, real cooldown, integer manaCost returns nothing
| // Registers an order using strings.
|
|- method registerTargetOrderById takes integer orderId, widget target, integer priority, real cooldown, integer manaCost returns nothing
|- method registerPointOrderById takes integer orderId, real locX, real locY, integer priority, real cooldown, integer manaCost returns nothing
|- method registerInstantOrderById takes integer orderId, integer priority, real cooldown, integer manaCost returns nothing
| // Registers an order using integers for order id.
//! endnovjass
native UnitAlive takes unit u returns boolean
/*------CONFIGURATION------*/
globals
private constant real PERIODIC_INTERVAL = .5 // Interval for Periodic Events
private constant real COOLDOWN_INTERVAL = .5 // Interval for Cooldown check
private constant integer MAX_ORDERS = 15 // Max number of orders for a unit per event
private constant integer LOWEST_PRIO = 1 // Minimum priority value for orders
private constant integer HIGHEST_PRIO = 30 // Maximum priority value for orders
private constant boolean OTHER_UNITS_EVENTS = true // Set to false if you don't want to fire onAlly / onEnemy events
private constant real UNIT_SEARCH_RANGE = 700. // Max range used to detect onAlly / onEnemy events
private constant real MIN_DMG = 1. // Minimum value required to fire a Damage event. Recommended value: 1.0
// Used for GroupEnumUnitsWithCollision function
private constant real MAX_COLLISION = 64. // Max collision size for units
private real tempX = 0. // Don't touch
private real tempY = 0. // Don't touch
private real tempRange = 0. // Don't touch
// Arrays, don't touch
Boolean2D OrderInCooldown
Boolean1D OrderExecuted
Integer1D RegOrders
Integer2D UnitBehavior
Integer2D UnitTypeBehavior
Boolean1D HasCustomOrders
Integer1D TotalBehaviors
Integer1D TotalBehaviorsType
endglobals
/*------FUNCTIONS------*/
private function FilterInRange takes nothing returns boolean
return IsUnitInRangeXY(GetFilterUnit(), tempX, tempY, tempRange)
endfunction
private function GroupEnumUnitsWithCollision takes group g, real x, real y, real radius returns group
set tempX = x
set tempY = y
set tempRange = radius
call GroupEnumUnitsInRange(g, x, y, radius+MAX_COLLISION, Filter(function FilterInRange))
return g
endfunction
/*------EVENTS------*/
interface Behavior
// Spell Cast Events
method onCast takes unit caster, unit target returns nothing defaults nothing
method onTargeted takes unit target, unit caster returns nothing defaults nothing
// Attack Events
method onAttack takes unit attacker, unit target returns nothing defaults nothing
method onAttacked takes unit target, unit attacker returns nothing defaults nothing
// Damage Events
method onDamageDealt takes unit source, unit target returns nothing defaults nothing
method onDamageTaken takes unit target, unit source returns nothing defaults nothing
// Kill Event
method onKill takes unit killer, unit victim returns nothing defaults nothing
// Periodic Event
method onPeriod takes unit u returns nothing defaults nothing
// OnAlly Events
method onAllyCasts takes unit u, unit ally, unit target returns nothing defaults nothing
method onAllyTargeted takes unit u, unit ally, unit caster returns nothing defaults nothing
method onAllyAttacks takes unit u, unit ally, unit target returns nothing defaults nothing
method onAllyAttacked takes unit u, unit ally, unit attacker returns nothing defaults nothing
method onAllyDmgDealt takes unit u, unit ally, unit target returns nothing defaults nothing
method onAllyDmgTaken takes unit u, unit ally, unit source returns nothing defaults nothing
method onAllyKills takes unit u, unit ally, unit victim returns nothing defaults nothing
method onAllyDeath takes unit u, unit ally, unit killer returns nothing defaults nothing
// OnEnemy Events
method onEnemyCasts takes unit u, unit enemy, unit target returns nothing defaults nothing
method onEnemyTargeted takes unit u, unit enemy, unit caster returns nothing defaults nothing
method onEnemyAttacks takes unit u, unit enemy, unit target returns nothing defaults nothing
method onEnemyAttacked takes unit u, unit enemy, unit attacker returns nothing defaults nothing
method onEnemyDmgDealt takes unit u, unit enemy, unit target returns nothing defaults nothing
method onEnemyDmgTaken takes unit u, unit enemy, unit source returns nothing defaults nothing
method onEnemyKills takes unit u, unit enemy, unit victim returns nothing defaults nothing
method onEnemyDeath takes unit u, unit enemy, unit killer returns nothing defaults nothing
endinterface
/*------MAIN SYSTEM------*/
struct Cooldown
private integer casterId
private integer order
private real duration
private timer loopTimer
private method onDestroy takes nothing returns nothing
call ReleaseTimer(.loopTimer)
set .loopTimer = null
endmethod
private static method check takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
local unit caster
static if LIBRARY_UnitIndexerGUI then
set caster = GetUnitById(.casterId)
else
set caster = udg_UDexUnits[.casterId]
endif
if .duration > 0 and UnitAlive(caster) and OrderInCooldown[.casterId][.order] then
set .duration = .duration - COOLDOWN_INTERVAL
else
set OrderInCooldown[.casterId][.order] = false
call .destroy()
endif
set caster = null
endmethod
static method start takes integer unitId, integer orderId, real cooldown returns nothing
local thistype this = thistype.allocate()
set .casterId = unitId
set .order = orderId
set .duration = cooldown
set .loopTimer = NewTimerEx(this)
if not OrderInCooldown[.casterId][.order] then
set OrderInCooldown[.casterId][.order] = true
endif
call TimerStart(.loopTimer, COOLDOWN_INTERVAL, true, function thistype.check)
endmethod
endstruct
struct PreventNewOrders
private integer casterId
private timer loopTimer
private method onDestroy takes nothing returns nothing
call ReleaseTimer(.loopTimer)
set .loopTimer = null
endmethod
private static method check takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
set OrderExecuted[.casterId] = false
call .destroy()
endmethod
static method start takes integer unitId returns nothing
local thistype this = thistype.allocate()
set .casterId = unitId
set .loopTimer = NewTimerEx(this)
if not OrderExecuted[.casterId] then
set OrderExecuted[.casterId] = true
endif
call TimerStart(.loopTimer, 1., false, function thistype.check)
endmethod
endstruct
struct CustomOrder
private integer unitId
private integer totalOrders = 0
private integer array order[MAX_ORDERS]
private integer array priority[MAX_ORDERS]
private real array cooldown[MAX_ORDERS]
private integer array manaCost[MAX_ORDERS]
private widget array target[MAX_ORDERS]
private real array locX[MAX_ORDERS]
private real array locY[MAX_ORDERS]
private boolean array locBased[MAX_ORDERS]
private method onDestroy takes nothing returns nothing
local integer i = 0
set HasCustomOrders[.unitId] = false
loop
exitwhen i >= .totalOrders
set target[i] = null
set i = i + 1
endloop
endmethod
static method create takes unit u returns thistype
local thistype this
local integer id
static if LIBRARY_UnitIndexerGUI then
set id = GetUnitId(u)
else
set id = GetUnitUserData(u)
endif
if not HasCustomOrders[id] then
set HasCustomOrders[id] = true
set this = thistype.allocate()
set .unitId = id
set RegOrders[.unitId] = this
return RegOrders[.unitId]
else
return RegOrders[id]
endif
endmethod
method checkOrder takes string orderStr returns boolean
local integer i = 0
local boolean isRegistered = false
local integer orderId = OrderId(orderStr)
loop
exitwhen i >= .totalOrders or isRegistered
if orderId == .order[i] then
set isRegistered = true
endif
set i = i + 1
endloop
return isRegistered
endmethod
method checkOrderById takes integer orderId returns boolean
local integer i = 0
local boolean isRegistered = false
loop
exitwhen i >= .totalOrders or isRegistered
if orderId == .order[i] then
set isRegistered = true
endif
set i = i + 1
endloop
return isRegistered
endmethod
method isOrderInCooldown takes string orderStr returns boolean
local integer orderId = OrderId(orderStr)
return OrderInCooldown[.unitId][orderId]
endmethod
method isOrderInCooldownById takes integer orderId returns boolean
return OrderInCooldown[.unitId][orderId]
endmethod
method registerOrder takes integer orderId, widget target, real locX, real locY, boolean locBased, integer priority, real cooldown, integer manaCost returns nothing
set .order[.totalOrders] = orderId
if priority < LOWEST_PRIO then
set .priority[.totalOrders] = LOWEST_PRIO
elseif priority > HIGHEST_PRIO then
set .priority[.totalOrders] = HIGHEST_PRIO
else
set .priority[.totalOrders] = priority
endif
set .cooldown[.totalOrders] = cooldown
set .manaCost[.totalOrders] = manaCost
set .target[.totalOrders] = target
set .locX[.totalOrders] = locX
set .locY[.totalOrders] = locY
set .locBased[.totalOrders] = locBased
set .totalOrders = .totalOrders + 1
endmethod
// String Orders
method registerTargetOrder takes string orderStr, widget target, integer priority, real cooldown, integer manaCost returns nothing
local integer orderId = OrderId(orderStr)
call .registerOrder(orderId, target, 0, 0, false, priority, cooldown, manaCost)
endmethod
method registerPointOrder takes string orderStr, real locX, real locY, integer priority, real cooldown, integer manaCost returns nothing
local integer orderId = OrderId(orderStr)
call .registerOrder(orderId, null, locX, locY, true, priority, cooldown, manaCost)
endmethod
method registerInstantOrder takes string orderStr, integer priority, real cooldown, integer manaCost returns nothing
local integer orderId = OrderId(orderStr)
call .registerOrder(orderId, null, 0, 0, false, priority, cooldown, manaCost)
endmethod
// Integer Orders
method registerTargetOrderById takes integer orderId, widget target, integer priority, real cooldown, integer manaCost returns nothing
call .registerOrder(orderId, target, 0, 0, false, priority, cooldown, manaCost)
endmethod
method registerPointOrderById takes integer orderId, real locX, real locY, integer priority, real cooldown, integer manaCost returns nothing
call .registerOrder(orderId, null, locX, locY, true, priority, cooldown, manaCost)
endmethod
method registerInstantOrderById takes integer orderId, integer priority, real cooldown, integer manaCost returns nothing
call .registerOrder(orderId, null, 0, 0, false, priority, cooldown, manaCost)
endmethod
private method orderByPriority takes nothing returns nothing
local integer i = 0
local integer j
local integer tempOrder = 0
local integer tempPriority = 0
local real tempCooldown = 0
local integer tempMana = 0
local widget tempTarget
local real tempX = 0
local real tempY = 0
local boolean tempLocBased = false
local integer tempIndex
loop
exitwhen i > .totalOrders - 1
set j = i
set tempIndex = i
loop
exitwhen j > .totalOrders - 1
if .priority[tempIndex] < .priority[j + 1] then
set tempIndex = j + 1
endif
set j = j + 1
endloop
set tempOrder = .order[i]
set tempPriority = .priority[i]
set tempCooldown = .cooldown[i]
set tempMana = .manaCost[i]
set tempTarget = .target[i]
set tempX = .locX[i]
set tempY = .locY[i]
set tempLocBased = .locBased[i]
set .order[i] = .order[tempIndex]
set .priority[i] = .priority[tempIndex]
set .cooldown[i] = .cooldown[tempIndex]
set .manaCost[i] = .manaCost[tempIndex]
set .target[i] = .target[tempIndex]
set .locX[i] = .locX[tempIndex]
set .locY[i] = .locY[tempIndex]
set .locBased[i] = .locBased[tempIndex]
set .order[tempIndex] = tempOrder
set .priority[tempIndex] = tempPriority
set .cooldown[tempIndex] = tempCooldown
set .manaCost[tempIndex] = tempMana
set .target[tempIndex] = tempTarget
set .locX[tempIndex] = tempX
set .locY[tempIndex] = tempY
set .locBased[tempIndex] = tempLocBased
set i = i + 1
endloop
set tempTarget = null
endmethod
static method runOrders takes CustomOrder o returns nothing
local thistype this = o
local integer i = 0
local unit caster
local real casterMana
local integer tempOrder
static if LIBRARY_UnitIndexerGUI then
set caster = GetUnitById(.unitId)
else
set caster = udg_UDexUnits[.unitId]
endif
set casterMana = GetUnitState(caster, UNIT_STATE_MANA)
if HasCustomOrders[.unitId] then
call .orderByPriority()
loop
exitwhen i >= .totalOrders or OrderExecuted[.unitId]
if not .isOrderInCooldownById(.order[i]) and casterMana >= .manaCost[i] then
if .target[i] != null then
call IssueTargetOrderById(caster, .order[i], .target[i])
elseif .locBased[i] then
call IssuePointOrderById(caster, .order[i], .locX[i], .locY[i])
else
call IssueImmediateOrderById(caster, .order[i])
endif
call Cooldown.start(.unitId, .order[i], .cooldown[i])
call PreventNewOrders.start(.unitId)
endif
set i = i + 1
endloop
endif
set caster = null
call .destroy()
endmethod
endstruct
private module Init
private static method onInit takes nothing returns nothing
call thistype.initArrays()
endmethod
endmodule
struct Controller extends array
private static timer loopTimer = CreateTimer()
//! textmacro LOAD_BEHAVIOR takes opName
set id = GetUnitTypeId(u)
if GetPlayerController(GetOwningPlayer(u)) != MAP_CONTROL_USER then
set i = 0
loop
exitwhen i == TotalBehaviorsType[id]
set b = UnitTypeBehavior[id][i]
call b.$opName$(u, secU)
set i = i + 1
endloop
static if LIBRARY_UnitIndexerGUI then
set id = GetUnitId(u)
else
set id = GetUnitUserData(u)
endif
set i = 0
loop
exitwhen i == TotalBehaviors[id]
set b = UnitBehavior[id][i]
call b.$opName$(u, secU)
set i = i + 1
endloop
if HasCustomOrders[id] then
call CustomOrder.runOrders(RegOrders[id])
endif
endif
//! endtextmacro
//! textmacro LOAD_BEHAVIOR_OTHERS takes opName
set id = GetUnitTypeId(u)
if GetPlayerController(GetOwningPlayer(u)) != MAP_CONTROL_USER then
set i = 0
loop
exitwhen i == TotalBehaviorsType[id]
set b = UnitTypeBehavior[id][i]
call b.$opName$(u, eventU, secU)
set i = i + 1
endloop
static if LIBRARY_UnitIndexerGUI then
set id = GetUnitId(u)
else
set id = GetUnitUserData(u)
endif
set i = 0
loop
exitwhen i == TotalBehaviors[id]
set b = UnitBehavior[id][i]
call b.$opName$(u, eventU, secU)
set i = i + 1
endloop
if HasCustomOrders[id] then
call CustomOrder.runOrders(RegOrders[id])
endif
endif
//! endtextmacro
public static method registerBehavior takes unit u, Behavior b returns nothing
local integer i
local integer unitId
static if LIBRARY_UnitIndexerGUI then
set unitId = GetUnitId(u)
else
set unitId = GetUnitUserData(u)
endif
set i = TotalBehaviors[unitId]
set UnitBehavior[unitId][i] = b
set TotalBehaviors[unitId] = TotalBehaviors[unitId] + 1
endmethod
public static method registerBehaviorType takes integer uTypeId, Behavior b returns nothing
local integer i = TotalBehaviorsType[uTypeId]
set UnitTypeBehavior[uTypeId][i] = b
set TotalBehaviorsType[uTypeId] = TotalBehaviorsType[uTypeId] + 1
endmethod
public static method removeBehavior takes unit u, Behavior b returns nothing
local integer i = 0
local integer unitId
static if LIBRARY_UnitIndexerGUI then
set unitId = GetUnitId(u)
else
set unitId = GetUnitUserData(u)
endif
loop
exitwhen i == TotalBehaviors[unitId]
if UnitBehavior[unitId][i] == b then
set UnitBehavior[unitId][i] = 0
endif
set i = i + 1
endloop
endmethod
public static method removeBehaviorType takes integer uTypeId, Behavior b returns nothing
local integer i = 0
loop
exitwhen i == TotalBehaviorsType[uTypeId]
if UnitTypeBehavior[uTypeId][i] == b then
set UnitTypeBehavior[uTypeId][i] = 0
endif
set i = i + 1
endloop
endmethod
private static method registerCast takes nothing returns boolean
local unit u
local unit secU
local integer id
local Behavior b
local group g1 = CreateGroup()
local group g2 = CreateGroup()
local unit eventU
local integer i
set u = GetSpellAbilityUnit()
set secU = GetSpellTargetUnit()
//! runtextmacro LOAD_BEHAVIOR("onCast")
set u = GetSpellTargetUnit()
set secU = GetSpellAbilityUnit()
//! runtextmacro LOAD_BEHAVIOR("onTargeted")
if OTHER_UNITS_EVENTS then
set eventU = GetSpellAbilityUnit()
set secU = GetSpellTargetUnit()
call GroupEnumUnitsWithCollision(g1, GetUnitX(eventU), GetUnitY(eventU), UNIT_SEARCH_RANGE)
loop
set u = FirstOfGroup(g1)
exitwhen u == null
if IsUnitAlly(eventU, GetOwningPlayer(u)) and eventU != u then
//! runtextmacro LOAD_BEHAVIOR_OTHERS("onAllyCasts")
elseif IsUnitEnemy(eventU, GetOwningPlayer(u)) and eventU != u then
//! runtextmacro LOAD_BEHAVIOR_OTHERS("onEnemyCasts")
endif
call GroupRemoveUnit(g1, u)
set u = null
endloop
set eventU = GetSpellTargetUnit()
set secU = GetSpellAbilityUnit()
call GroupEnumUnitsWithCollision(g2, GetUnitX(eventU), GetUnitY(eventU), UNIT_SEARCH_RANGE)
loop
set u = FirstOfGroup(g2)
exitwhen u == null
if IsUnitAlly(eventU, GetOwningPlayer(u)) and eventU != u then
//! runtextmacro LOAD_BEHAVIOR_OTHERS("onAllyTargeted")
elseif IsUnitEnemy(eventU, GetOwningPlayer(u)) and eventU != u then
//! runtextmacro LOAD_BEHAVIOR_OTHERS("onEnemyTargeted")
endif
call GroupRemoveUnit(g2, u)
set u = null
endloop
set eventU = null
endif
call DestroyGroup(g1)
call DestroyGroup(g2)
set g1 = null
set g2 = null
set u = null
set secU = null
return false
endmethod
private static method registerAttack takes nothing returns boolean
local unit u
local unit secU
local integer id
local Behavior b
local group g1 = CreateGroup()
local group g2 = CreateGroup()
local unit eventU
local integer i
set u = GetAttacker()
set secU = GetTriggerUnit()
//! runtextmacro LOAD_BEHAVIOR("onAttack")
set u = GetTriggerUnit()
set secU = GetAttacker()
//! runtextmacro LOAD_BEHAVIOR("onAttacked")
if OTHER_UNITS_EVENTS then
set eventU = GetAttacker()
set secU = GetTriggerUnit()
call GroupEnumUnitsWithCollision(g1, GetUnitX(eventU), GetUnitY(eventU), UNIT_SEARCH_RANGE)
loop
set u = FirstOfGroup(g1)
exitwhen u == null
if IsUnitAlly(eventU, GetOwningPlayer(u)) and eventU != u then
//! runtextmacro LOAD_BEHAVIOR_OTHERS("onAllyAttacks")
elseif IsUnitEnemy(eventU, GetOwningPlayer(u)) and eventU != u then
//! runtextmacro LOAD_BEHAVIOR_OTHERS("onEnemyAttacks")
endif
call GroupRemoveUnit(g1, u)
set u = null
endloop
set eventU = GetTriggerUnit()
set secU = GetAttacker()
call GroupEnumUnitsWithCollision(g2, GetUnitX(eventU), GetUnitY(eventU), UNIT_SEARCH_RANGE)
loop
set u = FirstOfGroup(g2)
exitwhen u == null
if IsUnitAlly(eventU, GetOwningPlayer(u)) and eventU != u then
//! runtextmacro LOAD_BEHAVIOR_OTHERS("onAllyAttacked")
elseif IsUnitEnemy(eventU, GetOwningPlayer(u)) and eventU != u then
//! runtextmacro LOAD_BEHAVIOR_OTHERS("onEnemyAttacked")
endif
call GroupRemoveUnit(g2, u)
set u = null
endloop
set eventU = null
endif
call DestroyGroup(g1)
call DestroyGroup(g2)
set g1 = null
set g2 = null
set u = null
set secU = null
return false
endmethod
private static method registerDamage takes nothing returns boolean
local unit u
local unit secU
local integer id
local Behavior b
local group g1 = CreateGroup()
local group g2 = CreateGroup()
local unit eventU
local integer i
if udg_DamageEventAmount >= MIN_DMG then
set u = udg_DamageEventSource
set secU = udg_DamageEventTarget
//! runtextmacro LOAD_BEHAVIOR("onDamageDealt")
set u = udg_DamageEventTarget
set secU = udg_DamageEventSource
//! runtextmacro LOAD_BEHAVIOR("onDamageTaken")
if OTHER_UNITS_EVENTS then
set eventU = udg_DamageEventSource
set secU = udg_DamageEventTarget
call GroupEnumUnitsWithCollision(g1, GetUnitX(eventU), GetUnitY(eventU), UNIT_SEARCH_RANGE)
loop
set u = FirstOfGroup(g1)
exitwhen u == null
if IsUnitAlly(eventU, GetOwningPlayer(u)) and eventU != u then
//! runtextmacro LOAD_BEHAVIOR_OTHERS("onAllyDmgDealt")
elseif IsUnitEnemy(eventU, GetOwningPlayer(u)) and eventU != u then
//! runtextmacro LOAD_BEHAVIOR_OTHERS("onEnemyDmgDealt")
endif
call GroupRemoveUnit(g1, u)
set u = null
endloop
set eventU = udg_DamageEventTarget
set secU = udg_DamageEventSource
call GroupEnumUnitsWithCollision(g2, GetUnitX(eventU), GetUnitY(eventU), UNIT_SEARCH_RANGE)
loop
set u = FirstOfGroup(g2)
exitwhen u == null
if IsUnitAlly(eventU, GetOwningPlayer(u)) and eventU != u then
//! runtextmacro LOAD_BEHAVIOR_OTHERS("onAllyDmgTaken")
elseif IsUnitEnemy(eventU, GetOwningPlayer(u)) and eventU != u then
//! runtextmacro LOAD_BEHAVIOR_OTHERS("onEnemyDmgTaken")
endif
call GroupRemoveUnit(g2, u)
set u = null
endloop
set eventU = null
endif
endif
call DestroyGroup(g1)
call DestroyGroup(g2)
set g1 = null
set g2 = null
set u = null
set secU = null
return false
endmethod
private static method registerKill takes nothing returns boolean
local unit u
local unit secU
local integer id
local Behavior b
local group g1 = CreateGroup()
local group g2 = CreateGroup()
local unit eventU
local integer i
set u = GetKillingUnit()
set secU = GetDyingUnit()
//! runtextmacro LOAD_BEHAVIOR("onKill")
if OTHER_UNITS_EVENTS then
set eventU = GetKillingUnit()
set secU = GetDyingUnit()
call GroupEnumUnitsWithCollision(g1, GetUnitX(eventU), GetUnitY(eventU), UNIT_SEARCH_RANGE)
loop
set u = FirstOfGroup(g1)
exitwhen u == null
if IsUnitAlly(eventU, GetOwningPlayer(u)) and eventU != u then
//! runtextmacro LOAD_BEHAVIOR_OTHERS("onAllyKills")
elseif IsUnitEnemy(eventU, GetOwningPlayer(u)) and eventU != u then
//! runtextmacro LOAD_BEHAVIOR_OTHERS("onEnemyKills")
endif
call GroupRemoveUnit(g1, u)
set u = null
endloop
set eventU = GetDyingUnit()
set secU = GetKillingUnit()
call GroupEnumUnitsWithCollision(g2, GetUnitX(eventU), GetUnitY(eventU), UNIT_SEARCH_RANGE)
loop
set u = FirstOfGroup(g2)
exitwhen u == null
if IsUnitAlly(eventU, GetOwningPlayer(u)) and eventU != u then
//! runtextmacro LOAD_BEHAVIOR_OTHERS("onAllyDeath")
elseif IsUnitEnemy(eventU, GetOwningPlayer(u)) and eventU != u then
//! runtextmacro LOAD_BEHAVIOR_OTHERS("onEnemyDeath")
endif
call GroupRemoveUnit(g2, u)
set u = null
endloop
set eventU = null
endif
call DestroyGroup(g1)
call DestroyGroup(g2)
set g1 = null
set g2 = null
set u = null
set secU = null
return false
endmethod
private static method registerPeriod takes nothing returns nothing
local group allUnits = CreateGroup()
local unit u
local integer id
local Behavior b
local integer i
call GroupEnumUnitsInRect(allUnits, bj_mapInitialPlayableArea, null)
loop
set u = FirstOfGroup(allUnits)
exitwhen u == null
set id = GetUnitTypeId(u)
if GetPlayerController(GetOwningPlayer(u)) != MAP_CONTROL_USER then
set i = 0
loop
exitwhen i == TotalBehaviorsType[id]
set b = UnitTypeBehavior[id][i]
call b.onPeriod(u)
set i = i + 1
endloop
static if LIBRARY_UnitIndexerGUI then
set id = GetUnitId(u)
else
set id = GetUnitUserData(u)
endif
set i = 0
loop
exitwhen i == TotalBehaviors[id]
set b = UnitBehavior[id][i]
call b.onPeriod(u)
set i = i + 1
endloop
if HasCustomOrders[id] then
call CustomOrder.runOrders(RegOrders[id])
endif
endif
call GroupRemoveUnit(allUnits, u)
set u = null
endloop
call DestroyGroup(allUnits)
set allUnits = null
endmethod
private static method initArrays takes nothing returns nothing
set OrderInCooldown = Boolean2D.create()
set OrderExecuted = Boolean1D.create()
set RegOrders = Integer1D.create()
set UnitBehavior = Integer2D.create()
set UnitTypeBehavior = Integer2D.create()
set HasCustomOrders = Boolean1D.create()
set TotalBehaviors = Integer1D.create()
set TotalBehaviorsType = Integer1D.create()
endmethod
implement Init
private static method onInit takes nothing returns nothing
local trigger castEvent = CreateTrigger()
local trigger attackEvent = CreateTrigger()
local trigger damageEvent = CreateTrigger()
local trigger killEvent = CreateTrigger()
static if LIBRARY_RegisterPlayerUnitEvent then
call RegisterAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_EFFECT, function thistype.registerCast)
call RegisterAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_ATTACKED, function thistype.registerAttack)
call RegisterAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function thistype.registerKill)
call DestroyTrigger(castEvent)
call DestroyTrigger(attackEvent)
call DestroyTrigger(killEvent)
else
call TriggerRegisterAnyUnitEventBJ(castEvent, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(castEvent, function thistype.registerCast)
call TriggerRegisterAnyUnitEventBJ(attackEvent, EVENT_PLAYER_UNIT_ATTACKED)
call TriggerAddCondition(attackEvent, function thistype.registerAttack)
call TriggerRegisterAnyUnitEventBJ(killEvent, EVENT_PLAYER_UNIT_DEATH)
call TriggerAddCondition(killEvent, function thistype.registerKill)
endif
call TriggerRegisterVariableEvent(damageEvent, "udg_DamageEvent", EQUAL, 1.0)
call TriggerAddCondition(damageEvent, function thistype.registerDamage)
call TimerStart(thistype.loopTimer, PERIODIC_INTERVAL, true, function thistype.registerPeriod)
set castEvent = null
set attackEvent = null
set damageEvent = null
set killEvent = null
endmethod
endstruct
endlibrary
//TESH.scrollpos=51
//TESH.alwaysfold=0
library UnitIndexerGUI //requires GUI Unit Indexer
globals
private trigger index = null
private trigger deindex = null
private trigger init = null
private trigger tempTrig
endglobals
private function DoTheThings takes trigger t, code c, real r returns trigger
if t == null then
set t = CreateTrigger()
call TriggerRegisterVariableEvent(t, "udg_UnitIndexEvent", EQUAL, r)
endif
call TriggerAddCondition(t, Filter(c))
set tempTrig = t
set t = null
return tempTrig
endfunction
//call RegisterUnitIndexEvent(Filter(function Blah), EVENT_UNIT_INDEXED)
//->
//call OnUnitIndex(function Blah)
function OnUnitIndex takes code c returns nothing
set index = DoTheThings(index, c, 1.)
endfunction
//call RegisterUnitIndexEvent(Filter(function Blah), EVENT_UNIT_DEINDEXED)
//->
//call OnUnitDeindex(function Blah)
function OnUnitDeindex takes code c returns nothing
set deindex = DoTheThings(deindex, c, 2.)
endfunction
private function DestroyInit takes nothing returns boolean
call DestroyTrigger(init) //will still allow consecutive triggerconditions to run.
set init = null
return false
endfunction
//GUI Unit Indexer will initialize after any vJass stuff, so you need to do your
//unit-indexer-requiring stuff after this event instead of a module/struct/library
//initializer.
function OnUnitIndexerInitialized takes code c returns nothing
if init == null then
set init = CreateTrigger()
call TriggerAddCondition(init, Filter(function DestroyInit))
call TriggerRegisterVariableEvent(init, "udg_UnitIndexEvent", EQUAL, 3.00)
endif
call TriggerAddCondition(init, Filter(c))
endfunction
function GetUnitId takes unit u returns integer
return GetUnitUserData(u)
endfunction
function GetUnitById takes integer id returns unit
return udg_UDexUnits[id]
endfunction
function GetIndexedUnit takes nothing returns unit
return udg_UDexUnits[udg_UDex]
endfunction
function GetIndexedUnitId takes nothing returns integer
return udg_UDex
endfunction
function IsUnitIndexed takes unit u returns boolean
return udg_UDexUnits[GetUnitUserData(u)] == u
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
/*****************************************************************************
*
* RegisterNativeEvent v1.1.1.2
* by Bannar
*
* Storage of trigger handles for native events.
*
******************************************************************************
*
* Optional requirements:
*
* Table by Bribe
* hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/
*
******************************************************************************
*
* Important:
*
* Avoid using TriggerSleepAction within functions registered.
* Destroy native event trigger on your own responsibility.
*
******************************************************************************
*
* Core:
*
* function IsNativeEventRegistered takes integer whichIndex, integer whichEvent returns boolean
* Whether index whichIndex has already been attached to event whichEvent.
*
* function RegisterNativeEventTrigger takes integer whichIndex, integer eventId returns boolean
* Registers whichIndex within whichEvent scope and assigns new trigger handle for it.
*
* function GetIndexNativeEventTrigger takes integer whichIndex, integer whichEvent returns trigger
* Retrieves trigger handle for event whichEvent specific to provided index whichIndex.
*
* function GetNativeEventTrigger takes integer whichEvent returns trigger
* Retrieves trigger handle for event whichEvent.
*
*
* Custom events:
*
* function CreateNativeEvent takes nothing returns integer
* Returns unique id for new event and registers it with RegisterNativeEvent.
*
* function RegisterIndexNativeEvent takes integer whichIndex, integer whichEvent, code func returns nothing
* Registers new event handler func for event whichEvent specific to index whichIndex.
*
* function RegisterNativeEvent takes integer whichEvent, code func returns nothing
* Registers new event handler func for specified event whichEvent.
*
*****************************************************************************/
library RegisterNativeEvent uses optional Table
globals
private integer eventIndex = 500 // 0-499 reserved for Blizzard native events
endglobals
private module NativeEventInit
private static method onInit takes nothing returns nothing
static if LIBRARY_Table then
set table = TableArray[0x2000]
endif
endmethod
endmodule
private struct NativeEvent extends array
static if LIBRARY_Table then
static TableArray table
else
static hashtable table = InitHashtable()
endif
implement NativeEventInit
endstruct
function IsNativeEventRegistered takes integer whichIndex, integer whichEvent returns boolean
static if LIBRARY_Table then
return NativeEvent.table[whichEvent].trigger.has(whichIndex)
else
return HaveSavedHandle(NativeEvent.table, whichEvent, whichIndex)
endif
endfunction
function RegisterNativeEventTrigger takes integer whichIndex, integer whichEvent returns boolean
if not IsNativeEventRegistered(whichIndex, whichEvent) then
static if LIBRARY_Table then
set NativeEvent.table[whichEvent].trigger[whichIndex] = CreateTrigger()
else
call SaveTriggerHandle(NativeEvent.table, whichEvent, whichIndex, CreateTrigger())
endif
return true
endif
return false
endfunction
function GetIndexNativeEventTrigger takes integer whichIndex, integer whichEvent returns trigger
static if LIBRARY_Table then
return NativeEvent.table[whichEvent].trigger[whichIndex]
else
return LoadTriggerHandle(NativeEvent.table, whichEvent, whichIndex)
endif
endfunction
function GetNativeEventTrigger takes integer whichEvent returns trigger
return GetIndexNativeEventTrigger(bj_MAX_PLAYER_SLOTS, whichEvent)
endfunction
function CreateNativeEvent takes nothing returns integer
local integer eventId = eventIndex
call RegisterNativeEventTrigger(bj_MAX_PLAYER_SLOTS, eventId)
set eventIndex = eventIndex + 1
return eventId
endfunction
function RegisterIndexNativeEvent takes integer whichIndex, integer whichEvent, code func returns nothing
call RegisterNativeEventTrigger(whichIndex, whichEvent)
call TriggerAddCondition(GetIndexNativeEventTrigger(whichIndex, whichEvent), Condition(func))
endfunction
function RegisterNativeEvent takes integer whichEvent, code func returns nothing
call RegisterIndexNativeEvent(bj_MAX_PLAYER_SLOTS, whichEvent, func)
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
/*****************************************************************************
*
* RegisterPlayerUnitEvent v1.0.3.2
* by Bannar
*
* Register version of TriggerRegisterPlayerUnitEvent.
*
* Special thanks to Magtheridon96, Bribe, azlier and BBQ for the original library version.
*
******************************************************************************
*
* Requirements:
*
* RegisterNativeEvent by Bannar
* hiveworkshop.com/threads/snippet-registerevent-pack.250266/
*
******************************************************************************
*
* Functions:
*
* function GetAnyPlayerUnitEventTrigger takes playerunitevent whichEvent returns trigger
* Retrieves trigger handle for playerunitevent whichEvent.
*
* function GetPlayerUnitEventTrigger takes player whichPlayer, playerunitevent whichEvent returns trigger
* Retrieves trigger handle for playerunitevent whichEvent specific to player whichPlayer.
*
* function RegisterAnyPlayerUnitEvent takes playerunitevent whichEvent, code func returns nothing
* Registers generic playerunitevent whichEvent adding code func as callback.
*
* function RegisterPlayerUnitEvent takes player whichPlayer, playerunitevent whichEvent, code func returns nothing
* Registers playerunitevent whichEvent for player whichPlayer adding code func as callback.
*
*****************************************************************************/
library RegisterPlayerUnitEvent requires RegisterNativeEvent
function GetAnyPlayerUnitEventTrigger takes playerunitevent whichEvent returns trigger
return GetNativeEventTrigger(GetHandleId(whichEvent))
endfunction
function GetPlayerUnitEventTrigger takes player whichPlayer, playerunitevent whichEvent returns trigger
return GetIndexNativeEventTrigger(GetPlayerId(whichPlayer), GetHandleId(whichEvent))
endfunction
function RegisterAnyPlayerUnitEvent takes playerunitevent whichEvent, code func returns nothing
local integer eventId = GetHandleId(whichEvent)
local integer index = 0
local trigger t = null
if RegisterNativeEventTrigger(bj_MAX_PLAYER_SLOTS, eventId) then
set t = GetNativeEventTrigger(eventId)
loop
call TriggerRegisterPlayerUnitEvent(t, Player(index), whichEvent, null)
set index = index + 1
exitwhen index == bj_MAX_PLAYER_SLOTS
endloop
set t = null
endif
call RegisterNativeEvent(eventId, func)
endfunction
function RegisterPlayerUnitEvent takes player whichPlayer, playerunitevent whichEvent, code func returns nothing
local integer playerId = GetPlayerId(whichPlayer)
local integer eventId = GetHandleId(whichEvent)
if RegisterNativeEventTrigger(playerId, eventId) then
call TriggerRegisterPlayerUnitEvent(GetIndexNativeEventTrigger(playerId, eventId), whichPlayer, whichEvent, null)
endif
call RegisterIndexNativeEvent(playerId, eventId, func)
endfunction
endlibrary
library AIBCAdapterGUI requires AIBehaviorController
// Clear variables to avoid accidentally inserting old values into new Behaviors
private function ClearVariables takes nothing returns nothing
set udg_Event_Caster = null
set udg_Event_Attacker = null
set udg_Event_Source = null
set udg_Event_Target = null
set udg_Event_Killer = null
set udg_Event_Victim = null
set udg_Event_Unit = null
set udg_Event_Ally = null
set udg_Event_Enemy = null
set udg_Behavior_Unit = null
set udg_Behavior_UnitType = 0
set udg_Behavior_OnPeriod = null
set udg_Behavior_OnCast = null
set udg_Behavior_OnTargeted = null
set udg_Behavior_OnAttack = null
set udg_Behavior_OnAttacked = null
set udg_Behavior_OnDamageDealt = null
set udg_Behavior_OnDamageTaken = null
set udg_Behavior_OnKill = null
set udg_Behavior_OnAllyCasts = null
set udg_Behavior_OnAllyTargeted = null
set udg_Behavior_OnAllyAttacks = null
set udg_Behavior_OnAllyAttacked = null
set udg_Behavior_OnAllyDmgDealt = null
set udg_Behavior_OnAllyDmgTaken = null
set udg_Behavior_OnAllyKills = null
set udg_Behavior_OnAllyDeath = null
set udg_Behavior_OnEnemyCasts = null
set udg_Behavior_OnEnemyTargeted = null
set udg_Behavior_OnEnemyAttacks = null
set udg_Behavior_OnEnemyAttacked = null
set udg_Behavior_OnEnemyDmgDealt = null
set udg_Behavior_OnEnemyDmgTaken = null
set udg_Behavior_OnEnemyKills = null
set udg_Behavior_OnEnemyDeath = null
call RemoveLocation(udg_CustomO_Location)
set udg_CustomO_Unit = null
set udg_CustomO_Target = null
set udg_CustomO_Location = null
set udg_CustomO_Priority = 0
set udg_CustomO_Cooldown = 0
set udg_CustomO_ManaCost = 0
set udg_CustomO_IsInCooldown = false
endfunction
// Behavior Template
private struct NewB extends Behavior
private trigger OnPeriod
private trigger OnCast
private trigger OnTargeted
private trigger OnAttack
private trigger OnAttacked
private trigger OnDamageDealt
private trigger OnDamageTaken
private trigger OnKill
private trigger OnAllyCasts
private trigger OnAllyTargeted
private trigger OnAllyAttacks
private trigger OnAllyAttacked
private trigger OnAllyDmgDealt
private trigger OnAllyDmgTaken
private trigger OnAllyKills
private trigger OnAllyDeath
private trigger OnEnemyCasts
private trigger OnEnemyTargeted
private trigger OnEnemyAttacks
private trigger OnEnemyAttacked
private trigger OnEnemyDmgDealt
private trigger OnEnemyDmgTaken
private trigger OnEnemyKills
private trigger OnEnemyDeath
private method assignVariables takes nothing returns nothing
set .OnPeriod = udg_Behavior_OnPeriod
set .OnCast = udg_Behavior_OnCast
set .OnTargeted = udg_Behavior_OnTargeted
set .OnAttack = udg_Behavior_OnAttack
set .OnAttacked = udg_Behavior_OnAttacked
set .OnDamageDealt = udg_Behavior_OnDamageDealt
set .OnDamageTaken = udg_Behavior_OnDamageTaken
set .OnKill = udg_Behavior_OnKill
set .OnAllyCasts = udg_Behavior_OnAllyCasts
set .OnAllyTargeted = udg_Behavior_OnAllyTargeted
set .OnAllyAttacks = udg_Behavior_OnAllyAttacks
set .OnAllyAttacked = udg_Behavior_OnAllyAttacked
set .OnAllyDmgDealt = udg_Behavior_OnAllyDmgDealt
set .OnAllyDmgTaken = udg_Behavior_OnAllyDmgTaken
set .OnAllyKills = udg_Behavior_OnAllyKills
set .OnAllyDeath = udg_Behavior_OnAllyDeath
set .OnEnemyCasts = udg_Behavior_OnEnemyCasts
set .OnEnemyTargeted = udg_Behavior_OnEnemyTargeted
set .OnEnemyAttacks = udg_Behavior_OnEnemyAttacks
set .OnEnemyAttacked = udg_Behavior_OnEnemyAttacked
set .OnEnemyDmgDealt = udg_Behavior_OnEnemyDmgDealt
set .OnEnemyDmgTaken = udg_Behavior_OnEnemyDmgTaken
set .OnEnemyKills = udg_Behavior_OnEnemyKills
set .OnEnemyDeath = udg_Behavior_OnEnemyDeath
endmethod
method onPeriod takes unit u returns nothing
if .OnPeriod != null then
set udg_Event_Unit = u
if TriggerEvaluate(.OnPeriod) then
call TriggerExecute(.OnPeriod)
endif
endif
endmethod
method onCast takes unit caster, unit target returns nothing
if .OnCast != null then
set udg_Event_Caster = caster
set udg_Event_Target = target
if TriggerEvaluate(.OnCast) then
call TriggerExecute(.OnCast)
endif
endif
endmethod
method onTargeted takes unit target, unit caster returns nothing
if .OnTargeted != null then
set udg_Event_Target = target
set udg_Event_Caster = caster
if TriggerEvaluate(.OnTargeted) then
call TriggerExecute(.OnTargeted)
endif
endif
endmethod
method onAttack takes unit attacker, unit target returns nothing
if .OnAttack != null then
set udg_Event_Attacker = attacker
set udg_Event_Target = target
if TriggerEvaluate(.OnAttack) then
call TriggerExecute(.OnAttack)
endif
endif
endmethod
method onAttacked takes unit target, unit attacker returns nothing
if .OnAttacked != null then
set udg_Event_Target = target
set udg_Event_Attacker = attacker
if TriggerEvaluate(.OnAttacked) then
call TriggerExecute(.OnAttacked)
endif
endif
endmethod
method onDamageDealt takes unit source, unit target returns nothing
if .OnDamageDealt != null then
set udg_Event_Source = source
set udg_Event_Target = target
if TriggerEvaluate(.OnDamageDealt) then
call TriggerExecute(.OnDamageDealt)
endif
endif
endmethod
method onDamageTaken takes unit target, unit source returns nothing
if .OnDamageTaken != null then
set udg_Event_Target = target
set udg_Event_Source = source
if TriggerEvaluate(.OnDamageTaken) then
call TriggerExecute(.OnDamageTaken)
endif
endif
endmethod
method onKill takes unit killer, unit victim returns nothing
if .OnKill != null then
set udg_Event_Killer = killer
set udg_Event_Victim = victim
if TriggerEvaluate(.OnKill) then
call TriggerExecute(.OnKill)
endif
endif
endmethod
method onAllyCasts takes unit u, unit ally, unit target returns nothing
if .OnAllyCasts != null then
set udg_Event_Unit = u
set udg_Event_Ally = ally
set udg_Event_Target = target
if TriggerEvaluate(.OnAllyCasts) then
call TriggerExecute(.OnAllyCasts)
endif
endif
endmethod
method onAllyTargeted takes unit u, unit ally, unit caster returns nothing
if .OnAllyTargeted != null then
set udg_Event_Unit = u
set udg_Event_Ally = ally
set udg_Event_Caster = caster
if TriggerEvaluate(.OnAllyTargeted) then
call TriggerExecute(.OnAllyTargeted)
endif
endif
endmethod
method onAllyAttacks takes unit u, unit ally, unit target returns nothing
if .OnAllyAttacks != null then
set udg_Event_Unit = u
set udg_Event_Ally = ally
set udg_Event_Target = target
if TriggerEvaluate(.OnAllyAttacks) then
call TriggerExecute(.OnAllyAttacks)
endif
endif
endmethod
method onAllyAttacked takes unit u, unit ally, unit attacker returns nothing
if .OnAllyAttacked != null then
set udg_Event_Unit = u
set udg_Event_Ally = ally
set udg_Event_Attacker = attacker
if TriggerEvaluate(.OnAllyAttacked) then
call TriggerExecute(.OnAllyAttacked)
endif
endif
endmethod
method onAllyDmgDealt takes unit u, unit ally, unit target returns nothing
if .OnAllyDmgDealt != null then
set udg_Event_Unit = u
set udg_Event_Ally = ally
set udg_Event_Target = target
if TriggerEvaluate(.OnAllyDmgDealt) then
call TriggerExecute(.OnAllyDmgDealt)
endif
endif
endmethod
method onAllyDmgTaken takes unit u, unit ally, unit source returns nothing
if .OnAllyDmgTaken != null then
set udg_Event_Unit = u
set udg_Event_Ally = ally
set udg_Event_Source = source
if TriggerEvaluate(.OnAllyDmgTaken) then
call TriggerExecute(.OnAllyDmgTaken)
endif
endif
endmethod
method onAllyKills takes unit u, unit ally, unit victim returns nothing
if .OnAllyKills != null then
set udg_Event_Unit = u
set udg_Event_Ally = ally
set udg_Event_Victim = victim
if TriggerEvaluate(.OnAllyKills) then
call TriggerExecute(.OnAllyKills)
endif
endif
endmethod
method onAllyDeath takes unit u, unit ally, unit killer returns nothing
if .OnAllyDeath != null then
set udg_Event_Unit = u
set udg_Event_Ally = ally
set udg_Event_Killer = killer
if TriggerEvaluate(.OnAllyDeath) then
call TriggerExecute(.OnAllyDeath)
endif
endif
endmethod
method onEnemyCasts takes unit u, unit enemy, unit target returns nothing
if .OnEnemyCasts != null then
set udg_Event_Unit = u
set udg_Event_Enemy = enemy
set udg_Event_Target = target
if TriggerEvaluate(.OnEnemyCasts) then
call TriggerExecute(.OnEnemyCasts)
endif
endif
endmethod
method onEnemyTargeted takes unit u, unit enemy, unit caster returns nothing
if .OnEnemyTargeted != null then
set udg_Event_Unit = u
set udg_Event_Enemy = enemy
set udg_Event_Caster = caster
if TriggerEvaluate(.OnEnemyTargeted) then
call TriggerExecute(.OnEnemyTargeted)
endif
endif
endmethod
method onEnemyAttacks takes unit u, unit enemy, unit target returns nothing
if .OnEnemyAttacks != null then
set udg_Event_Unit = u
set udg_Event_Enemy = enemy
set udg_Event_Target = target
if TriggerEvaluate(.OnEnemyAttacks) then
call TriggerExecute(.OnEnemyAttacks)
endif
endif
endmethod
method onEnemyAttacked takes unit u, unit enemy, unit attacker returns nothing
if .OnEnemyAttacked != null then
set udg_Event_Unit = u
set udg_Event_Enemy = enemy
set udg_Event_Attacker = attacker
if TriggerEvaluate(.OnEnemyAttacked) then
call TriggerExecute(.OnEnemyAttacked)
endif
endif
endmethod
method onEnemyDmgDealt takes unit u, unit enemy, unit target returns nothing
if .OnEnemyDmgDealt != null then
set udg_Event_Unit = u
set udg_Event_Enemy = enemy
set udg_Event_Target = target
if TriggerEvaluate(.OnEnemyDmgDealt) then
call TriggerExecute(.OnEnemyDmgDealt)
endif
endif
endmethod
method onEnemyDmgTaken takes unit u, unit enemy, unit source returns nothing
if .OnEnemyDmgTaken != null then
set udg_Event_Unit = u
set udg_Event_Enemy = enemy
set udg_Event_Source = source
if TriggerEvaluate(.OnEnemyDmgTaken) then
call TriggerExecute(.OnEnemyDmgTaken)
endif
endif
endmethod
method onEnemyKills takes unit u, unit enemy, unit victim returns nothing
if .OnEnemyKills != null then
set udg_Event_Unit = u
set udg_Event_Enemy = enemy
set udg_Event_Victim = victim
if TriggerEvaluate(.OnEnemyKills) then
call TriggerExecute(.OnEnemyKills)
endif
endif
endmethod
method onEnemyDeath takes unit u, unit enemy, unit killer returns nothing
if .OnEnemyDeath != null then
set udg_Event_Unit = u
set udg_Event_Enemy = enemy
set udg_Event_Killer = killer
if TriggerEvaluate(.OnEnemyDeath) then
call TriggerExecute(.OnEnemyDeath)
endif
endif
endmethod
static method attach takes unit u returns nothing
local NewB b = NewB.create()
call b.assignVariables()
call Controller.registerBehavior(u, b)
endmethod
static method attachType takes integer uTypeId returns nothing
local NewB b = NewB.create()
call b.assignVariables()
call Controller.registerBehaviorType(uTypeId, b)
endmethod
endstruct
function AIBC_GUI_RegisterBehavior takes boolean isUnitType returns nothing
if isUnitType then
call NewB.attachType(udg_Behavior_UnitType)
else
call NewB.attach(udg_Behavior_Unit)
endif
call ClearVariables()
endfunction
endlibrary
//TESH.scrollpos=75
//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
//===========================================================================
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 id = 0
local unit u
loop
set id = udg_CheckDeathList[id]
exitwhen id == 0
set udg_UDex = id
set u = udg_UDexUnits[id]
if udg_IsUnitNew[id] then
//The unit was just created.
set udg_IsUnitNew[id] = false
set udg_UnitIndexEvent = 1.50 //New event requested by SpellBound to detect when unit fully enters scope.
set udg_UnitIndexEvent = 0.00
elseif udg_IsUnitTransforming[id] then
//Added 21 July 2017 to fix the issue re-adding this ability in the same instant
set udg_UnitTypeEvent = 0.00
set udg_UnitTypeEvent = 1.00
set udg_UnitTypeOf[id] = GetUnitTypeId(u) //Set this afterward as otherwise the user won't know what the previous unittype was.
set udg_IsUnitTransforming[id] = false
call UnitAddAbility(u, udg_DetectTransformAbility)
elseif udg_IsUnitAlive[id] then
//The unit has started reincarnating.
set udg_IsUnitReincarnating[id] = true
set udg_IsUnitAlive[id] = false
set udg_DeathEvent = 0.50
set udg_DeathEvent = 0.00
elseif GetUnitTypeId(u) != 0 and not IsUnitType(u, UNIT_TYPE_DEAD) then //with vJass, could just use UnitAlive instead of both of these values.
//Moved this code to fire after a 0 second timer instead.
set udg_IsUnitAlive[id] = true
set udg_DeathEvent = 2.00
set udg_DeathEvent = 0.00
set udg_IsUnitReincarnating[id] = false
endif
set udg_CheckDeathInList[id] = false
endloop
set u = null
//Empty the list
set udg_CheckDeathList[0] = 0
endfunction
function UnitEventCheckAfterProxy takes integer i returns nothing
if udg_CheckDeathList[0] == 0 then
call TimerStart(udg_CheckDeathTimer, 0.00, false, function UnitEventCheckAfter)
endif
if not udg_CheckDeathInList[i] then
set udg_CheckDeathList[i] = udg_CheckDeathList[0]
set udg_CheckDeathList[0] = i
set udg_CheckDeathInList[i] = true
endif
endfunction
function UnitEventOnUnload takes nothing returns nothing
local integer i = udg_UDex
call GroupRemoveUnit(udg_CargoTransportGroup[GetUnitUserData(udg_CargoTransportUnit[i])], udg_UDexUnits[i])
set udg_IsUnitBeingUnloaded[i] = true
set udg_CargoEvent = 0.00
set udg_CargoEvent = 2.00
set udg_CargoEvent = 0.00
set udg_IsUnitBeingUnloaded[i] = false
if not IsUnitLoaded(udg_UDexUnits[i]) or IsUnitType(udg_CargoTransportUnit[i], UNIT_TYPE_DEAD) or GetUnitTypeId(udg_CargoTransportUnit[i]) == 0 then
set udg_CargoTransportUnit[i] = null
endif
endfunction
function UnitEventOnDeath takes nothing returns boolean
local integer pdex = udg_UDex
set udg_UDex = GetUnitUserData(GetTriggerUnit())
if udg_UDex != 0 then
set udg_KillerOfUnit[udg_UDex] = GetKillingUnit() //Added 29 May 2017 for GIMLI_2
set udg_IsUnitAlive[udg_UDex] = false
set udg_DeathEvent = 0.00
set udg_DeathEvent = 1.00
set udg_DeathEvent = 0.00
set udg_KillerOfUnit[udg_UDex] = null
if udg_CargoTransportUnit[udg_UDex] != null then
call UnitEventOnUnload()
endif
endif
set udg_UDex = pdex
return false
endfunction
function UnitEventOnOrder takes nothing returns boolean
local integer pdex = udg_UDex
local unit u = GetFilterUnit()
local integer i = GetUnitUserData(u)
if i > 0 then
set udg_UDex = i
if GetUnitAbilityLevel(u, udg_DetectRemoveAbility) == 0 then
if not udg_IsUnitRemoved[i] then
set udg_IsUnitRemoved[i] = true
set udg_IsUnitAlive[i] = false
set udg_SummonerOfUnit[i] = null
//For backwards-compatibility:
set udg_DeathEvent = 0.00
set udg_DeathEvent = 3.00
set udg_DeathEvent = 0.00
//Fire deindex event for UDex:
set udg_UnitIndexEvent = 0.00
set udg_UnitIndexEvent = 2.00
set udg_UnitIndexEvent = 0.00
set udg_UDexNext[udg_UDexPrev[i]] = udg_UDexNext[i]
set udg_UDexPrev[udg_UDexNext[i]] = udg_UDexPrev[i]
// Recycle the index for later use
set udg_UDexUnits[i] = null
set udg_UDexPrev[i] = udg_UDexLastRecycled
set udg_UDexLastRecycled = i
call UnitEventDestroyGroup(i)
endif
elseif not udg_IsUnitAlive[i] then
if not IsUnitType(u, UNIT_TYPE_DEAD) then
call UnitEventCheckAfterProxy(i) //modified 22 Oct 2022 to ensure the unit is fully revived before firing the event.
endif
elseif IsUnitType(u, UNIT_TYPE_DEAD) then
if udg_IsUnitNew[i] then
//This unit was created as a corpse.
set udg_IsUnitAlive[i] = false
set udg_DeathEvent = 0.00
set udg_DeathEvent = 1.00
set udg_DeathEvent = 0.00
elseif udg_CargoTransportUnit[i] == null or not IsUnitType(u, UNIT_TYPE_HERO) then
//The unit may have just started reincarnating.
call UnitEventCheckAfterProxy(i)
endif
elseif GetUnitAbilityLevel(u, udg_DetectTransformAbility) == 0 and not udg_IsUnitTransforming[i] then
set udg_IsUnitTransforming[i] = true
call UnitEventCheckAfterProxy(i) //This block has been updated on 21 July 2017
endif
if udg_CargoTransportUnit[i] != null and not udg_IsUnitBeingUnloaded[i] and not IsUnitLoaded(u) or IsUnitType(u, UNIT_TYPE_DEAD) then
call UnitEventOnUnload()
endif
set udg_UDex = pdex
endif
set u = null
return false
endfunction
function UnitEventOnSummon takes nothing returns boolean
local integer pdex = udg_UDex
set udg_UDex = GetUnitUserData(GetTriggerUnit())
if udg_IsUnitNew[udg_UDex] then
set udg_SummonerOfUnit[udg_UDex] = GetSummoningUnit()
set udg_UnitIndexEvent = 0.00
set udg_UnitIndexEvent = 0.50
set udg_UnitIndexEvent = 0.00
endif
set udg_UDex = pdex
return false
endfunction
function UnitEventOnLoad takes nothing returns boolean
local integer pdex = udg_UDex
local integer i = GetUnitUserData(GetTriggerUnit())
local integer index
if i != 0 then
set udg_UDex = i
if udg_CargoTransportUnit[i] != null then
call UnitEventOnUnload()
endif
//Loaded corpses do not issue an order when unloaded, therefore must
//use the enter-region event method taken from Jesus4Lyf's Transport.
if not udg_IsUnitAlive[i] then
call SetUnitX(udg_UDexUnits[i], udg_WorldMaxX)
call SetUnitY(udg_UDexUnits[i], udg_WorldMaxY)
endif
set udg_CargoTransportUnit[i] = GetTransportUnit()
set index = GetUnitUserData(udg_CargoTransportUnit[i])
if udg_CargoTransportGroup[index] == null then
set udg_CargoTransportGroup[index] = CreateGroup()
endif
call GroupAddUnit(udg_CargoTransportGroup[index], udg_UDexUnits[i])
set udg_CargoEvent = 0.00
set udg_CargoEvent = 1.00
set udg_CargoEvent = 0.00
set udg_UDex = pdex
endif
return false
endfunction
function UnitEventEnter takes nothing returns boolean
local integer pdex = udg_UDex
local integer i = udg_UDexLastRecycled
local unit u = GetFilterUnit()
if udg_UnitIndexerEnabled and GetUnitAbilityLevel(u, udg_DetectRemoveAbility) == 0 then
//Generate a unique integer index for this unit
if i == 0 then
set i = udg_UDexMax + 1
set udg_UDexMax = i
else
set udg_UDexLastRecycled = udg_UDexPrev[i]
endif
//Link index to unit, unit to index
set udg_UDexUnits[i] = u
call SetUnitUserData(u, i)
//For backwards-compatibility, add the unit to a linked list
set udg_UDexNext[i] = udg_UDexNext[0]
set udg_UDexPrev[udg_UDexNext[0]] = i
set udg_UDexNext[0] = i
set udg_UDexPrev[i] = 0
set udg_CheckDeathInList[i] = false
call UnitAddAbility(u, udg_DetectRemoveAbility)
call UnitMakeAbilityPermanent(u, true, udg_DetectRemoveAbility)
call UnitAddAbility(u, udg_DetectTransformAbility)
set udg_UnitTypeOf[i] = GetUnitTypeId(u)
set udg_IsUnitNew[i] = true
set udg_IsUnitAlive[i] = true
set udg_IsUnitRemoved[i] = false
set udg_IsUnitReincarnating[i] = false
set udg_IsUnitPreplaced[i] = udg_IsUnitPreplaced[0] //Added 29 May 2017 for Spellbound
call UnitEventCheckAfterProxy(i)
//Fire index event for UDex
set udg_UDex = i
set udg_UnitIndexEvent = 0.00
set udg_UnitIndexEvent = 1.00
set udg_UnitIndexEvent = 0.00
else
set udg_UDex = GetUnitUserData(u)
if udg_CargoTransportUnit[udg_UDex] != null and not IsUnitLoaded(u) then
//The unit was dead, but has re-entered the map.
call UnitEventOnUnload()
endif
endif
set udg_UDex = pdex
set u = null
return false
endfunction
//===========================================================================
function UnitEventInit takes nothing returns nothing
local integer i = bj_MAX_PLAYER_SLOTS //update to make it work with 1.29
local player p
local trigger t = CreateTrigger()
local trigger load = CreateTrigger()
local trigger death = CreateTrigger()
local trigger summon = CreateTrigger()
local rect r = GetWorldBounds()
local region re = CreateRegion()
local boolexpr enterB = Filter(function UnitEventEnter)
local boolexpr orderB = Filter(function UnitEventOnOrder)
set udg_WorldMaxX = GetRectMaxX(r)
set udg_WorldMaxY = GetRectMaxY(r)
call RegionAddRect(re, r)
call RemoveRect(r)
call UnitEventDestroyGroup(0)
call UnitEventDestroyGroup(1)
set udg_CheckDeathList[0] = 0
set udg_UnitIndexerEnabled = true
call TriggerRegisterEnterRegion(CreateTrigger(), re, enterB)
call TriggerAddCondition(load, Filter(function UnitEventOnLoad))
call TriggerAddCondition(death, Filter(function UnitEventOnDeath))
call TriggerAddCondition(summon, Filter(function UnitEventOnSummon))
loop
set i = i - 1
set p = Player(i)
call SetPlayerAbilityAvailable(p, udg_DetectRemoveAbility, false)
call SetPlayerAbilityAvailable(p, udg_DetectTransformAbility, false)
call TriggerRegisterPlayerUnitEvent(summon, p, EVENT_PLAYER_UNIT_SUMMON, null)
call TriggerRegisterPlayerUnitEvent(t, p, EVENT_PLAYER_UNIT_ISSUED_ORDER, orderB)
call TriggerRegisterPlayerUnitEvent(death, p, EVENT_PLAYER_UNIT_DEATH, null)
call TriggerRegisterPlayerUnitEvent(load, p, EVENT_PLAYER_UNIT_LOADED, null)
call GroupEnumUnitsOfPlayer(bj_lastCreatedGroup, p, enterB)
exitwhen i == 0
endloop
set summon = null
set death = null
set load = null
set re = null
set enterB = null
set orderB = null
set p = null
set r = null
set t = null
endfunction
function InitTrig_Unit_Event takes nothing returns nothing
endfunction
//===========================================================================
//
// Damage Engine 5.9.0.0 - update requires re-copying the Damage Engine category.
//
/*
Three GUI Damage systems for the community of The Hive,
Seven vJass Damage systems for the JASS-heads on their pedestals high,
Nine competing Damage systems, doomed to die,
One for Bribe on his dark throne
In the Land of the Hive where the Workshop lies.
One Damage Engine to rule them all, One Damage Engine to find them,
One Damage Engine to bring them all and in cross-compatibility unite them.
*/
//! novjass
JASS API (work in progress - I have a lot of documentation to go through):
struct Damage extends array
readonly static unit source //stores udg_DamageEventSource
readonly static unit target //stores udg_DamageEventTarget
static real amount //stores udg_DamageEventAmount
readonly unit sourceUnit //stores udg_DamageEventSource by index
readonly unit targetUnit //stores udg_DamageEventTarget by index
real damage //stores udg_DamageEventAmount by index
readonly real prevAmt //stores udg_DamageEventPrevAmt by index
attacktype attackType //stores udg_DamageEventAttackT by index
damagetype damageType //stores udg_DamageEventDamageT by index
weapontype weaponType //stores udg_DamageEventWeaponT by index
integer userType //stores udg_DamageEventType by index
readonly integer eFilter //replaces the previous eventFilter variable
readonly boolean isAttack //stores udg_IsDamageAttack by index
readonly boolean isCode //stores udg_IsDamageCode by index
readonly boolean isMelee //stores udg_IsDamageMelee by index
readonly boolean isRanged //stores udg_IsDamageRanged by index
readonly boolean isSpell //stores udg_IsDamageSpell by index
real armorPierced //stores udg_DamageEventArmorPierced by index
integer armorType //stores udg_DamageEventArmorT by index
integer defenseType //stores udg_DamageEventDefenseT by index
static boolean operator enabled
- Set to false to disable the damage event triggers/false to reverse that
static method apply takes unit src, unit tgt, real amt, boolean a, boolean r, attacktype at, damagetype dt, weapontype wt returns Damage
- Same arguments as "UnitDamageTarget" but has the benefit of being performance-friendly during recursive events.
- Will automatically cause the damage to be registered as Code damage.
static method applySpell takes unit src, unit tgt, real amt, damagetype dt returns Damage
- A simplified version of the above function that autofills in the booleans, attack type and weapon type.
static method applyAttack takes unit src, unit tgt, real amt, boolean ranged, attacktype at, weapontype wt returns Damage
- A different variation of the above which autofills the "attack" boolean and sets the damagetype to DAMAGE_TYPE_NORMAL.
struct DamageTrigger extends array
method operator filter= takes integer filter returns nothing
// Apply primary filters such as DamageEngine_FILTER_MELEE/RANGED/SPELL which are based off of limitop handles to enable easier access for GUI folks
// Full filter list:
- global integer DamageEngine_FILTER_ATTACK
- global integer DamageEngine_FILTER_MELEE
- global integer DamageEngine_FILTER_OTHER
- global integer DamageEngine_FILTER_RANGED
- global integer DamageEngine_FILTER_SPELL
- global integer DamageEngine_FILTER_CODE
boolean configured //set to True after configuring any filters listed below.
method configure takes nothing returns nothing
// Apply custom filters after setting any desired udg_DamageFilter variables (for GUI).
// Alternatively, vJass users can set these instead. Just be mindful to set the variable
// "configured" to true after settings these.
unit source
unit target
integer sourceType
integer targetType
integer sourceBuff
integer targetBuff
real damageMin
integer attackType
integer damageType
integer userType
//The string in the aruments below requires the following API:
// "" for standard damage event
// "Modifier(or Mod if you prefer)/After/Lethal/AOE" for the others
static method registerTrigger takes trigger whichTrig, string var, real value returns nothing
static method unregister takes trigger t, string eventName, real value, boolean reset returns boolean
static method getIndex takes trigger t, string eventName, real value returns integer
//If you already have the index of the trigger you want to unregister.
method unregisterByIndex takes boolean reset returns boolean
// Converts a code argument to a trigger, while checking if the same code had already been registered before.
static method operator [] takes code c returns trigger
//The accepted strings here use the same criteria as DamageTrigger.getIndex/registerTrigger/unregister
function TriggerRegisterDamageEngineEx takes trigger whichTrig, string eventName, real value, integer f returns nothing
function TriggerRegisterDamageEngine takes trigger whichTrig, string eventName, real value returns nothing
function RegisterDamageEngineEx takes code c, string eventName, real value, integer f returns nothing
function RegisterDamageEngine takes code c, string eventName, real value returns nothing
//! endnovjass
//===========================================================================
library DamageEngine
globals
private constant boolean USE_GUI = true //If you don't use any of the GUI events, set to false to slightly improve performance
private constant boolean USE_SCALING = USE_GUI //If you don't need or want to use DamageScalingUser/WC3 then set this to false
private constant boolean USE_EXTRA = true //If you don't use DamageEventLevel or AOEDamageEvent, set this to false
private constant boolean USE_ARMOR_MOD = true //If you do not modify nor detect armor/defense, set this to false
private constant boolean USE_MELEE_RANGE= true //If you do not detect melee nor ranged damage, set this to false
private constant boolean USE_LETHAL = true //If you do not use LethalDamageEvent nor negative damage (explosive) types, set this to false
private constant integer LIMBO = 16 //When manually-enabled recursion is enabled via DamageEngine_recurion, the engine will never go deeper than LIMBO.
public constant integer TYPE_CODE = 1 //Must be the same as udg_DamageTypeCode, or 0 if you prefer to disable the automatic flag.
public constant integer TYPE_PURE = 2 //Must be the same as udg_DamageTypePure
private constant real DEATH_VAL = 0.405 //In case Blizz ever changes this, it'll be a quick fix here.
private timer alarm = null
private boolean alarmSet = false
//Values to track the original pre-spirit Link/defensive damage values
private Damage lastInstance = 0
private boolean canKick = true
private boolean totem = false
private boolean array attacksImmune
private boolean array damagesImmune
//Made global in order to use enable/disable behavior.
private trigger t1 = null
private trigger t2 = null
private trigger t3 = null //Catches, stores recursive events
//These variables coincide with Blizzard's "limitop" type definitions so as to enable users (GUI in particular) with some nice performance perks.
public constant integer FILTER_ATTACK = 0 //LESS_THAN
public constant integer FILTER_MELEE = 1 //LESS_THAN_OR_EQUAL
public constant integer FILTER_OTHER = 2 //EQUAL
public constant integer FILTER_RANGED = 3 //GREATER_THAN_OR_EQUAL
public constant integer FILTER_SPELL = 4 //GREATER_THAN
public constant integer FILTER_CODE = 5 //NOT_EQUAL
public constant integer FILTER_MAX = 6
private integer eventFilter = FILTER_OTHER
public boolean inception = false //When true, it allows your trigger to potentially go recursive up to LIMBO. However it must be set per-trigger throughout the game and not only once per trigger during map initialization.
private boolean dreaming = false
private integer sleepLevel = 0
private group proclusGlobal = null //track sources of recursion
private group fischerMorrow = null //track targets of recursion
private boolean kicking = false
private boolean eventsRun = false
private keyword run
private keyword trigFrozen
private keyword levelsDeep
private keyword inceptionTrig
private boolean hasLethal = false
endglobals
native UnitAlive takes unit u returns boolean
//GUI Vars:
/*
Retained from 3.8 and prior:
----------------------------
unit udg_DamageEventSource
unit udg_DamageEventTarget
unit udg_EnhancedDamageTarget
group udg_DamageEventAOEGroup
integer udg_DamageEventAOE
integer udg_DamageEventLevel
real udg_DamageModifierEvent
real udg_DamageEvent
real udg_AfterDamageEvent
real udg_DamageEventAmount
real udg_DamageEventPrevAmt
real udg_AOEDamageEvent
boolean udg_DamageEventOverride
boolean udg_NextDamageType
boolean udg_DamageEventType
boolean udg_IsDamageSpell
//Added in 5.0:
boolean udg_IsDamageMelee
boolean udg_IsDamageRanged
unit udg_AOEDamageSource
real udg_LethalDamageEvent
real udg_LethalDamageHP
real udg_DamageScalingWC3
integer udg_DamageEventAttackT
integer udg_DamageEventDamageT
integer udg_DamageEventWeaponT
//Added in 5.1:
boolean udg_IsDamageCode
//Added in 5.2:
integer udg_DamageEventArmorT
integer udg_DamageEventDefenseT
//Addded in 5.3:
real DamageEventArmorPierced
real udg_DamageScalingUser
//Added in 5.4.2 to allow GUI users to re-issue the exact same attack and damage type at the attacker.
attacktype array udg_CONVERTED_ATTACK_TYPE
damagetype array udg_CONVERTED_DAMAGE_TYPE
//Added after Reforged introduced the new native BlzGetDamageIsAttack
boolean udg_IsDamageAttack
//Added in 5.6 to give GUI users control over the "IsDamageAttack", "IsDamageRanged" and "DamageEventWeaponT" field
boolean udg_NextDamageIsAttack //The first boolean value in the UnitDamageTarget native
boolean udg_NextDamageIsMelee //Flag the damage classification as melee
boolean udg_NextDamageIsRanged //The second boolean value in the UnitDamageTarget native
integer udg_NextDamageWeaponT //Allows control over damage sound effect
//Added in 5.7 to enable efficient, built-in filtering (see the below "checkConfig" method - I recommend commenting-out anything you don't need in your map)
integer udg_DamageFilterAttackT
integer udg_DamageFilterDamageT //filter for a specific attack/damage type
unit udg_DamageFilterSource
unit udg_DamageFilterTarget //filter for a specific source/target
integer udg_DamageFilterSourceT
integer udg_DamageFilterTargetT //unit type of source/target
integer udg_DamageFilterType //which DamageEventType was used
integer udg_DamageFilterSourceB
integer udg_DamageFilterTargetB //if source/target has a buff
real udg_DamageFilterMinAmount //only allow a minimum damage threshold
//Added in 5.8:
boolean udg_RemoveDamageEvent //Allow GUI users to more fully unregister a damage event trigger. Can only be used from within a damage event (of any kind).
integer udg_DamageFilterSourceA
integer udg_DamageFilterTargetA //Check if a source or target have a specific ability (will overwrite any source or target buff check, I need to use this because GUI differentiates ability ID and buff ID)
integer udg_DamageFilterSourceI
integer udg_DamageFilterTargetI //Check if a source or target have a specific type of item
integer udg_DamageFilterSourceC
integer udg_DamageFilterTargetC //Classification of source/target (e.g. hero, treant, ward)
*/
struct DamageTrigger extends array
static method checkItem takes unit u, integer id returns boolean
local integer i
if IsUnitType(u, UNIT_TYPE_HERO) then
set i = UnitInventorySize(u)
loop
exitwhen i <= 0
set i = i - 1
if GetItemTypeId(UnitItemInSlot(u, i)) == id then
return true
endif
endloop
endif
return false
endmethod
//Map-makers should comment-out any lines they will never need to check for and move to the top any lines
//that are checked more frequently in their map.
method checkConfig takes nothing returns boolean
//call BJDebugMsg("Checking configuration")
if this.sourceType != 0 and GetUnitTypeId(udg_DamageEventSource) != this.sourceType then
elseif this.targetType != 0 and GetUnitTypeId(udg_DamageEventTarget) != this.targetType then
elseif this.sourceBuff != 0 and GetUnitAbilityLevel(udg_DamageEventSource, this.sourceBuff) == 0 then
elseif this.targetBuff != 0 and GetUnitAbilityLevel(udg_DamageEventTarget, this.targetBuff) == 0 then
elseif this.failChance > 0.00 and GetRandomReal(0.00, 1.00) <= this.failChance then
elseif this.userType != 0 and udg_DamageEventType != this.userType then
elseif this.source != null and this.source != udg_DamageEventSource then
elseif this.target != null and this.target != udg_DamageEventTarget then
elseif this.attackType >= 0 and this.attackType != udg_DamageEventAttackT then
elseif this.damageType >= 0 and this.damageType != udg_DamageEventDamageT then
elseif this.sourceItem != 0 and not .checkItem(udg_DamageEventSource, this.sourceItem) then
elseif this.targetItem != 0 and not .checkItem(udg_DamageEventTarget, this.targetItem) then
elseif this.sourceClass >= 0 and not IsUnitType(udg_DamageEventSource, ConvertUnitType(this.sourceClass)) then
elseif this.targetClass >= 0 and not IsUnitType(udg_DamageEventTarget, ConvertUnitType(this.targetClass)) then
elseif udg_DamageEventAmount >= this.damageMin then
//call BJDebugMsg("Configuration passed")
return true
endif
//call BJDebugMsg("Checking failed")
return false
endmethod
//The below variables are to be treated as constant
readonly static thistype MOD = 1
readonly static thistype SHIELD = 4
readonly static thistype DAMAGE = 5
readonly static thistype ZERO = 6
readonly static thistype AFTER = 7
readonly static thistype LETHAL = 8
readonly static thistype AOE = 9
private static integer count = 9
static thistype lastRegistered = 0
private static thistype array trigIndexStack
static thistype eventIndex = 0
static boolean array filters
readonly string eventStr
readonly real weight
boolean usingGUI
//The below variables are to be treated as private
private thistype next
private trigger rootTrig
boolean trigFrozen //Whether the trigger is currently disabled due to recursion
integer levelsDeep //How deep the user recursion currently is.
boolean inceptionTrig //Added in 5.4.2 to simplify the inception variable for very complex DamageEvent trigger.
//configuration variables:
boolean configured
unit source
unit target
integer sourceType
integer targetType
integer sourceBuff
integer targetBuff
integer sourceItem
integer targetItem
integer sourceClass
integer targetClass
real damageMin
real failChance
integer attackType
integer damageType
integer userType
method operator runChance takes nothing returns real
return 1.00 - this.failChance
endmethod
method operator runChance= takes real r returns nothing
set this.failChance = 1.00 - r
endmethod
method configure takes nothing returns nothing
set this.attackType = udg_DamageFilterAttackT
set this.damageType = udg_DamageFilterDamageT
set this.source = udg_DamageFilterSource
set this.target = udg_DamageFilterTarget
set this.sourceType = udg_DamageFilterSourceT
set this.targetType = udg_DamageFilterTargetT
set this.sourceItem = udg_DamageFilterSourceI
set this.targetItem = udg_DamageFilterTargetI
set this.sourceClass = udg_DamageFilterSourceC
set this.targetClass = udg_DamageFilterTargetC
set this.userType = udg_DamageFilterType
set this.damageMin = udg_DamageFilterMinAmount
set this.failChance = 1.00 - (udg_DamageFilterRunChance - udg_DamageFilterFailChance)
if udg_DamageFilterSourceA > 0 then
set this.sourceBuff = udg_DamageFilterSourceA
set udg_DamageFilterSourceA = 0
else
set this.sourceBuff = udg_DamageFilterSourceB
endif
if udg_DamageFilterTargetA > 0 then
set this.targetBuff = udg_DamageFilterTargetA
set udg_DamageFilterTargetA = 0
else
set this.targetBuff = udg_DamageFilterTargetB
endif
set udg_DamageFilterAttackT = -1
set udg_DamageFilterDamageT = -1
set udg_DamageFilterSource = null
set udg_DamageFilterTarget = null
set udg_DamageFilterSourceT = 0
set udg_DamageFilterTargetT = 0
set udg_DamageFilterType = 0
set udg_DamageFilterSourceB = 0
set udg_DamageFilterTargetB = 0
set udg_DamageFilterSourceC = -1
set udg_DamageFilterTargetC = -1
set udg_DamageFilterSourceI = 0
set udg_DamageFilterTargetI = 0
set udg_DamageFilterMinAmount = 0.00
set udg_DamageFilterFailChance = 0.00
set udg_DamageFilterRunChance = 1.00
set this.configured = true
endmethod
static method setGUIFromStruct takes boolean full returns nothing
set udg_DamageEventAmount = Damage.index.damage
set udg_DamageEventAttackT = GetHandleId(Damage.index.attackType)
set udg_DamageEventDamageT = GetHandleId(Damage.index.damageType)
set udg_DamageEventWeaponT = GetHandleId(Damage.index.weaponType)
set udg_DamageEventType = Damage.index.userType
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_DamageEventArmorPierced = Damage.index.armorPierced
set udg_DamageEventArmorT = Damage.index.armorType
set udg_DamageEventDefenseT = Damage.index.defenseType
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if full then
set udg_DamageEventSource = Damage.index.sourceUnit
set udg_DamageEventTarget = Damage.index.targetUnit
set udg_DamageEventPrevAmt = Damage.index.prevAmt
set udg_IsDamageAttack = Damage.index.isAttack
set udg_IsDamageCode = Damage.index.isCode
set udg_IsDamageSpell = Damage.index.isSpell
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_IsDamageMelee = Damage.index.isMelee
set udg_IsDamageRanged = Damage.index.isRanged
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endif
endmethod
static method setStructFromGUI takes nothing returns nothing
set Damage.index.damage = udg_DamageEventAmount
set Damage.index.attackType = ConvertAttackType(udg_DamageEventAttackT)
set Damage.index.damageType = ConvertDamageType(udg_DamageEventDamageT)
set Damage.index.weaponType = ConvertWeaponType(udg_DamageEventWeaponT)
set Damage.index.userType = udg_DamageEventType
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set Damage.index.armorPierced = udg_DamageEventArmorPierced
set Damage.index.armorType = udg_DamageEventArmorT
set Damage.index.defenseType = udg_DamageEventDefenseT
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endmethod
static method getVerboseStr takes string eventName returns string
if eventName == "Modifier" or eventName == "Mod" then
return "udg_DamageModifierEvent"
endif
return "udg_" + eventName + "DamageEvent"
endmethod
private static method getStrIndex takes string var, real lbs returns thistype
local integer root = R2I(lbs)
if (var == "udg_DamageModifierEvent" and root < 4) or var == "udg_PreDamageEvent" then
set root = MOD
elseif var == "udg_DamageModifierEvent" or var == "udg_ArmorDamageEvent" then
set root = SHIELD
elseif (var == "udg_DamageEvent" and root == 2 or root == 0) or var == "udg_ZeroDamageEvent" then
set root = ZERO
elseif var == "udg_DamageEvent" or var == "udg_OnDamageEvent" then
set root = DAMAGE
elseif var == "udg_AfterDamageEvent" then
set root = AFTER
elseif var == "udg_LethalDamageEvent" then
set root = LETHAL
elseif var == "udg_AOEDamageEvent" or var == "udg_SourceDamageEvent" then
set root = AOE
else
set root = 0
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_GDD()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_PDD()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_05()
endif
return root
endmethod
private method toggleAllFilters takes boolean flag returns nothing
set filters[this + FILTER_ATTACK] = flag
set filters[this + FILTER_MELEE] = flag
set filters[this + FILTER_OTHER] = flag
set filters[this + FILTER_RANGED] = flag
set filters[this + FILTER_SPELL] = flag
set filters[this + FILTER_CODE] = flag
endmethod
method operator filter= takes integer f returns nothing
set this = this*FILTER_MAX
if f == FILTER_OTHER then
call this.toggleAllFilters(true)
else
if f == FILTER_ATTACK then
set filters[this + FILTER_ATTACK] = true
set filters[this + FILTER_MELEE] = true
set filters[this + FILTER_RANGED] = true
else
set filters[this + f] = true
endif
endif
endmethod
static method registerVerbose takes trigger whichTrig, string var, real lbs, boolean GUI, integer filt returns thistype
local thistype index= getStrIndex(var, lbs)
local thistype i = 0
local thistype id = 0
if index == 0 then
return 0
elseif lastRegistered.rootTrig == whichTrig and lastRegistered.usingGUI then
set filters[lastRegistered*FILTER_MAX + filt] = true //allows GUI to register multiple different types of Damage filters to the same trigger
return 0
endif
if not hasLethal and index == LETHAL then
set hasLethal = true
endif
if trigIndexStack[0] == 0 then
set count = count + 1 //List runs from index 10 and up
set id = count
else
set id = trigIndexStack[0]
set trigIndexStack[0] = trigIndexStack[id]
endif
set lastRegistered = id
set id.filter = filt
set id.rootTrig = whichTrig
set id.usingGUI = GUI
set id.weight = lbs
set id.eventStr = var
//Next 2 lines added to fix a bug when using manual vJass configuration,
//discovered and solved by lolreported
set id.attackType = -1
set id.damageType = -1
//they will probably bug out with class types as well, so I should add them, just in case:
set id.sourceClass = -1
set id.targetClass = -1
loop
set i = index.next
exitwhen i == 0 or lbs < i.weight
set index = i
endloop
set index.next = id
set id.next = i
//call BJDebugMsg("Registered " + I2S(id) + " to " + I2S(index) + " and before " + I2S(i))
return lastRegistered
endmethod
static method registerTrigger takes trigger t, string var, real lbs returns thistype
return registerVerbose(t, DamageTrigger.getVerboseStr(var), lbs, false, FILTER_OTHER)
endmethod
private static thistype prev = 0
static method getIndex takes trigger t, string eventName, real lbs returns thistype
local thistype index = getStrIndex(getVerboseStr(eventName), lbs)
loop
set prev = index
set index = index.next
exitwhen index == 0 or index.rootTrig == t
endloop
return index
endmethod
method unregisterByIndex takes boolean reset returns boolean
if this == 0 then
return false
endif
set prev.next = this.next
set trigIndexStack[this] = trigIndexStack[0]
set trigIndexStack[0] = this
if reset then
call this.configure()
set this.configured = false
call thistype(this*FILTER_MAX).toggleAllFilters(false)
endif
return true
endmethod
static method unregister takes trigger t, string eventName, real lbs, boolean reset returns boolean
return getIndex(t, eventName, lbs).unregisterByIndex(reset)
endmethod
method run takes nothing returns nothing
local integer cat = this
local Damage d = Damage.index
static if USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
local boolean structUnset = false
local boolean guiUnset = false
local boolean mod = cat <= DAMAGE
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if dreaming then
return
endif
set dreaming = true
call DisableTrigger(t1)
call DisableTrigger(t2)
call EnableTrigger(t3)
//call BJDebugMsg("Start of event running")
loop
set this = this.next
exitwhen this == 0
exitwhen cat == MOD and (udg_DamageEventOverride or udg_DamageEventType == TYPE_PURE)
exitwhen cat == SHIELD and udg_DamageEventAmount <= 0.00
static if USE_LETHAL then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
exitwhen cat == LETHAL and udg_LethalDamageHP > DEATH_VAL
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set eventIndex = this
if (not this.trigFrozen) and filters[this*FILTER_MAX + d.eFilter] and IsTriggerEnabled(this.rootTrig) and ((not this.configured) or (this.checkConfig())) and (cat != AOE or udg_DamageEventAOE > 1 or this.eventStr == "udg_SourceDamageEvent") then
static if USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if mod then
if this.usingGUI then
if guiUnset then
set guiUnset = false
call setGUIFromStruct(false)
endif
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_PDD()
elseif structUnset then
set structUnset = false
call setStructFromGUI()
endif
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_05()
//JASS users who do not use actions can modify the below block to just evaluate.
//It should not make any perceptable difference in terms of performance.
if TriggerEvaluate(this.rootTrig) then
call TriggerExecute(this.rootTrig)
endif
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_05()
static if USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if mod then
if this.usingGUI then
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_PDD()
if cat != MOD then
set d.damage = udg_DamageEventAmount
else
set structUnset = true
endif
elseif cat != MOD then
set udg_DamageEventAmount = d.damage
else
set guiUnset = true
endif
endif
if udg_RemoveDamageEvent then
set udg_RemoveDamageEvent = false
call this.unregisterByIndex(true)
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endif
endloop
static if USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if structUnset then
call setStructFromGUI()
endif
if guiUnset then
call setGUIFromStruct(false)
endif
else// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call setGUIFromStruct(false)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
//call BJDebugMsg("End of event running")
call DisableTrigger(t3)
call EnableTrigger(t1)
call EnableTrigger(t2)
set dreaming = false
endmethod
static trigger array autoTriggers
static boolexpr array autoFuncs
static integer autoN = 0
static method operator [] takes code c returns trigger
local integer i = 0
local boolexpr b = Filter(c)
loop
if i == autoN then
set autoTriggers[i] = CreateTrigger()
set autoFuncs[i] = b
call TriggerAddCondition(autoTriggers[i], b)
exitwhen true
endif
set i = i + 1
exitwhen b == autoFuncs[i]
endloop
return autoTriggers[i]
endmethod
endstruct
//! runtextmacro optional DAMAGE_EVENT_USER_STRUCT_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_USER_STRUCT_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_USER_STRUCT_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_USER_STRUCT_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_USER_STRUCT_PLUGIN_05()
struct Damage extends array
readonly unit sourceUnit //stores udg_DamageEventSource
readonly unit targetUnit //stores udg_DamageEventTarget
real damage //stores udg_DamageEventAmount
readonly real prevAmt //stores udg_DamageEventPrevAmt
attacktype attackType //stores udg_DamageEventAttackT
damagetype damageType //stores udg_DamageEventDamageT
weapontype weaponType //stores udg_DamageEventWeaponT
integer userType //stores udg_DamageEventType
readonly boolean isAttack //stores udg_IsDamageAttack
readonly boolean isCode //stores udg_IsDamageCode
readonly boolean isSpell //stores udg_IsDamageSpell
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
readonly boolean isMelee //stores udg_IsDamageMelee
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
readonly boolean isRanged //stores udg_IsDamageRanged
readonly integer eFilter //stores the previous eventFilter variable
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
real armorPierced //stores udg_DamageEventArmorPierced
integer armorType //stores udg_DamageEventArmorT
integer defenseType //stores udg_DamageEventDefenseT
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
readonly static Damage index = 0
private static Damage damageStack = 0
private static Damage prepped = 0
private static integer count = 0 //The number of currently-running queued or sequential damage instances
private Damage stackRef
private DamageTrigger recursiveTrig
private integer prevArmorT
private integer prevDefenseT
static method operator source takes nothing returns unit
return udg_DamageEventSource
endmethod
static method operator target takes nothing returns unit
return udg_DamageEventTarget
endmethod
static method operator amount takes nothing returns real
return Damage.index.damage
endmethod
static method operator amount= takes real r returns nothing
set Damage.index.damage = r
endmethod
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
private method setArmor takes boolean reset returns nothing
local real pierce
local integer at
local integer dt
if reset then
set pierce = udg_DamageEventArmorPierced
set at = Damage.index.prevArmorT
set dt = Damage.index.prevDefenseT
set udg_DamageEventArmorPierced = 0.00
set this.armorPierced = 0.00
else
set pierce = -udg_DamageEventArmorPierced
set at = udg_DamageEventArmorT
set dt = udg_DamageEventDefenseT
endif
if not (pierce == 0.00) then //Changed condition thanks to bug reported by BLOKKADE
call BlzSetUnitArmor(udg_DamageEventTarget, BlzGetUnitArmor(udg_DamageEventTarget) + pierce)
endif
if Damage.index.prevArmorT != udg_DamageEventArmorT then
call BlzSetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_ARMOR_TYPE, at)
endif
if Damage.index.prevDefenseT != udg_DamageEventDefenseT then
call BlzSetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_DEFENSE_TYPE, dt)
endif
endmethod
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
static if USE_EXTRA then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
private static method onAOEEnd takes nothing returns nothing
call DamageTrigger.AOE.run()
set udg_DamageEventAOE = 1
set udg_DamageEventLevel = 1
set udg_EnhancedDamageTarget = null
set udg_AOEDamageSource = null
call GroupClear(udg_DamageEventAOEGroup)
endmethod
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
private static method afterDamage takes nothing returns nothing
if udg_DamageEventDamageT != 0 and not (udg_DamageEventPrevAmt == 0.00) then
call DamageTrigger.AFTER.run()
set udg_DamageEventDamageT = 0
set udg_DamageEventPrevAmt = 0.00
endif
endmethod
private method doPreEvents takes boolean natural returns boolean
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set this.armorType = BlzGetUnitIntegerField(this.targetUnit, UNIT_IF_ARMOR_TYPE)
set this.defenseType = BlzGetUnitIntegerField(this.targetUnit, UNIT_IF_DEFENSE_TYPE)
set this.prevArmorT = this.armorType
set this.prevDefenseT = this.defenseType
set this.armorPierced = 0.00
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set Damage.index = this
call DamageTrigger.setGUIFromStruct(true)
call GroupAddUnit(proclusGlobal, udg_DamageEventSource)
call GroupAddUnit(fischerMorrow, udg_DamageEventTarget)
//! runtextmacro optional DAMAGE_EVENT_PRE_VARS_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_PRE_VARS_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_PRE_VARS_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_PRE_VARS_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_PRE_VARS_PLUGIN_05()
if not (udg_DamageEventAmount == 0.00) then
set udg_DamageEventOverride = udg_DamageEventDamageT == 0
call DamageTrigger.MOD.run()
static if not USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call DamageTrigger.setGUIFromStruct(false)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if natural then
call BlzSetEventAttackType(this.attackType)
call BlzSetEventDamageType(this.damageType)
call BlzSetEventWeaponType(this.weaponType)
call BlzSetEventDamage(udg_DamageEventAmount)
endif
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call this.setArmor(false)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
return false
endif
return true
endmethod
private static method unfreeze takes nothing returns nothing
local Damage i = damageStack
loop
exitwhen i == 0
set i = i - 1
set i.stackRef.recursiveTrig.trigFrozen = false
set i.stackRef.recursiveTrig.levelsDeep = 0
endloop
call EnableTrigger(t1)
call EnableTrigger(t2)
set kicking = false
set damageStack = 0
set prepped = 0
set dreaming = false
set sleepLevel = 0
call GroupClear(proclusGlobal)
call GroupClear(fischerMorrow)
//call BJDebugMsg("Cleared up the groups")
endmethod
static method finish takes nothing returns nothing
local Damage i = 0
local integer exit
if eventsRun then
set eventsRun = false
call afterDamage()
endif
if canKick and not kicking then
if damageStack != 0 then
set kicking = true
loop
set sleepLevel = sleepLevel + 1
set exit = damageStack
loop
set prepped = i.stackRef
if UnitAlive(prepped.targetUnit) then //Added just in case dead units had issues.
call prepped.doPreEvents(false) //don't evaluate the pre-event
if prepped.damage > 0.00 then
call DisableTrigger(t1) //Force only the after armor event to run.
call EnableTrigger(t2) //in case the user forgot to re-enable this
set totem = true
call UnitDamageTarget(prepped.sourceUnit, prepped.targetUnit, prepped.damage, prepped.isAttack, prepped.isRanged, prepped.attackType, prepped.damageType, prepped.weaponType)
else
//No new events run at all in this case
if udg_DamageEventDamageT != 0 then
call DamageTrigger.DAMAGE.run()
endif
if prepped.damage < 0.00 then
//No need for BlzSetEventDamage here
call SetWidgetLife(prepped.targetUnit, GetWidgetLife(prepped.targetUnit) - prepped.damage)
endif
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call prepped.setArmor(true)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endif
call afterDamage()
endif
set i = i + 1
exitwhen i == exit
endloop
exitwhen i == damageStack
endloop
endif
call unfreeze()
endif
endmethod
private static method failsafeClear takes nothing returns nothing
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call Damage.index.setArmor(true)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set canKick = true
set kicking = false
set totem = false
if udg_DamageEventDamageT != 0 then
call DamageTrigger.DAMAGE.run()
set eventsRun = true
endif
call finish()
endmethod
static method operator enabled= takes boolean b returns nothing
if b then
if dreaming then
call EnableTrigger(t3)
else
call EnableTrigger(t1)
call EnableTrigger(t2)
endif
else
if dreaming then
call DisableTrigger(t3)
else
call DisableTrigger(t1)
call DisableTrigger(t2)
endif
endif
endmethod
static method operator enabled takes nothing returns boolean
return IsTriggerEnabled(t1)
endmethod
private static boolean arisen = false
private static method getOutOfBed takes nothing returns nothing
if totem then
call failsafeClear() //WarCraft 3 didn't run the DAMAGED event despite running the DAMAGING event.
else
set canKick = true
set kicking = false
call finish()
endif
static if USE_EXTRA then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call onAOEEnd()
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set arisen = true
endmethod
private static method wakeUp takes nothing returns nothing
set dreaming = false
set Damage.enabled = true
call ForForce(bj_FORCE_PLAYER[0], function thistype.getOutOfBed) //Moved to a new thread in case of a thread crash
if not arisen then
//call BJDebugMsg("DamageEngine issue: thread crashed!")
call unfreeze()
else
set arisen = false
endif
set Damage.count = 0
set Damage.index = 0
set alarmSet = false
//call BJDebugMsg("Timer wrapped up")
endmethod
private method addRecursive takes nothing returns nothing
if not (this.damage == 0.00) then
set this.recursiveTrig = DamageTrigger.eventIndex
if not this.isCode then
set this.isCode = true
set this.userType = TYPE_CODE
endif
set inception = inception or DamageTrigger.eventIndex.inceptionTrig
if kicking and IsUnitInGroup(this.sourceUnit, proclusGlobal) and IsUnitInGroup(this.targetUnit, fischerMorrow) then
if not inception then
set DamageTrigger.eventIndex.trigFrozen = true
elseif not DamageTrigger.eventIndex.trigFrozen then
set DamageTrigger.eventIndex.inceptionTrig = true
if DamageTrigger.eventIndex.levelsDeep < sleepLevel then
set DamageTrigger.eventIndex.levelsDeep = DamageTrigger.eventIndex.levelsDeep + 1
if DamageTrigger.eventIndex.levelsDeep >= LIMBO then
set DamageTrigger.eventIndex.trigFrozen = true
endif
endif
endif
endif
set damageStack.stackRef = this
set damageStack = damageStack + 1
//call BJDebugMsg("damageStack: " + I2S(damageStack) + " levelsDeep: " + I2S(DamageTrigger.eventIndex.levelsDeep) + " sleepLevel: " + I2S(sleepLevel))
endif
set inception = false
endmethod
private static method clearNexts takes nothing returns nothing
set udg_NextDamageIsAttack = false
set udg_NextDamageType = 0
set udg_NextDamageWeaponT = 0
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_NextDamageIsMelee = false
set udg_NextDamageIsRanged = false
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endmethod
static method create takes unit src, unit tgt, real amt, boolean a, attacktype at, damagetype dt, weapontype wt returns Damage
local Damage d = Damage.count + 1
set Damage.count = d
set d.sourceUnit = src
set d.targetUnit = tgt
set d.damage = amt
set d.prevAmt = amt
set d.attackType = at
set d.damageType = dt
set d.weaponType = wt
set d.isAttack = udg_NextDamageIsAttack or a
set d.isSpell = d.attackType == null and not d.isAttack
return d
endmethod
private static method createFromEvent takes nothing returns Damage
local Damage d = create(GetEventDamageSource(), GetTriggerUnit(), GetEventDamage(), BlzGetEventIsAttack(), BlzGetEventAttackType(), BlzGetEventDamageType(), BlzGetEventWeaponType())
set d.isCode = udg_NextDamageType != 0 or udg_NextDamageIsAttack or udg_NextDamageIsRanged or udg_NextDamageIsMelee or d.damageType == DAMAGE_TYPE_MIND or udg_NextDamageWeaponT != 0 or (d.damageType == DAMAGE_TYPE_UNKNOWN and not (d.damage == 0.00))
if d.isCode then
if udg_NextDamageType != 0 then
set d.userType = udg_NextDamageType
else
set d.userType = TYPE_CODE
endif
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set d.isMelee = udg_NextDamageIsMelee
set d.isRanged = udg_NextDamageIsRanged
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set d.eFilter = FILTER_CODE
if udg_NextDamageWeaponT != 0 then
set d.weaponType = ConvertWeaponType(udg_NextDamageWeaponT)
set udg_NextDamageWeaponT = 0
endif
else
set d.userType = 0
if d.damageType == DAMAGE_TYPE_NORMAL and d.isAttack then
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set d.isMelee = IsUnitType(d.sourceUnit, UNIT_TYPE_MELEE_ATTACKER)
set d.isRanged = IsUnitType(d.sourceUnit, UNIT_TYPE_RANGED_ATTACKER)
if d.isMelee and d.isRanged then
set d.isMelee = d.weaponType != null // Melee units play a sound when damaging
set d.isRanged = not d.isMelee // In the case where a unit is both ranged and melee, the ranged attack plays no sound.
endif
if d.isMelee then
set d.eFilter = FILTER_MELEE
elseif d.isRanged then
set d.eFilter = FILTER_RANGED
else
set d.eFilter = FILTER_ATTACK
endif
else
set d.eFilter = FILTER_ATTACK
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
else
if d.isSpell then
set d.eFilter = FILTER_SPELL
else
set d.eFilter = FILTER_OTHER
endif
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set d.isMelee = false
set d.isRanged = false
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endif
endif
call clearNexts()
return d
endmethod
private static method onRecursion takes nothing returns boolean //New in 5.7
local Damage d = Damage.createFromEvent()
call d.addRecursive()
call BlzSetEventDamage(0.00)
return false
endmethod
private static method onDamaging takes nothing returns boolean
local Damage d = Damage.createFromEvent()
//call BJDebugMsg("Pre-damage event running for " + GetUnitName(GetTriggerUnit()))
if alarmSet then
if totem then //WarCraft 3 didn't run the DAMAGED event despite running the DAMAGING event.
if d.damageType == DAMAGE_TYPE_SPIRIT_LINK or d.damageType == DAMAGE_TYPE_DEFENSIVE or d.damageType == DAMAGE_TYPE_PLANT then
set totem = false
set lastInstance= Damage.index
set canKick = false
else
call failsafeClear() //Not an overlapping event - just wrap it up
endif
else
call finish() //wrap up any previous damage index
endif
static if USE_EXTRA then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if d.sourceUnit != udg_AOEDamageSource then
call onAOEEnd()
set udg_AOEDamageSource = d.sourceUnit
elseif d.targetUnit == udg_EnhancedDamageTarget then
set udg_DamageEventLevel= udg_DamageEventLevel + 1
elseif not IsUnitInGroup(d.targetUnit, udg_DamageEventAOEGroup) then
set udg_DamageEventAOE = udg_DamageEventAOE + 1
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
else
call TimerStart(alarm, 0.00, false, function Damage.wakeUp)
set alarmSet = true
static if USE_EXTRA then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_AOEDamageSource = d.sourceUnit
set udg_EnhancedDamageTarget= d.targetUnit
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endif
static if USE_EXTRA then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call GroupAddUnit(udg_DamageEventAOEGroup, d.targetUnit)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if d.doPreEvents(true) then
call DamageTrigger.ZERO.run()
set canKick = true
call finish()
endif
set totem = lastInstance == 0 or attacksImmune[udg_DamageEventAttackT] or damagesImmune[udg_DamageEventDamageT] or not IsUnitType(udg_DamageEventTarget, UNIT_TYPE_MAGIC_IMMUNE)
return false
endmethod
private static method onDamaged takes nothing returns boolean
local real r = GetEventDamage()
local Damage d = Damage.index
//call BJDebugMsg("Second damage event running for " + GetUnitName(GetTriggerUnit()))
if prepped > 0 then
set prepped = 0
elseif dreaming or d.prevAmt == 0.00 then
return false
elseif totem then
set totem = false
else
//This should only happen for stuff like Spirit Link or Thorns Aura/Carapace
call afterDamage()
set Damage.index = lastInstance
set lastInstance = 0
set d = Damage.index
set canKick = true
call DamageTrigger.setGUIFromStruct(true)
endif
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call d.setArmor(true)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
static if USE_SCALING then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if not (udg_DamageEventAmount == 0.00) and not (r == 0.00) then
set udg_DamageScalingWC3 = r / udg_DamageEventAmount
elseif udg_DamageEventAmount > 0.00 then
set udg_DamageScalingWC3 = 0.00
else
set udg_DamageScalingWC3 = 1.00
if udg_DamageEventPrevAmt == 0.00 then
set udg_DamageScalingUser = 0.00
else
set udg_DamageScalingUser = udg_DamageEventAmount/udg_DamageEventPrevAmt
endif
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_DamageEventAmount = r
set d.damage = r
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_GDD()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_PDD()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_05()
if udg_DamageEventAmount > 0.00 then
call DamageTrigger.SHIELD.run()
static if not USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_DamageEventAmount = d.damage
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
static if USE_LETHAL then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if hasLethal or udg_DamageEventType < 0 then
set udg_LethalDamageHP = GetWidgetLife(udg_DamageEventTarget) - udg_DamageEventAmount
if udg_LethalDamageHP <= DEATH_VAL then
if hasLethal then
call DamageTrigger.LETHAL.run()
set udg_DamageEventAmount = GetWidgetLife(udg_DamageEventTarget) - udg_LethalDamageHP
set d.damage = udg_DamageEventAmount
endif
if udg_DamageEventType < 0 and udg_LethalDamageHP <= DEATH_VAL then
call SetUnitExploded(udg_DamageEventTarget, true)
endif
endif
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
static if USE_SCALING then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if udg_DamageEventPrevAmt == 0.00 or udg_DamageScalingWC3 == 0.00 then
set udg_DamageScalingUser = 0.00
else
set udg_DamageScalingUser = udg_DamageEventAmount/udg_DamageEventPrevAmt/udg_DamageScalingWC3
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endif
if udg_DamageEventDamageT != 0 then
call DamageTrigger.DAMAGE.run()
endif
call BlzSetEventDamage(udg_DamageEventAmount)
set eventsRun = true
if udg_DamageEventAmount == 0.00 then
call finish()
endif
return false
endmethod
static method apply takes unit src, unit tgt, real amt, boolean a, boolean r, attacktype at, damagetype dt, weapontype wt returns Damage
local Damage d
if udg_NextDamageType == 0 then
set udg_NextDamageType = TYPE_CODE
endif
if dreaming then
set d = create(src, tgt, amt, a, at, dt, wt)
set d.isCode = true
set d.eFilter = FILTER_CODE
set d.userType = udg_NextDamageType
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if not d.isSpell then
set d.isRanged = udg_NextDamageIsRanged or r
set d.isMelee = not d.isRanged
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call d.addRecursive()
else
call UnitDamageTarget(src, tgt, amt, a, r, at, dt, wt)
set d = Damage.index
call finish()
endif
call clearNexts()
return d
endmethod
static method applySpell takes unit src, unit tgt, real amt, damagetype dt returns Damage
return apply(src, tgt, amt, false, false, null, dt, null)
endmethod
static method applyAttack takes unit src, unit tgt, real amt, boolean ranged, attacktype at, weapontype wt returns Damage
return apply(src, tgt, amt, true, ranged, at, DAMAGE_TYPE_NORMAL, wt)
endmethod
//===========================================================================
private static method onInit takes nothing returns nothing
set alarm = CreateTimer()
set proclusGlobal = CreateGroup()
set fischerMorrow = CreateGroup()
set t1 = CreateTrigger()
set t2 = CreateTrigger()
set t3 = CreateTrigger() //Moved from globals block as per request of user Ricola3D
call TriggerRegisterAnyUnitEventBJ(t1, EVENT_PLAYER_UNIT_DAMAGING)
call TriggerAddCondition(t1, Filter(function Damage.onDamaging))
call TriggerRegisterAnyUnitEventBJ(t2, EVENT_PLAYER_UNIT_DAMAGED)
call TriggerAddCondition(t2, Filter(function Damage.onDamaged))
//For recursion
call TriggerRegisterAnyUnitEventBJ(t3, EVENT_PLAYER_UNIT_DAMAGING)
call TriggerAddCondition(t3, Filter(function Damage.onRecursion))
call DisableTrigger(t3)
//For preventing Thorns/Defensive glitch.
//Data gathered from https://www.hiveworkshop.com/threads/repo-in-progress-mapping-damage-types-to-their-abilities.316271/
set attacksImmune[0] = false //ATTACK_TYPE_NORMAL
set attacksImmune[1] = true //ATTACK_TYPE_MELEE
set attacksImmune[2] = true //ATTACK_TYPE_PIERCE
set attacksImmune[3] = true //ATTACK_TYPE_SIEGE
set attacksImmune[4] = false //ATTACK_TYPE_MAGIC
set attacksImmune[5] = true //ATTACK_TYPE_CHAOS
set attacksImmune[6] = true //ATTACK_TYPE_HERO
set damagesImmune[0] = true //DAMAGE_TYPE_UNKNOWN
set damagesImmune[4] = true //DAMAGE_TYPE_NORMAL
set damagesImmune[5] = true //DAMAGE_TYPE_ENHANCED
set damagesImmune[8] = false //DAMAGE_TYPE_FIRE
set damagesImmune[9] = false //DAMAGE_TYPE_COLD
set damagesImmune[10] = false //DAMAGE_TYPE_LIGHTNING
set damagesImmune[11] = true //DAMAGE_TYPE_POISON
set damagesImmune[12] = true //DAMAGE_TYPE_DISEASE
set damagesImmune[13] = false //DAMAGE_TYPE_DIVINE
set damagesImmune[14] = false //DAMAGE_TYPE_MAGIC
set damagesImmune[15] = false //DAMAGE_TYPE_SONIC
set damagesImmune[16] = true //DAMAGE_TYPE_ACID
set damagesImmune[17] = false //DAMAGE_TYPE_FORCE
set damagesImmune[18] = false //DAMAGE_TYPE_DEATH
set damagesImmune[19] = false //DAMAGE_TYPE_MIND
set damagesImmune[20] = false //DAMAGE_TYPE_PLANT
set damagesImmune[21] = false //DAMAGE_TYPE_DEFENSIVE
set damagesImmune[22] = true //DAMAGE_TYPE_DEMOLITION
set damagesImmune[23] = true //DAMAGE_TYPE_SLOW_POISON
set damagesImmune[24] = false //DAMAGE_TYPE_SPIRIT_LINK
set damagesImmune[25] = false //DAMAGE_TYPE_SHADOW_STRIKE
set damagesImmune[26] = true //DAMAGE_TYPE_UNIVERSAL
endmethod
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_DMGPKG()
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_05()
endstruct
public function DebugStr takes nothing returns nothing
local integer i = 0
loop
set udg_CONVERTED_ATTACK_TYPE[i] = ConvertAttackType(i)
exitwhen i == 6
set i = i + 1
endloop
set i = 0
loop
set udg_CONVERTED_DAMAGE_TYPE[i] = ConvertDamageType(i)
exitwhen i == 26
set i = i + 1
endloop
set udg_AttackTypeDebugStr[0] = "SPELLS" //ATTACK_TYPE_NORMAL in JASS
set udg_AttackTypeDebugStr[1] = "NORMAL" //ATTACK_TYPE_MELEE in JASS
set udg_AttackTypeDebugStr[2] = "PIERCE"
set udg_AttackTypeDebugStr[3] = "SIEGE"
set udg_AttackTypeDebugStr[4] = "MAGIC"
set udg_AttackTypeDebugStr[5] = "CHAOS"
set udg_AttackTypeDebugStr[6] = "HERO"
set udg_DamageTypeDebugStr[0] = "UNKNOWN"
set udg_DamageTypeDebugStr[4] = "NORMAL"
set udg_DamageTypeDebugStr[5] = "ENHANCED"
set udg_DamageTypeDebugStr[8] = "FIRE"
set udg_DamageTypeDebugStr[9] = "COLD"
set udg_DamageTypeDebugStr[10] = "LIGHTNING"
set udg_DamageTypeDebugStr[11] = "POISON"
set udg_DamageTypeDebugStr[12] = "DISEASE"
set udg_DamageTypeDebugStr[13] = "DIVINE"
set udg_DamageTypeDebugStr[14] = "MAGIC"
set udg_DamageTypeDebugStr[15] = "SONIC"
set udg_DamageTypeDebugStr[16] = "ACID"
set udg_DamageTypeDebugStr[17] = "FORCE"
set udg_DamageTypeDebugStr[18] = "DEATH"
set udg_DamageTypeDebugStr[19] = "MIND"
set udg_DamageTypeDebugStr[20] = "PLANT"
set udg_DamageTypeDebugStr[21] = "DEFENSIVE"
set udg_DamageTypeDebugStr[22] = "DEMOLITION"
set udg_DamageTypeDebugStr[23] = "SLOW_POISON"
set udg_DamageTypeDebugStr[24] = "SPIRIT_LINK"
set udg_DamageTypeDebugStr[25] = "SHADOW_STRIKE"
set udg_DamageTypeDebugStr[26] = "UNIVERSAL"
set udg_WeaponTypeDebugStr[0] = "NONE" //WEAPON_TYPE_WHOKNOWS in JASS
set udg_WeaponTypeDebugStr[1] = "METAL_LIGHT_CHOP"
set udg_WeaponTypeDebugStr[2] = "METAL_MEDIUM_CHOP"
set udg_WeaponTypeDebugStr[3] = "METAL_HEAVY_CHOP"
set udg_WeaponTypeDebugStr[4] = "METAL_LIGHT_SLICE"
set udg_WeaponTypeDebugStr[5] = "METAL_MEDIUM_SLICE"
set udg_WeaponTypeDebugStr[6] = "METAL_HEAVY_SLICE"
set udg_WeaponTypeDebugStr[7] = "METAL_MEDIUM_BASH"
set udg_WeaponTypeDebugStr[8] = "METAL_HEAVY_BASH"
set udg_WeaponTypeDebugStr[9] = "METAL_MEDIUM_STAB"
set udg_WeaponTypeDebugStr[10] = "METAL_HEAVY_STAB"
set udg_WeaponTypeDebugStr[11] = "WOOD_LIGHT_SLICE"
set udg_WeaponTypeDebugStr[12] = "WOOD_MEDIUM_SLICE"
set udg_WeaponTypeDebugStr[13] = "WOOD_HEAVY_SLICE"
set udg_WeaponTypeDebugStr[14] = "WOOD_LIGHT_BASH"
set udg_WeaponTypeDebugStr[15] = "WOOD_MEDIUM_BASH"
set udg_WeaponTypeDebugStr[16] = "WOOD_HEAVY_BASH"
set udg_WeaponTypeDebugStr[17] = "WOOD_LIGHT_STAB"
set udg_WeaponTypeDebugStr[18] = "WOOD_MEDIUM_STAB"
set udg_WeaponTypeDebugStr[19] = "CLAW_LIGHT_SLICE"
set udg_WeaponTypeDebugStr[20] = "CLAW_MEDIUM_SLICE"
set udg_WeaponTypeDebugStr[21] = "CLAW_HEAVY_SLICE"
set udg_WeaponTypeDebugStr[22] = "AXE_MEDIUM_CHOP"
set udg_WeaponTypeDebugStr[23] = "ROCK_HEAVY_BASH"
set udg_DefenseTypeDebugStr[0] = "LIGHT"
set udg_DefenseTypeDebugStr[1] = "MEDIUM"
set udg_DefenseTypeDebugStr[2] = "HEAVY"
set udg_DefenseTypeDebugStr[3] = "FORTIFIED"
set udg_DefenseTypeDebugStr[4] = "NORMAL" //Typically deals flat damage to all armor types
set udg_DefenseTypeDebugStr[5] = "HERO"
set udg_DefenseTypeDebugStr[6] = "DIVINE"
set udg_DefenseTypeDebugStr[7] = "UNARMORED"
set udg_ArmorTypeDebugStr[0] = "NONE" //ARMOR_TYPE_WHOKNOWS in JASS, added in 1.31
set udg_ArmorTypeDebugStr[1] = "FLESH"
set udg_ArmorTypeDebugStr[2] = "METAL"
set udg_ArmorTypeDebugStr[3] = "WOOD"
set udg_ArmorTypeDebugStr[4] = "ETHEREAL"
set udg_ArmorTypeDebugStr[5] = "STONE"
// -
// Added 25 July 2017 to allow detection of things like Bash or Pulverize or AOE spread
// -
set udg_DamageEventAOE = 1
set udg_DamageEventLevel = 1
// -
// In-game World Editor doesn't allow Attack Type and Damage Type comparisons. Therefore I need to code them as integers into GUI
// -
set udg_ATTACK_TYPE_SPELLS = 0
set udg_ATTACK_TYPE_NORMAL = 1
set udg_ATTACK_TYPE_PIERCE = 2
set udg_ATTACK_TYPE_SIEGE = 3
set udg_ATTACK_TYPE_MAGIC = 4
set udg_ATTACK_TYPE_CHAOS = 5
set udg_ATTACK_TYPE_HERO = 6
// -
set udg_DAMAGE_TYPE_UNKNOWN = 0
set udg_DAMAGE_TYPE_NORMAL = 4
set udg_DAMAGE_TYPE_ENHANCED = 5
set udg_DAMAGE_TYPE_FIRE = 8
set udg_DAMAGE_TYPE_COLD = 9
set udg_DAMAGE_TYPE_LIGHTNING = 10
set udg_DAMAGE_TYPE_POISON = 11
set udg_DAMAGE_TYPE_DISEASE = 12
set udg_DAMAGE_TYPE_DIVINE = 13
set udg_DAMAGE_TYPE_MAGIC = 14
set udg_DAMAGE_TYPE_SONIC = 15
set udg_DAMAGE_TYPE_ACID = 16
set udg_DAMAGE_TYPE_FORCE = 17
set udg_DAMAGE_TYPE_DEATH = 18
set udg_DAMAGE_TYPE_MIND = 19
set udg_DAMAGE_TYPE_PLANT = 20
set udg_DAMAGE_TYPE_DEFENSIVE = 21
set udg_DAMAGE_TYPE_DEMOLITION = 22
set udg_DAMAGE_TYPE_SLOW_POISON = 23
set udg_DAMAGE_TYPE_SPIRIT_LINK = 24
set udg_DAMAGE_TYPE_SHADOW_STRIKE = 25
set udg_DAMAGE_TYPE_UNIVERSAL = 26
// -
// The below variables don't affect damage amount, but do affect the sound played
// They also give important information about the type of attack used.
// They can differentiate between ranged and melee for units who are both
// -
set udg_WEAPON_TYPE_NONE = 0
// Metal Light/Medium/Heavy
set udg_WEAPON_TYPE_ML_CHOP = 1
set udg_WEAPON_TYPE_MM_CHOP = 2
set udg_WEAPON_TYPE_MH_CHOP = 3
set udg_WEAPON_TYPE_ML_SLICE = 4
set udg_WEAPON_TYPE_MM_SLICE = 5
set udg_WEAPON_TYPE_MH_SLICE = 6
set udg_WEAPON_TYPE_MM_BASH = 7
set udg_WEAPON_TYPE_MH_BASH = 8
set udg_WEAPON_TYPE_MM_STAB = 9
set udg_WEAPON_TYPE_MH_STAB = 10
// Wood Light/Medium/Heavy
set udg_WEAPON_TYPE_WL_SLICE = 11
set udg_WEAPON_TYPE_WM_SLICE = 12
set udg_WEAPON_TYPE_WH_SLICE = 13
set udg_WEAPON_TYPE_WL_BASH = 14
set udg_WEAPON_TYPE_WM_BASH = 15
set udg_WEAPON_TYPE_WH_BASH = 16
set udg_WEAPON_TYPE_WL_STAB = 17
set udg_WEAPON_TYPE_WM_STAB = 18
// Claw Light/Medium/Heavy
set udg_WEAPON_TYPE_CL_SLICE = 19
set udg_WEAPON_TYPE_CM_SLICE = 20
set udg_WEAPON_TYPE_CH_SLICE = 21
// Axe Medium
set udg_WEAPON_TYPE_AM_CHOP = 22
// Rock Heavy
set udg_WEAPON_TYPE_RH_BASH = 23
// -
// Since GUI still doesn't provide Defense Type and Armor Types, I needed to include the below
// -
set udg_ARMOR_TYPE_NONE = 0
set udg_ARMOR_TYPE_FLESH = 1
set udg_ARMOR_TYPE_METAL = 2
set udg_ARMOR_TYPE_WOOD = 3
set udg_ARMOR_TYPE_ETHEREAL = 4
set udg_ARMOR_TYPE_STONE = 5
// -
set udg_DEFENSE_TYPE_LIGHT = 0
set udg_DEFENSE_TYPE_MEDIUM = 1
set udg_DEFENSE_TYPE_HEAVY = 2
set udg_DEFENSE_TYPE_FORTIFIED = 3
set udg_DEFENSE_TYPE_NORMAL = 4
set udg_DEFENSE_TYPE_HERO = 5
set udg_DEFENSE_TYPE_DIVINE = 6
set udg_DEFENSE_TYPE_UNARMORED = 7
// -
set udg_UNIT_CLASS_HERO = 0
set udg_UNIT_CLASS_DEAD = 1
set udg_UNIT_CLASS_STRUCTURE = 2
// -
set udg_UNIT_CLASS_FLYING = 3
set udg_UNIT_CLASS_GROUND = 4
// -
set udg_UNIT_CLASS_ATTACKS_FLYING = 5
set udg_UNIT_CLASS_ATTACKS_GROUND = 6
// -
set udg_UNIT_CLASS_MELEE = 7
set udg_UNIT_CLASS_RANGED = 8
// -
set udg_UNIT_CLASS_GIANT = 9
set udg_UNIT_CLASS_SUMMONED = 10
set udg_UNIT_CLASS_STUNNED = 11
set udg_UNIT_CLASS_PLAGUED = 12
set udg_UNIT_CLASS_SNARED = 13
// -
set udg_UNIT_CLASS_UNDEAD = 14
set udg_UNIT_CLASS_MECHANICAL = 15
set udg_UNIT_CLASS_PEON = 16
set udg_UNIT_CLASS_SAPPER = 17
set udg_UNIT_CLASS_TOWNHALL = 18
set udg_UNIT_CLASS_ANCIENT = 19
// -
set udg_UNIT_CLASS_TAUREN = 20
set udg_UNIT_CLASS_POISONED = 21
set udg_UNIT_CLASS_POLYMORPHED = 22
set udg_UNIT_CLASS_SLEEPING = 23
set udg_UNIT_CLASS_RESISTANT = 24
set udg_UNIT_CLASS_ETHEREAL = 25
set udg_UNIT_CLASS_MAGIC_IMMUNE = 26
// -
set udg_DamageFilterAttackT = -1
set udg_DamageFilterDamageT = -1
set udg_DamageFilterSourceC = -1
set udg_DamageFilterTargetC = -1
set udg_DamageFilterRunChance = 1.00
endfunction
//===========================================================================
//
// Setup of automatic events from GUI and custom ones from JASS alike
//
//===========================================================================
public function RegisterFromHook takes trigger whichTrig, string var, limitop op, real value returns nothing
call DamageTrigger.registerVerbose(whichTrig, var, value, true, GetHandleId(op))
endfunction
hook TriggerRegisterVariableEvent RegisterFromHook
function TriggerRegisterDamageEngineEx takes trigger whichTrig, string eventName, real value, integer f returns DamageTrigger
return DamageTrigger.registerVerbose(whichTrig, DamageTrigger.getVerboseStr(eventName), value, false, f)
endfunction
function TriggerRegisterDamageEngine takes trigger whichTrig, string eventName, real value returns DamageTrigger
return DamageTrigger.registerTrigger(whichTrig, eventName, value)
endfunction
function RegisterDamageEngineEx takes code c, string eventName, real value, integer f returns DamageTrigger
return TriggerRegisterDamageEngineEx(DamageTrigger[c], eventName, value, f)
endfunction
//Similar to TriggerRegisterDamageEvent, although takes code instead of trigger as the first argument.
function RegisterDamageEngine takes code c, string eventName, real value returns DamageTrigger
return RegisterDamageEngineEx(c, eventName, value, FILTER_OTHER)
endfunction
//For GUI to tap into more powerful vJass event filtering:
//! textmacro DAMAGE_TRIGGER_CONFIG
if not DamageTrigger.eventIndex.configured then
//! endtextmacro
//! textmacro DAMAGE_TRIGGER_CONFIG_END
call DamageTrigger.eventIndex.configure()
endif
if not DamageTrigger.eventIndex.checkConfig() then
return
endif
//! endtextmacro
endlibrary