Name | Type | is_array | initial_value |
AfterDamageEvent | real | 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 | |
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 | |
BlightMeldGroup | group | No | |
CallOfNightmaresReanimator | integer | No | |
CargoEvent | real | No | |
CargoTransportGroup | group | Yes | |
CargoTransportUnit | unit | Yes | |
CheckDeathInList | boolean | Yes | |
CheckDeathList | integer | Yes | |
CheckDeathTimer | timer | No | |
CONVERTED_ATTACK_TYPE | attacktype | Yes | |
CONVERTED_DAMAGE_TYPE | damagetype | Yes | |
CorruptedAgesGroup | group | No | |
CorruptedEternityGroup | group | No | |
CorruptedLifeGroup | group | No | |
CorruptedLoreGroup | group | No | |
CorruptedProtectorGroup | group | No | |
CorruptedTreeOfLife | group | No | |
CorruptedWarGroup | group | No | |
CorruptedWindGroup | group | No | |
CorruptedWondersGroup | group | No | |
CriticalMassUnits | group | No | |
DAMAGE_TYPE_ACID | integer | No | |
DAMAGE_TYPE_COLD | integer | No | |
DAMAGE_TYPE_DEATH | integer | No | |
DAMAGE_TYPE_DEFENSIVE | integer | No | |
DAMAGE_TYPE_DEMOLITION | integer | No | |
DAMAGE_TYPE_DISEASE | integer | No | |
DAMAGE_TYPE_DIVINE | integer | No | |
DAMAGE_TYPE_ENHANCED | integer | No | |
DAMAGE_TYPE_FIRE | integer | No | |
DAMAGE_TYPE_FORCE | integer | No | |
DAMAGE_TYPE_LIGHTNING | integer | No | |
DAMAGE_TYPE_MAGIC | integer | No | |
DAMAGE_TYPE_MIND | integer | No | |
DAMAGE_TYPE_NORMAL | integer | No | |
DAMAGE_TYPE_PLANT | integer | No | |
DAMAGE_TYPE_POISON | integer | No | |
DAMAGE_TYPE_SHADOW_STRIKE | integer | No | |
DAMAGE_TYPE_SLOW_POISON | integer | No | |
DAMAGE_TYPE_SONIC | integer | No | |
DAMAGE_TYPE_SPIRIT_LINK | integer | No | |
DAMAGE_TYPE_UNIVERSAL | integer | No | |
DAMAGE_TYPE_UNKNOWN | integer | No | |
DamageEvent | real | No | |
DamageEventAmount | real | No | |
DamageEventAOE | integer | No | |
DamageEventAOEGroup | group | No | |
DamageEventArmorPierced | real | No | |
DamageEventArmorT | integer | No | |
DamageEventAttackT | integer | No | |
DamageEventDamageT | integer | No | |
DamageEventDefenseT | integer | No | |
DamageEventLevel | integer | No | |
DamageEventOverride | boolean | No | |
DamageEventPrevAmt | real | No | |
DamageEventSource | unit | No | |
DamageEventTarget | unit | No | |
DamageEventTrigger | trigger | No | |
DamageEventType | integer | No | |
DamageEventWeaponT | integer | No | |
DamageFilterAttackT | integer | No | |
DamageFilterDamageT | integer | No | |
DamageFilterMinAmount | real | No | |
DamageFilterSource | unit | No | |
DamageFilterSourceB | buffcode | No | |
DamageFilterSourceT | unitcode | No | |
DamageFilterTarget | unit | No | |
DamageFilterTargetB | buffcode | No | |
DamageFilterTargetT | unitcode | No | |
DamageFilterType | integer | No | |
DamageModifierEvent | real | No | |
DamageScalingUser | real | No | |
DamageScalingWC3 | real | No | |
DamageTypeBlocked | integer | No | |
DamageTypeCode | integer | No | |
DamageTypeCriticalStrike | integer | No | |
DamageTypeDebugStr | string | Yes | |
DamageTypeExplosive | integer | No | |
DamageTypeHeal | integer | No | |
DamageTypePure | integer | No | |
DamageTypePureExplosive | integer | No | |
DamageTypeReduced | integer | No | |
DC_AddedAbil | integer | No | |
DC_Caster | unit | No | |
DC_DummyCaster | unit | Yes | |
DC_Hash | hashtable | No | |
DC_I | integervar | No | |
DC_ID | integer | No | |
DC_Level | integer | No | |
DC_Loc | location | No | |
DC_Order | string | No | |
DC_Owner | player | No | |
DC_Target | unit | No | |
DC_TargetDest | destructable | No | |
DC_TargetLoc | location | No | |
DeathEvent | real | 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 | |
DefiledWellBlight | group | No | |
DefiledWellUnblight | group | No | |
Demo_Angle | real | No | |
Demo_Angle_Copy | real | No | |
Demo_Effect | effect | No | |
Demo_TimedAuraGroup | group | No | |
Demo_TimedAuraHashtable | hashtable | No | |
Demo_TimedAuraReal | real | No | |
Demo_Unit | unit | No | |
Demo_Unit_Copy | unit | No | |
DetectRemoveAbility | abilcode | No | |
DetectTransformAbility | abilcode | No | |
Dummy_Angle | real | Yes | |
Dummy_Count | integer | Yes | |
Dummy_CountHead | integer | Yes | |
Dummy_CountNext | integer | Yes | |
Dummy_CountPrev | integer | Yes | |
Dummy_Hashtable | hashtable | No | |
Dummy_LastInstance | integer | No | |
Dummy_Lower | integer | No | |
Dummy_Next | integer | Yes | |
Dummy_Prev | integer | Yes | |
Dummy_Unit | unit | Yes | |
Dummy_UnitCount | integer | No | |
Dummy_Upper | integer | No | |
Dummy_X | real | No | |
Dummy_Y | real | No | |
EnhancedDamageTarget | unit | No | |
EntangledConstructing | group | No | |
EntangledCounter | integer | No | |
EntangledGroup | group | No | |
GoldMineGroup | group | No | |
GoldMineGroup2 | group | No | |
HiddenEntangled | group | No | |
IllusionaryGroup | group | No | |
IllusionaryUnitTmp | 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 | |
KillerOfUnit | unit | Yes | |
LethalDamageEvent | real | No | |
LethalDamageHP | real | No | |
NextDamageIsAttack | boolean | No | |
NextDamageIsMelee | boolean | No | |
NextDamageIsRanged | boolean | No | |
NextDamageType | integer | No | |
NextDamageWeaponT | integer | No | |
NightmareCounter | integer | Yes | |
NightmareGroup | group | No | |
NightmareUnitTmp | unit | No | |
PlayerGroup | force | No | |
PowerGeneratorCount | integer | Yes | |
RaceHandicapVariable | integer | Yes | |
SoundTest | sound | No | |
SpellSteal_Buff | buffcode | No | |
SpellSteal_Group | group | No | |
SpellSteal_Point | location | No | |
SpellSteal_Target | unit | No | |
SummonerOfUnit | unit | Yes | |
Tmp_Loc | location | No | |
TmpInt | integer | No | |
TmpOrder | ordercode | No | |
TmpReal | real | No | |
TmpUnit1 | unit | No | |
TmpUnitGroup | group | No | |
TownHallGroup | group | No | |
UDex | integer | No | |
UDexLastRecycled | integer | No | |
UDexMax | integer | No | |
UDexNext | integer | Yes | |
UDexPrev | integer | Yes | |
UDexUnits | unit | Yes | |
UnitInAction | boolean | Yes | |
UnitInActionEvent | real | No | |
UnitIndexerEnabled | boolean | No | |
UnitIndexEvent | real | No | |
UnitName | string | Yes | |
UnitTypeEvent | real | No | |
UnitTypeOf | unitcode | Yes | |
VanishGroup | group | No | |
WEAPON_TYPE_AM_CHOP | integer | No | |
WEAPON_TYPE_CH_SLICE | integer | No | |
WEAPON_TYPE_CL_SLICE | integer | No | |
WEAPON_TYPE_CM_SLICE | integer | No | |
WEAPON_TYPE_MH_BASH | integer | No | |
WEAPON_TYPE_MH_CHOP | integer | No | |
WEAPON_TYPE_MH_SLICE | integer | No | |
WEAPON_TYPE_MH_STAB | integer | No | |
WEAPON_TYPE_ML_CHOP | integer | No | |
WEAPON_TYPE_ML_SLICE | integer | No | |
WEAPON_TYPE_MM_BASH | integer | No | |
WEAPON_TYPE_MM_CHOP | integer | No | |
WEAPON_TYPE_MM_SLICE | integer | No | |
WEAPON_TYPE_MM_STAB | integer | No | |
WEAPON_TYPE_NONE | integer | No | |
WEAPON_TYPE_RH_BASH | integer | No | |
WEAPON_TYPE_WH_BASH | integer | No | |
WEAPON_TYPE_WH_SLICE | integer | No | |
WEAPON_TYPE_WL_BASH | integer | No | |
WEAPON_TYPE_WL_SLICE | integer | No | |
WEAPON_TYPE_WL_STAB | integer | No | |
WEAPON_TYPE_WM_BASH | integer | No | |
WEAPON_TYPE_WM_SLICE | integer | No | |
WEAPON_TYPE_WM_STAB | integer | No | |
WeaponTypeDebugStr | string | Yes | |
WorldMaxX | real | No | |
WorldMaxY | real | No | |
WSP_AuraArray | integer | No | |
WSP_AuraEffect | string | Yes | |
WSP_AuraEffectPoint | string | Yes | |
WSP_AuraGroup | group | No | |
WSP_AuraGroupAbility | group | Yes | |
WSP_AuraHashtable | hashtable | No | |
WSP_AuraMainAbility | abilcode | Yes | |
WSP_AuraMainDummy | abilcode | Yes | |
WSP_AuraRange | real | Yes | |
WSP_AuraTargetHasAbility | abilcode | Yes | |
WSP_AuraTargetIsAlly | boolean | Yes | |
WSP_AuraTargetIsEnemy | boolean | Yes | |
WSP_AuraTargetIsFlying | boolean | Yes | |
WSP_AuraTargetIsGround | boolean | Yes | |
WSP_AuraTargetIsHero | boolean | Yes | |
WSP_AuraTargetIsLiving | boolean | Yes | |
WSP_AuraTargetIsMechanical | boolean | Yes | |
WSP_AuraTargetIsNonHero | boolean | Yes | |
WSP_AuraTargetIsOrganic | boolean | Yes | |
WSP_AuraTargetIsRace | race | Yes | |
WSP_AuraTargetIsUndead | boolean | Yes | |
WSP_AuraTargetMustBeStructure | boolean | Yes | |
WSP_AuraTargetMustBeSummoned | boolean | Yes | |
WSP_AuraTargetSelf | boolean | Yes | |
WSP_Loop | integer | No | |
WSP_NoneAbility | abilcode | No | |
WSP_NoneRace | race | No | |
WSP_TmpGroup | group | Yes | |
WSP_TmpPoint | location | Yes | |
WSP_TmpUnit | unit | No |
library FrameLoader initializer init_function
// in 1.31 and upto 1.32.9 PTR (when I wrote this). Frames are not correctly saved and loaded, breaking the game.
// This library runs all functions added to it with a 0s delay after the game was loaded.
// function FrameLoaderAdd takes code func returns nothing
// func runs when the game is loaded.
globals
private trigger eventTrigger = CreateTrigger()
private trigger actionTrigger = CreateTrigger()
private timer t = CreateTimer()
endglobals
function FrameLoaderAdd takes code func returns nothing
call TriggerAddAction(actionTrigger, func)
endfunction
private function timerAction takes nothing returns nothing
call TriggerExecute(actionTrigger)
endfunction
private function eventAction takes nothing returns nothing
call TimerStart(t, 0, false, function timerAction)
endfunction
private function init_function takes nothing returns nothing
call TriggerRegisterGameEvent(eventTrigger, EVENT_GAME_LOADED)
call TriggerAddAction(eventTrigger, function eventAction)
endfunction
endlibrary
library CustomConsoleUI initializer init_function requires optional FrameLoader
// CustomConsoleUI by Tasyen
// CustomConsoleUI allows to change the UI during the game, when setuped correctly. This excludes the mouse cursor and the UI sounds.
// In non reforged it can also not change the Idle worker Button nor the no inventory cover.
// How to setup this: First you have to make the default Console Textures be hidden that is done in Game Interface.
// Set ConsoleTexture01 to ConsoleTexture06 to UI\Widgets\EscMenu\Human\blank-background.blp
// The Day of Time clock has hardcoded textures therefore you need to swap it out. That also should be done in Gameinterface.
// TimeOfDayIndicator to the model included in this system.
// Now export and Import war3mapImported\CustomConsoleUI.toc & war3mapImported\CustomConsoleUI.fdf
// Finally you have to set the used textures into local data
globals
private framehandle idleWorkerButton
private framehandle idleWorkerButtonOverlay
private framehandle idleWorkerButtonOverlayParent
private framehandle customInventoryCover
private framehandle customInventoryCoverParent
public string array data
public integer array dataCount
private integer dataPageSize = 11
public real array x
public real array y
// workerFace = true can only be used when you save the map in 1.32.6+
private constant boolean workerFace = true
endglobals
function AddCustomConsole takes integer index, string texture returns nothing
set dataCount[index] = dataCount[index] + 1
set data[index*dataPageSize + dataCount[index]] = texture
endfunction
function UseCustomConsole takes player p, integer index returns nothing
local integer pageValue
if GetLocalPlayer() != p then
return
endif
if index < 1 then
set index = GetHandleId(GetPlayerRace(p))
endif
set pageValue = index*dataPageSize
call BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUI5T", 0), data[pageValue + 5], 0, false)
call BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUI6T", 0), data[pageValue + 6], 0, false)
call BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUI4T", 0), data[pageValue + 4], 0, false)
call BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUI3T", 0), data[pageValue + 3], 0, false)
call BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUI2TL", 0), data[pageValue + 2], 0, false)
call BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUI2TR", 0), data[pageValue + 2], 0, false)
call BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUI1T", 0), data[pageValue + 1], 0, false)
call BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUI1B", 0), data[pageValue + 1], 0, false)
call BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUI2B", 0), data[pageValue + 2], 0, false)
call BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUI3B", 0), data[pageValue + 3], 0, false)
call BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUI4B", 0), data[pageValue + 4], 0, false)
call BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUI5B", 0), data[pageValue + 5], 0, false)
call BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUI6B", 0), data[pageValue + 6], 0, false)
call BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUIClock", 0), data[pageValue + 7] ,0, true)
if GetLocalizedString("REFORGED") != "REFORGED" then
call BlzFrameSetTexture(BlzGetFrameByName("InventoryCoverTexture", 0), data[pageValue + 8] ,0, true)
static if workerFace then
call BlzFrameSetTexture(idleWorkerButtonOverlay, data[pageValue + 9], 0, false)
endif
else
call BlzFrameSetTexture(customInventoryCover, data[pageValue + 8] ,0, true)
endif
call BlzFrameSetPoint(BlzGetFrameByName("CustomConsoleUIClock", 0), FRAMEPOINT_TOP, BlzGetFrameByName("ConsoleUI", 0), FRAMEPOINT_TOP, x[index], y[index])
endfunction
function CreateCustomConsole takes nothing returns nothing
call BlzLoadTOCFile( "war3mapimported\\CustomConsoleUI.toc" )
call BlzCreateSimpleFrame( "CustomConsoleUI", BlzGetFrameByName("ConsoleUI", 0), 0)
if GetLocalizedString("REFORGED") != "REFORGED" then
// Requires a native existing only in Reforged
static if workerFace then
set idleWorkerButton = BlzFrameGetChild(BlzGetFrameByName("ConsoleUI", 0), 7)
set idleWorkerButtonOverlayParent = BlzCreateSimpleFrame( "SimpleTextureFrame", idleWorkerButton, 0 )
set idleWorkerButtonOverlay = BlzGetFrameByName("SimpleTextureFrameValue", 0)
call BlzFrameSetAllPoints(idleWorkerButtonOverlay, idleWorkerButton)
call BlzFrameSetLevel(idleWorkerButtonOverlayParent, 4)
endif
else
set customInventoryCoverParent = BlzCreateSimpleFrame( "SimpleTextureFrame", BlzGetFrameByName("ConsoleUI", 0), 0)
call BlzFrameSetLevel(customInventoryCoverParent, 4)
set customInventoryCover = BlzGetFrameByName("SimpleTextureFrameValue", 0)
call BlzFrameSetAbsPoint(customInventoryCover, FRAMEPOINT_BOTTOMRIGHT, 0.6, 0)
call BlzFrameSetAbsPoint(customInventoryCover, FRAMEPOINT_TOPLEFT, 0.6 - 0.128, 0.2558)
endif
// Preload
call BlzGetOriginFrame(ORIGIN_FRAME_ITEM_BUTTON, 0)
call BlzGetFrameByName("InventoryCoverTexture", 0)
call BlzGetFrameByName("CustomConsoleUIClock", 0)
call BlzGetFrameByName("CustomConsoleUI5T", 0)
call BlzGetFrameByName("CustomConsoleUI6T", 0)
call BlzGetFrameByName("CustomConsoleUI4T", 0)
call BlzGetFrameByName("CustomConsoleUI3T", 0)
call BlzGetFrameByName("CustomConsoleUI2TL", 0)
call BlzGetFrameByName("CustomConsoleUI2TR", 0)
call BlzGetFrameByName("CustomConsoleUI1T", 0)
call BlzGetFrameByName("CustomConsoleUI1B", 0)
call BlzGetFrameByName("CustomConsoleUI2B", 0)
call BlzGetFrameByName("CustomConsoleUI3B", 0)
call BlzGetFrameByName("CustomConsoleUI4B", 0)
call BlzGetFrameByName("CustomConsoleUI5B", 0)
call BlzGetFrameByName("CustomConsoleUI6B", 0)
endfunction
private function Init takes nothing returns nothing
call CreateCustomConsole()
//call UseCustomConsole(GetLocalPlayer(), 0)
//if GetPlayerHandicapBJ(GetLocalPlayer()) == 100.00 then
// call UseCustomConsole(GetLocalPlayer(), 0)
//endif
//if GetPlayerHandicapBJ(GetLocalPlayer()) == 90.00 then
// call UseCustomConsole(GetLocalPlayer(), 6)
//endif
call TriggerExecute( gg_trg_UI_Start_Old )
endfunction
private function at0s takes nothing returns nothing
call Init()
call DestroyTimer(GetExpiredTimer())
endfunction
private function update takes nothing returns nothing
call BlzFrameSetVisible(customInventoryCoverParent, not BlzFrameIsVisible(BlzGetOriginFrame(ORIGIN_FRAME_ITEM_BUTTON, 0)))
endfunction
private function init_function takes nothing returns nothing
local integer index = 0
set index = GetHandleId(RACE_HUMAN)
call AddCustomConsole(index, "ui\\console\\human\\humanuitile01")
call AddCustomConsole(index, "ui\\console\\human\\humanuitile02")
call AddCustomConsole(index, "ui\\console\\human\\humanuitile03")
call AddCustomConsole(index, "ui\\console\\human\\humanuitile04")
call AddCustomConsole(index, "ui\\console\\human\\humanuitile05")
call AddCustomConsole(index, "ui\\console\\human\\humanuitile06")
call AddCustomConsole(index, "ui\\console\\human\\humanuitile-timeindicatorframe")
call AddCustomConsole(index, "ui\\console\\human\\humanuitile-inventorycover")
call AddCustomConsole(index, "ReplaceableTextures\\CommandButtons\\BTNPeasant")
// offset this mostly is used to fit to the glowing orbs showing the houers
set x[index] = 0.0009
set y[index] = 0.0
set index = GetHandleId(RACE_ORC)
call AddCustomConsole(index, "ui\\console\\orc\\orcuitile01")
call AddCustomConsole(index, "ui\\console\\orc\\orcuitile02")
call AddCustomConsole(index, "ui\\console\\orc\\orcuitile03")
call AddCustomConsole(index, "ui\\console\\orc\\orcuitile04")
call AddCustomConsole(index, "ui\\console\\orc\\orcuitile05")
call AddCustomConsole(index, "ui\\console\\orc\\orcuitile06")
call AddCustomConsole(index, "ui\\console\\orc\\orcuitile-timeindicatorframe")
call AddCustomConsole(index, "ui\\console\\orc\\orcuitile-inventorycover")
call AddCustomConsole(index, "ReplaceableTextures\\CommandButtons\\BTNPeon")
set x[index] = 0.0004
set y[index] = 0.0
set index = GetHandleId(RACE_UNDEAD)
call AddCustomConsole(index, "ui\\console\\undead\\undeaduitile01")
call AddCustomConsole(index, "ui\\console\\undead\\undeaduitile02")
call AddCustomConsole(index, "ui\\console\\undead\\undeaduitile03")
call AddCustomConsole(index, "ui\\console\\undead\\undeaduitile04")
call AddCustomConsole(index, "ui\\console\\undead\\undeaduitile05")
call AddCustomConsole(index, "ui\\console\\undead\\undeaduitile06")
call AddCustomConsole(index, "ui\\console\\undead\\undeaduitile-timeindicatorframe")
call AddCustomConsole(index, "ui\\console\\undead\\undeaduitile-inventorycover")
call AddCustomConsole(index, "ReplaceableTextures\\CommandButtons\\BTNAcolyte")
set x[index] = 0.0009
set y[index] = 0.0
set index = GetHandleId(RACE_NIGHTELF)
call AddCustomConsole(index, "ui\\console\\nightelf\\nightelfuitile01")
call AddCustomConsole(index, "ui\\console\\nightelf\\nightelfuitile02")
call AddCustomConsole(index, "ui\\console\\nightelf\\nightelfuitile03")
call AddCustomConsole(index, "ui\\console\\nightelf\\nightelfuitile04")
call AddCustomConsole(index, "ui\\console\\nightelf\\nightelfuitile05")
call AddCustomConsole(index, "ui\\console\\nightelf\\nightelfuitile06")
call AddCustomConsole(index, "ui\\console\\nightelf\\nightelfuitile-timeindicatorframe")
call AddCustomConsole(index, "ui\\console\\nightelf\\nightelfuitile-inventorycover")
call AddCustomConsole(index, "ReplaceableTextures\\CommandButtons\\BTNWisp")
set x[index] = 0.0009
set y[index] = 0.0
set index = GetHandleId(RACE_DEMON)
call AddCustomConsole(index, "ui\\console\\human\\humanuitile01")
call AddCustomConsole(index, "ui\\console\\human\\humanuitile02")
call AddCustomConsole(index, "ui\\console\\human\\humanuitile03")
call AddCustomConsole(index, "ui\\console\\human\\humanuitile04")
call AddCustomConsole(index, "ui\\console\\human\\humanuitile05")
call AddCustomConsole(index, "ui\\console\\human\\humanuitile06")
call AddCustomConsole(index, "ui\\console\\human\\humanuitile-timeindicatorframe")
call AddCustomConsole(index, "ui\\console\\human\\humanuitile-inventorycover")
call AddCustomConsole(index, "ReplaceableTextures\\CommandButtons\\BTNPeasant")
set x[index] = 0.000
set y[index] = 0.0
set index = 6
call AddCustomConsole(index, "war3mapImported\\corrupteduitile01")
call AddCustomConsole(index, "war3mapImported\\corrupteduitile02")
call AddCustomConsole(index, "war3mapImported\\corrupteduitile03")
call AddCustomConsole(index, "war3mapImported\\corrupteduitile04")
call AddCustomConsole(index, "war3mapImported\\corrupteduitile05")
call AddCustomConsole(index, "war3mapImported\\corrupteduitile06")
call AddCustomConsole(index, "war3mapImported\\corrupteduitile-timeindicatorframe")
call AddCustomConsole(index, "war3mapImported\\corrupteduitile-inventorycover2")
call AddCustomConsole(index, "ReplaceableTextures\\CommandButtons\\BTNSatyr")
set x[index] = 0.0009
set y[index] = 0.0
set index = 7
call AddCustomConsole(index, "war3mapImported\\NightElfUITile01")
call AddCustomConsole(index, "war3mapImported\\NightElfUITile02")
call AddCustomConsole(index, "war3mapImported\\NightElfUITile03")
call AddCustomConsole(index, "war3mapImported\\NightElfUITile04")
call AddCustomConsole(index, "war3mapImported\\corrupteduitile05")
call AddCustomConsole(index, "war3mapImported\\corrupteduitile06")
call AddCustomConsole(index, "war3mapImported\\NightElfUITile-timeindicatorframe")
call AddCustomConsole(index, "war3mapImported\\NightElfUITile-inventorycover")
call AddCustomConsole(index, "ReplaceableTextures\\CommandButtons\\BTNSatyr")
set x[index] = 0.0009
set y[index] = 0.0
if GetLocalizedString("REFORGED") == "REFORGED" then
call TimerStart(CreateTimer(), 1/32.0, true, function update)
endif
call TimerStart(CreateTimer(), 0, false, function at0s)
static if LIBRARY_FrameLoader then
call FrameLoaderAdd(function Init)
endif
endfunction
endlibrary
//===========================================================================
function UnitEventDestroyGroup takes integer i returns nothing
if udg_CargoTransportGroup[i] != null then
call DestroyGroup(udg_CargoTransportGroup[i])
set udg_CargoTransportGroup[i] = null
endif
endfunction
function UnitEventCheckAfter takes nothing returns nothing
local integer i = 0
loop
set i = udg_CheckDeathList[i]
exitwhen i == 0
if udg_IsUnitNew[i] then
//The unit was just created.
set udg_IsUnitNew[i] = false
elseif udg_IsUnitTransforming[i] then
//Added 21 July 2017 to fix the issue re-adding this ability in the same instant
set udg_UDex = i
set udg_UnitTypeEvent = 0.00
set udg_UnitTypeEvent = 1.00
set udg_UnitTypeOf[i] = GetUnitTypeId(udg_UDexUnits[i]) //Set this afterward to give the user extra reference
set udg_IsUnitTransforming[i] = false
call UnitAddAbility(udg_UDexUnits[i], udg_DetectTransformAbility)
elseif udg_IsUnitAlive[i] then
//The unit has started reincarnating.
set udg_IsUnitReincarnating[i] = true
set udg_IsUnitAlive[i] = false
set udg_UDex = i
set udg_DeathEvent = 0.50
set udg_DeathEvent = 0.00
endif
set udg_CheckDeathInList[i] = false
endloop
//Empty the list
set udg_CheckDeathList[0] = 0
endfunction
function UnitEventCheckAfterProxy takes integer i returns nothing
if udg_CheckDeathList[0] == 0 then
call TimerStart(udg_CheckDeathTimer, 0.00, false, function UnitEventCheckAfter)
endif
if not udg_CheckDeathInList[i] then
set udg_CheckDeathList[i] = udg_CheckDeathList[0]
set udg_CheckDeathList[0] = i
set udg_CheckDeathInList[i] = true
endif
endfunction
function UnitEventOnUnload takes nothing returns nothing
local integer i = udg_UDex
call GroupRemoveUnit(udg_CargoTransportGroup[GetUnitUserData(udg_CargoTransportUnit[i])], udg_UDexUnits[i])
set udg_IsUnitBeingUnloaded[i] = true
set udg_CargoEvent = 0.00
set udg_CargoEvent = 2.00
set udg_CargoEvent = 0.00
set udg_IsUnitBeingUnloaded[i] = false
if not IsUnitLoaded(udg_UDexUnits[i]) or IsUnitType(udg_CargoTransportUnit[i], UNIT_TYPE_DEAD) or GetUnitTypeId(udg_CargoTransportUnit[i]) == 0 then
set udg_CargoTransportUnit[i] = null
endif
endfunction
function UnitEventOnDeath takes nothing returns boolean
local integer pdex = udg_UDex
set udg_UDex = GetUnitUserData(GetTriggerUnit())
if udg_UDex != 0 then
set udg_KillerOfUnit[udg_UDex] = GetKillingUnit() //Added 29 May 2017 for GIMLI_2
set udg_IsUnitAlive[udg_UDex] = false
set udg_DeathEvent = 0.00
set udg_DeathEvent = 1.00
set udg_DeathEvent = 0.00
set udg_KillerOfUnit[udg_UDex] = null
if udg_CargoTransportUnit[udg_UDex] != null then
call UnitEventOnUnload()
endif
endif
set udg_UDex = pdex
return false
endfunction
function UnitEventOnOrder takes nothing returns boolean
local integer pdex = udg_UDex
local unit u = GetFilterUnit()
local integer i = GetUnitUserData(u)
if i > 0 then
set udg_UDex = i
if GetUnitAbilityLevel(u, udg_DetectRemoveAbility) == 0 then
if not udg_IsUnitRemoved[i] then
set udg_IsUnitRemoved[i] = true
set udg_IsUnitAlive[i] = false
set udg_SummonerOfUnit[i] = null
//For backwards-compatibility:
set udg_DeathEvent = 0.00
set udg_DeathEvent = 3.00
set udg_DeathEvent = 0.00
//Fire deindex event for UDex:
set udg_UnitIndexEvent = 0.00
set udg_UnitIndexEvent = 2.00
set udg_UnitIndexEvent = 0.00
set udg_UDexNext[udg_UDexPrev[i]] = udg_UDexNext[i]
set udg_UDexPrev[udg_UDexNext[i]] = udg_UDexPrev[i]
// Recycle the index for later use
set udg_UDexUnits[i] = null
set udg_UDexPrev[i] = udg_UDexLastRecycled
set udg_UDexLastRecycled = i
call UnitEventDestroyGroup(i)
endif
elseif not udg_IsUnitAlive[i] then
if not IsUnitType(u, UNIT_TYPE_DEAD) then
set udg_IsUnitAlive[i] = true
set udg_DeathEvent = 0.00
set udg_DeathEvent = 2.00
set udg_DeathEvent = 0.00
set udg_IsUnitReincarnating[i] = false
endif
elseif IsUnitType(u, UNIT_TYPE_DEAD) then
if udg_IsUnitNew[i] then
//This unit was created as a corpse.
set udg_IsUnitAlive[i] = false
set udg_DeathEvent = 0.00
set udg_DeathEvent = 1.00
set udg_DeathEvent = 0.00
elseif udg_CargoTransportUnit[i] == null or not IsUnitType(u, UNIT_TYPE_HERO) then
//The unit may have just started reincarnating.
call UnitEventCheckAfterProxy(i)
endif
elseif GetUnitAbilityLevel(u, udg_DetectTransformAbility) == 0 and not udg_IsUnitTransforming[i] then
set udg_IsUnitTransforming[i] = true
call UnitEventCheckAfterProxy(i) //This block has been updated on 21 July 2017
endif
if udg_CargoTransportUnit[i] != null and not udg_IsUnitBeingUnloaded[i] and not IsUnitLoaded(u) or IsUnitType(u, UNIT_TYPE_DEAD) then
call UnitEventOnUnload()
endif
set udg_UDex = pdex
endif
set u = null
return false
endfunction
function UnitEventOnSummon takes nothing returns boolean
local integer pdex = udg_UDex
set udg_UDex = GetUnitUserData(GetTriggerUnit())
if udg_IsUnitNew[udg_UDex] then
set udg_SummonerOfUnit[udg_UDex] = GetSummoningUnit()
set udg_UnitIndexEvent = 0.00
set udg_UnitIndexEvent = 0.50
set udg_UnitIndexEvent = 0.00
endif
set udg_UDex = pdex
return false
endfunction
function UnitEventOnLoad takes nothing returns boolean
local integer pdex = udg_UDex
local integer i = GetUnitUserData(GetTriggerUnit())
local integer index
if i != 0 then
set udg_UDex = i
if udg_CargoTransportUnit[i] != null then
call UnitEventOnUnload()
endif
//Loaded corpses do not issue an order when unloaded, therefore must
//use the enter-region event method taken from Jesus4Lyf's Transport.
if not udg_IsUnitAlive[i] then
call SetUnitX(udg_UDexUnits[i], udg_WorldMaxX)
call SetUnitY(udg_UDexUnits[i], udg_WorldMaxY)
endif
set udg_CargoTransportUnit[i] = GetTransportUnit()
set index = GetUnitUserData(udg_CargoTransportUnit[i])
if udg_CargoTransportGroup[index] == null then
set udg_CargoTransportGroup[index] = CreateGroup()
endif
call GroupAddUnit(udg_CargoTransportGroup[index], udg_UDexUnits[i])
set udg_CargoEvent = 0.00
set udg_CargoEvent = 1.00
set udg_CargoEvent = 0.00
set udg_UDex = pdex
endif
return false
endfunction
function UnitEventEnter takes nothing returns boolean
local integer pdex = udg_UDex
local integer i = udg_UDexLastRecycled
local unit u = GetFilterUnit()
if udg_UnitIndexerEnabled and GetUnitAbilityLevel(u, udg_DetectRemoveAbility) == 0 then
//Generate a unique integer index for this unit
if i == 0 then
set i = udg_UDexMax + 1
set udg_UDexMax = i
else
set udg_UDexLastRecycled = udg_UDexPrev[i]
endif
//Link index to unit, unit to index
set udg_UDexUnits[i] = u
call SetUnitUserData(u, i)
//For backwards-compatibility, add the unit to a linked list
set udg_UDexNext[i] = udg_UDexNext[0]
set udg_UDexPrev[udg_UDexNext[0]] = i
set udg_UDexNext[0] = i
set udg_UDexPrev[i] = 0
set udg_CheckDeathInList[i] = false
call UnitAddAbility(u, udg_DetectRemoveAbility)
call UnitMakeAbilityPermanent(u, true, udg_DetectRemoveAbility)
call UnitAddAbility(u, udg_DetectTransformAbility)
set udg_UnitTypeOf[i] = GetUnitTypeId(u)
set udg_IsUnitNew[i] = true
set udg_IsUnitAlive[i] = true
set udg_IsUnitRemoved[i] = false
set udg_IsUnitReincarnating[i] = false
set udg_IsUnitPreplaced[i] = udg_IsUnitPreplaced[0] //Added 29 May 2017 for Spellbound
call UnitEventCheckAfterProxy(i)
//Fire index event for UDex
set udg_UDex = i
set udg_UnitIndexEvent = 0.00
set udg_UnitIndexEvent = 1.00
set udg_UnitIndexEvent = 0.00
else
set udg_UDex = GetUnitUserData(u)
if udg_CargoTransportUnit[udg_UDex] != null and not IsUnitLoaded(u) then
//The unit was dead, but has re-entered the map.
call UnitEventOnUnload()
endif
endif
set udg_UDex = pdex
set u = null
return false
endfunction
//===========================================================================
function UnitEventInit takes nothing returns nothing
local integer i = bj_MAX_PLAYER_SLOTS //update to make it work with 1.29
local player p
local trigger t = CreateTrigger()
local trigger load = CreateTrigger()
local trigger death = CreateTrigger()
local trigger summon = CreateTrigger()
local rect r = GetWorldBounds()
local region re = CreateRegion()
local boolexpr enterB = Filter(function UnitEventEnter)
local boolexpr orderB = Filter(function UnitEventOnOrder)
set udg_WorldMaxX = GetRectMaxX(r)
set udg_WorldMaxY = GetRectMaxY(r)
call RegionAddRect(re, r)
call RemoveRect(r)
call UnitEventDestroyGroup(0)
call UnitEventDestroyGroup(1)
set udg_CheckDeathList[0] = 0
set udg_UnitIndexerEnabled = true
call TriggerRegisterEnterRegion(CreateTrigger(), re, enterB)
call TriggerAddCondition(load, Filter(function UnitEventOnLoad))
call TriggerAddCondition(death, Filter(function UnitEventOnDeath))
call TriggerAddCondition(summon, Filter(function UnitEventOnSummon))
loop
set i = i - 1
set p = Player(i)
call SetPlayerAbilityAvailable(p, udg_DetectRemoveAbility, false)
call SetPlayerAbilityAvailable(p, udg_DetectTransformAbility, false)
call TriggerRegisterPlayerUnitEvent(summon, p, EVENT_PLAYER_UNIT_SUMMON, null)
call TriggerRegisterPlayerUnitEvent(t, p, EVENT_PLAYER_UNIT_ISSUED_ORDER, orderB)
call TriggerRegisterPlayerUnitEvent(death, p, EVENT_PLAYER_UNIT_DEATH, null)
call TriggerRegisterPlayerUnitEvent(load, p, EVENT_PLAYER_UNIT_LOADED, null)
call GroupEnumUnitsOfPlayer(bj_lastCreatedGroup, p, enterB)
exitwhen i == 0
endloop
set summon = null
set death = null
set load = null
set re = null
set enterB = null
set orderB = null
set p = null
set r = null
set t = null
endfunction
function InitTrig_Unit_Event takes nothing returns nothing
endfunction
library dead
//returns true if the unit is alive. requires JassHelper
// to declare the AI native "UnitAlive" as a JASS native, so that
// we can use it in the trigger editor. If you trigger in vJASS,
// you should DEFINITELY use this since it is the only way to be
// sure that a unit is alive.
native UnitAlive takes unit id returns boolean
//returns true if the unit is dead. inline friendly.
function UnitDead takes unit u returns boolean
return not UnitAlive(u)
endfunction
//returns true if the unit exists in the game. inline friendly.
function DoesUnitExist takes unit u returns boolean
return GetUnitTypeId(u) != 0
endfunction
endlibrary
library bonusx initializer init
/* by quackerd
System to set/get bonus attributes of units
Please see below to add additional support for more attributes
*/
private struct BaseArrayX
integer array abi[17]
integer base
integer max_pow
endstruct
globals
BaseArrayX BNX_AGI
BaseArrayX BNX_STR
BaseArrayX BNX_INT
endglobals
private function BaseArrayX_get_val takes unit u, BaseArrayX arr returns integer
local integer val = 0
local integer tmp = 0
local integer i = 0
loop
exitwhen i > arr.max_pow
set tmp = GetUnitAbilityLevel(u, arr.abi[i])
if tmp > 0 then
if (i == arr.max_pow) then
set val = val - R2I(Pow(I2R(arr.base), I2R(i)))
else
set val = val + tmp * R2I(Pow(I2R(arr.base), I2R(i)))
endif
endif
set i = i + 1
endloop
return val
endfunction
private function BaseArrayX_set_val takes unit u, BaseArrayX arr, integer v returns nothing
local integer val = v
local integer mod = 0
local integer i = 0
local integer lvl = 0
if (val < -1 * R2I(Pow(I2R(arr.base), I2R(arr.max_pow)))) or (val > R2I(Pow(I2R(arr.base), I2R(arr.max_pow))) - 1) then
// we still have leftovers
call BJDebugMsg("Bonus: Integer " + I2S(v) + " too large.")
return
endif
// handle minus
if val < 0 then
set val = R2I(Pow(I2R(arr.base), I2R(arr.max_pow))) + val
set lvl = GetUnitAbilityLevel(u, arr.abi[arr.max_pow])
if lvl == 0 then
call UnitAddAbility(u, arr.abi[arr.max_pow])
call UnitMakeAbilityPermanent(u, true, arr.abi[arr.max_pow])
endif
else
call UnitRemoveAbility(u, arr.abi[arr.max_pow])
endif
loop
exitwhen i > arr.max_pow - 1
set mod = ModuloInteger(val, arr.base)
set val = val / arr.base
set lvl = GetUnitAbilityLevel(u, arr.abi[i])
if mod == 0 then
if lvl > 0 then
call UnitRemoveAbility(u, arr.abi[i])
endif
else
set lvl = GetUnitAbilityLevel(u, arr.abi[i])
if lvl == 0 then
call UnitAddAbility(u, arr.abi[i])
call UnitMakeAbilityPermanent(u, true, arr.abi[i])
endif
call SetUnitAbilityLevel(u, arr.abi[i], mod)
endif
set i = i + 1
endloop
endfunction
function BnxSetUnitBonus takes unit u, BaseArrayX arr, integer val returns nothing
call BaseArrayX_set_val(u, arr, val)
endfunction
function BnxGetUnitBonus takes unit u, BaseArrayX arr returns integer
return BaseArrayX_get_val(u, arr)
endfunction
function UtPreloadAbility takes integer abi returns nothing
local unit u = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), 'ewsp', 0, 0, 0)
call UnitAddAbility(u, abi)
call UnitRemoveAbility(u, abi)
call RemoveUnit(u)
set u = null
endfunction
private function preload_BaseArrayX takes BaseArrayX arr returns nothing
local integer abi
local integer i = 0
loop
set abi = arr.abi[i]
exitwhen abi == 0 or i > 16
call UtPreloadAbility(abi)
set i = i + 1
endloop
endfunction
//===========================================================================
private function init takes nothing returns nothing
set BNX_STR = BaseArrayX.create()
set BNX_STR.max_pow = 16
set BNX_STR.base = 2
set BNX_STR.abi[0] = 'ABS0'
set BNX_STR.abi[1] = 'ABS1'
set BNX_STR.abi[2] = 'ABS2'
set BNX_STR.abi[3] = 'ABS3'
set BNX_STR.abi[4] = 'ABS4'
set BNX_STR.abi[5] = 'ABS5'
set BNX_STR.abi[6] = 'ABS6'
set BNX_STR.abi[7] = 'ABS7'
set BNX_STR.abi[8] = 'ABS8'
set BNX_STR.abi[9] = 'ABS9'
set BNX_STR.abi[10] = 'ABSA'
set BNX_STR.abi[11] = 'ABSB'
set BNX_STR.abi[12] = 'ABSC'
set BNX_STR.abi[13] = 'ABSD'
set BNX_STR.abi[14] = 'ABSE'
set BNX_STR.abi[15] = 'ABSF'
set BNX_STR.abi[16] = 'ABSm'
call preload_BaseArrayX(BNX_STR)
set BNX_INT = BaseArrayX.create()
set BNX_INT.max_pow = 16
set BNX_INT.base = 2
set BNX_INT.abi[0] = 'ABI0'
set BNX_INT.abi[1] = 'ABI1'
set BNX_INT.abi[2] = 'ABI2'
set BNX_INT.abi[3] = 'ABI3'
set BNX_INT.abi[4] = 'ABI4'
set BNX_INT.abi[5] = 'ABI5'
set BNX_INT.abi[6] = 'ABI6'
set BNX_INT.abi[7] = 'ABI7'
set BNX_INT.abi[8] = 'ABI8'
set BNX_INT.abi[9] = 'ABI9'
set BNX_INT.abi[10] = 'ABIA'
set BNX_INT.abi[11] = 'ABIB'
set BNX_INT.abi[12] = 'ABIC'
set BNX_INT.abi[13] = 'ABID'
set BNX_INT.abi[14] = 'ABIE'
set BNX_INT.abi[15] = 'ABIF'
set BNX_INT.abi[16] = 'ABIm'
call preload_BaseArrayX(BNX_INT)
set BNX_AGI = BaseArrayX.create()
set BNX_AGI.max_pow = 16
set BNX_AGI.base = 2
set BNX_AGI.abi[0] = 'ABA0'
set BNX_AGI.abi[1] = 'ABA1'
set BNX_AGI.abi[2] = 'ABA2'
set BNX_AGI.abi[3] = 'ABA3'
set BNX_AGI.abi[4] = 'ABA4'
set BNX_AGI.abi[5] = 'ABA5'
set BNX_AGI.abi[6] = 'ABA6'
set BNX_AGI.abi[7] = 'ABA7'
set BNX_AGI.abi[8] = 'ABA8'
set BNX_AGI.abi[9] = 'ABA9'
set BNX_AGI.abi[10] = 'ABAA'
set BNX_AGI.abi[11] = 'ABAB'
set BNX_AGI.abi[12] = 'ABAC'
set BNX_AGI.abi[13] = 'ABAD'
set BNX_AGI.abi[14] = 'ABAE'
set BNX_AGI.abi[15] = 'ABAF'
set BNX_AGI.abi[16] = 'ABAm'
call preload_BaseArrayX(BNX_AGI)
endfunction
endlibrary
scope beatupaura initializer init
// this is an example of stacking aura
// notice how our primary logic is in AuraNode instead of AuraBuff
globals
private constant integer SPELL_ID = 'A000'
private constant integer DMG = 10
private Table g_tbl
endglobals
private struct AuraBuff extends AuraSysBuff
private static constant string TARGET_EFFECT = "Abilities\\Spells\\NightElf\\shadowstrike\\shadowstrike.mdl"
private effect e
// called when this buff is applied to an unit the first time
method on_apply takes nothing returns nothing
set e = AddSpecialEffectTarget(TARGET_EFFECT, this.as_target, "overhead")
endmethod
// called when the last AuraSys that inflicts this buff is removed from an unit
method on_remove takes nothing returns nothing
call DestroyEffect(e)
set e = null
endmethod
endstruct
private struct AuraNode extends AuraSysNode
private timer t
static method on_tick takes nothing returns nothing
local thistype this = g_tbl[GetHandleId(GetExpiredTimer())]
call UnitDamageTargetBJ(this.as_sys.as_source, this.as_buff.as_target, 10 * (BlzGroupGetSize(this.as_sys.as_activeg) + BlzGroupGetSize(this.as_sys.as_lingerg)), ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL)
endmethod
// called everytime a new AuraSys is added to the buff
method on_apply takes nothing returns nothing
set t = CreateTimer()
call TimerStart(t, 1, true, function thistype.on_tick)
set g_tbl[GetHandleId(t)] = this
endmethod
// called everytime an AuraSys is removed from the buff
method on_remove takes nothing returns nothing
call g_tbl.remove(GetHandleId(t))
call DestroyTimer(t)
set t = null
endmethod
endstruct
private struct Aura extends AuraSys
implement AuraSysInit
private static constant integer BUFF_SPELL_ID = 'A00P'
private static constant integer BUFF_ID = 'B00P'
private effect e
method get_range takes nothing returns real
return I2R(GetUnitAbilityLevel(this.as_source, SPELL_ID) * 300)
endmethod
method active_cond takes nothing returns boolean
return UnitAlive(this.as_source)
endmethod
method filter takes unit u returns boolean
return IsUnitEnemy(u, GetOwningPlayer(this.as_source)) and UnitAlive(u)
endmethod
method linger_filter takes unit u returns boolean
return UnitAlive(u)
endmethod
method new_buff takes nothing returns AuraSysBuff
return AuraBuff.create()
endmethod
method new_node takes nothing returns AuraSysNode
return AuraNode.create()
endmethod
method get_buff_typeid takes nothing returns integer
return AuraBuff.typeid
endmethod
method on_apply takes nothing returns nothing
set e = AddSpecialEffectTarget("Abilities\\Spells\\Undead\\UnholyAura\\UnholyAura.mdl", this.as_source, "origin")
endmethod
method on_remove takes nothing returns nothing
call DestroyEffect(e)
set e = null
endmethod
endstruct
private function learn_action takes nothing returns nothing
local Aura aura
if (GetLearnedSkill() == SPELL_ID) and GetLearnedSkillLevel() == 1 then
set aura = Aura.new(GetTriggerUnit())
endif
endfunction
//===========================================================================
private function init takes nothing returns nothing
local trigger t
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_HERO_SKILL)
call TriggerAddAction(t, function learn_action)
set g_tbl = Table.create()
set t = null
endfunction
endscope
scope strengthaura initializer init
// this is an example of non-stacking aura
globals
private constant integer SPELL_ID = 'A01E'
private constant integer STR_LVL = 1
private Table g_tbl
endglobals
private struct AuraBuff extends AuraSysBuff
private static constant string TARGET_EFFECT = "Abilities\\Spells\\Orc\\Bloodlust\\BloodlustTarget.mdl"
private effect el
private effect er
private timer t
private integer max_lvl
private integer cur_str
// called when this buff is applied to an unit the first time
method on_apply takes nothing returns nothing
set el = AddSpecialEffectTarget(TARGET_EFFECT, this.as_target, "hand left")
set er = AddSpecialEffectTarget(TARGET_EFFECT, this.as_target, "hand right")
set t = CreateTimer()
call TimerStart(t, 1.5, true, function thistype.on_tick)
set g_tbl[GetHandleId(t)] = this
endmethod
// called when the last AuraSys that inflicts this buff is removed from an unit
method on_remove takes nothing returns nothing
call g_tbl.remove(GetHandleId(t))
call PauseTimer(t)
call DestroyTimer(t)
set t = null
call DestroyEffect(el)
set el = null
call DestroyEffect(er)
set el = null
endmethod
static method on_tick takes nothing returns nothing
// periodically update level since the hero stat might change
local thistype this = g_tbl[GetHandleId(GetExpiredTimer())]
call this.update()
endmethod
method update takes nothing returns nothing
call this.update_lvl()
call this.update_str()
endmethod
private method update_str takes nothing returns nothing
local integer next = max_lvl * STR_LVL * GetHeroStr(this.as_target, false)
if next != this.cur_str then
call BnxSetUnitBonus(this.as_target, BNX_STR, BnxGetUnitBonus(this.as_target, BNX_STR) + (next - this.cur_str))
set this.cur_str = next
endif
endmethod
private method update_lvl takes nothing returns nothing
// keep track of the max_lvl
local AuraSysNode head = AuraSys.get_node_head(this)
local AuraSysNode next = head
local integer tmp = 0
local integer tmp2
// enum the highest score
loop
set next = AuraSys.get_next_node(head, next, 0)
exitwhen next == 0
set tmp2 = GetUnitAbilityLevel(next.as_sys.as_source, SPELL_ID)
if tmp < tmp2 then
set tmp = tmp2
endif
endloop
set this.max_lvl = tmp
endmethod
endstruct
private struct AuraNode extends AuraSysNode
// called everytime a new AuraSys is added to the buff
method on_apply takes nothing returns nothing
local AuraBuff buf = this.as_buff
call buf.update()
endmethod
// called everytime an AuraSys is removed from the buff
method on_remove takes nothing returns nothing
local AuraBuff buf = this.as_buff
call buf.update()
endmethod
endstruct
private struct Aura extends AuraSys
implement AuraSysInit
private static constant integer BUFF_SPELL_ID = 'A00W'
private static constant integer BUFF_ID = 'B00W'
private effect e
method get_range takes nothing returns real
return 900.0
endmethod
method active_cond takes nothing returns boolean
return UnitAlive(this.as_source)
endmethod
method filter takes unit u returns boolean
return IsUnitAlly(u, GetOwningPlayer(this.as_source)) and IsUnitType(u, UNIT_TYPE_HERO) and UnitAlive(u)
endmethod
method linger_filter takes unit u returns boolean
return UnitAlive(u)
endmethod
method new_node takes nothing returns AuraSysNode
return AuraNode.create()
endmethod
method new_buff takes nothing returns AuraSysBuff
return AuraBuff.create()
endmethod
method get_buff_typeid takes nothing returns integer
return AuraBuff.typeid
endmethod
method on_apply takes nothing returns nothing
set e = AddSpecialEffectTarget("Abilities\\Spells\\Orc\\Bloodlust\\BloodlustTarget.mdl", this.as_source, "overhead")
endmethod
method on_remove takes nothing returns nothing
call DestroyEffect(e)
set e = null
endmethod
endstruct
private function learn_action takes nothing returns nothing
local Aura aura
if (GetLearnedSkill() == SPELL_ID) and GetLearnedSkillLevel() == 1 then
set aura = Aura.new(GetTriggerUnit())
endif
endfunction
//===========================================================================
private function init takes nothing returns nothing
local trigger t
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_HERO_SKILL)
call TriggerAddAction(t, function learn_action)
set g_tbl = Table.create()
set t = null
endfunction
endscope
scope strengthaura initializer init
// this is an example of non-stacking aura
globals
private constant integer SPELL_ID = 'A01E'
private constant integer STR_LVL = 1
private Table g_tbl
endglobals
private struct AuraBuff extends AuraSysBuff
private static constant string TARGET_EFFECT = "Abilities\\Spells\\Orc\\Bloodlust\\BloodlustTarget.mdl"
private effect el
private effect er
private timer t
private integer max_lvl
private integer cur_lvl
// called when this buff is applied to an unit the first time
method on_apply takes nothing returns nothing
set el = AddSpecialEffectTarget(TARGET_EFFECT, this.as_target, "hand left")
set er = AddSpecialEffectTarget(TARGET_EFFECT, this.as_target, "hand right")
set t = CreateTimer()
call TimerStart(t, 1.5, true, function thistype.on_tick)
set g_tbl[GetHandleId(t)] = this
endmethod
// called when the last AuraSys that inflicts this buff is removed from an unit
method on_remove takes nothing returns nothing
call g_tbl.remove(GetHandleId(t))
call PauseTimer(t)
call DestroyTimer(t)
set t = null
call DestroyEffect(el)
set el = null
call DestroyEffect(er)
set el = null
endmethod
static method on_tick takes nothing returns nothing
// periodically update level since the hero stat might change
local thistype this = g_tbl[GetHandleId(GetExpiredTimer())]
call this.update()
endmethod
method update takes nothing returns nothing
call this.update_lvl()
call this.update_buff()
endmethod
private method update_buff takes nothing returns nothing
local integer next = max_lvl
if next != this.cur_lvl then
call SetUnitAbilityLevel(this.as_target, 'A00W', max_lvl)
set this.cur_lvl = next
endif
endmethod
private method update_lvl takes nothing returns nothing
// keep track of the max_lvl
local AuraSysNode head = AuraSys.get_node_head(this)
local AuraSysNode next = head
local integer tmp = 0
local integer tmp2
// enum the highest score
loop
set next = AuraSys.get_next_node(head, next, 0)
exitwhen next == 0
set tmp2 = GetUnitAbilityLevel(next.as_sys.as_source, SPELL_ID)
if tmp < tmp2 then
set tmp = tmp2
endif
endloop
set this.max_lvl = tmp
endmethod
endstruct
private struct AuraNode extends AuraSysNode
// called everytime a new AuraSys is added to the buff
method on_apply takes nothing returns nothing
local AuraBuff buf = this.as_buff
call buf.update()
endmethod
// called everytime an AuraSys is removed from the buff
method on_remove takes nothing returns nothing
local AuraBuff buf = this.as_buff
call buf.update()
endmethod
endstruct
private struct Aura extends AuraSys
implement AuraSysInit
private static constant integer BUFF_SPELL_ID = 'A00W'
private static constant integer BUFF_ID = 'B00W'
private effect e
method get_range takes nothing returns real
return 900.0
endmethod
method active_cond takes nothing returns boolean
return UnitAlive(this.as_source)
endmethod
method filter takes unit u returns boolean
return IsUnitAlly(u, GetOwningPlayer(this.as_source)) and IsUnitType(u, UNIT_TYPE_HERO) and UnitAlive(u)
endmethod
method linger_filter takes unit u returns boolean
return UnitAlive(u)
endmethod
method new_node takes nothing returns AuraSysNode
return AuraNode.create()
endmethod
method new_buff takes nothing returns AuraSysBuff
return AuraBuff.create()
endmethod
method get_buff_typeid takes nothing returns integer
return AuraBuff.typeid
endmethod
method on_apply takes nothing returns nothing
set e = AddSpecialEffectTarget("Abilities\\Spells\\Orc\\Bloodlust\\BloodlustTarget.mdl", this.as_source, "overhead")
endmethod
method on_remove takes nothing returns nothing
call DestroyEffect(e)
set e = null
endmethod
endstruct
private function learn_action takes nothing returns nothing
local Aura aura
if (GetLearnedSkill() == SPELL_ID) and GetLearnedSkillLevel() == 1 then
set aura = Aura.new(GetTriggerUnit())
endif
endfunction
//===========================================================================
private function init takes nothing returns nothing
local trigger t
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_HERO_SKILL)
call TriggerAddAction(t, function learn_action)
set g_tbl = Table.create()
set t = null
endfunction
endscope
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
library AuraSys initializer init requires Table
/* v0.2 made by quackerd
INTRO:
A somewhat complicated but very flexible custom aura system that follows vanilla aura's design.
***Impossible to use in GUI***
Supports:
- Stacking & non-stacking auras
- Aura lingering
- Aura enumeration
DESIGN:
AuraSys consists of 3 components:
- struct AuraSys: this is the main object representing an aura
- struct AuraBuff: this is the buff object that AuraSys applies onto each unit
- struct AuraNode: each AuraBuff contains multiple AuraNodes, which keeps track of all AuraSyses that give the buff.
this exists because AuraSyses that give the same buff only apply the buff once
Graphically:
+----------------------------------------------+
| |
v |
+----+----+ |
|AuraSys A| +------+---------+
|Unit 1 +----+ +--------------+ |AuraNode for |
+---------+ | Affects | AuraBuff A | |AuraSys A Unit 1|
+-------->+ Unit 3 +--->-----------------+
| +--------------+ |AuraNode for |
+---------+ | |AuraSys A Unit 2|
|AuraSys A+----+ +------+---------+
|Unit 2 | |
+----+----+ |
^ |
| |
+----------------------------------------------+
Both unit 1 and 2 have the same aura type. They both affect unit 3.
Notice that only one AuraBuff is created but there is an AuraNode for
each aura source.
GETTING STARTED:
1. Create a buff ability inheriting Slow Aura (Tornado) and a buff
Make sure to
- Set the buff of the ability to the corresponding buff
2. Create struct Aura that extends AuraSys
Make sure to
- Implement all stub functions
- Add "implement AuraSysInit" to your struct
- Declare
private static constant integer BUFF_SPELL_ID = Your Slow Aura ID from step 1
private static constant integer BUFF_ID = Your buff ID from step 1
3. Create struct AuraBuff that extends AuraSysBuff
Make sure to
- Implement all stub functions
4. Create struct AuraNode that extends AuraSysNode
Make sure to
- Implement all stub functions
5. Create event - Unit Learns Ability | Action - Add Aura to the unit
API:
I'm only listing public static functions here.
For struct-specific stuff please check out each struct and the demo map. There are detailed documentation and examples there.
To add an aura:
local SomeAura aura = SomeAura.new(source_unit)
To remove an aura:
call aura.delete()
To enum AuraBuffs of a unit:
local AuraSysBuff head = AuraSys.get_buff_head(some_unit)
local AuraSysBuff next = head
loop
// note that the following returns the next buff with buff.getType() == typeid
// setting typeid to 0 returns the next buff of any type
set next = AuraSys.get_next_buff(head, next, typeid)
exitwhen next == 0
// do your stuff
endloop
To enum AuraNodes of an AuraBuff:
local AuraNode head = AuraNode.get_node_head(some_buff)
local AuraNode next = head
loop
// note that the following returns the next node pointing to AuraSys sys
// setting sys to 0 returns the next node of any AuraSys
set next = AuraSys.get_next_node(head, next, sys)
exitwhen next == 0
// do your stuff
endloop
TENTATIVE STUFF (Please LMK):
- Aura Events?
- ...
Credits:
==vJass by Vexorian==
==BuffSystem by Flux== for vJass OOP lessons and some inspirations in aura stacking
==Table by bribe==
*/
globals
/**============ Configurables ============**/
// The interval at which the aura system registers units at. Change with caution as an extremely small value
// will result in reduced performance
private constant real UPDATE_INTERVAL = 0.25
// The aura lingering time (how many UPDATE_INTERVAL)
private constant integer LINGER_UNIT = 12 // 0.25 * 12 = 3 seconds
/**============ End Configurables ============**/
private Table g_tbl
endglobals
private module ListNode
thistype next
thistype prev
method ln_init takes nothing returns nothing
set this.next = this
set this.prev = this
endmethod
method ln_insert takes thistype e returns nothing
set this.next = e.next
set this.prev = e
set e.next.prev = this
set e.next = this
endmethod
method ln_empty takes nothing returns boolean
return (this.next == this)
endmethod
method ln_remove takes nothing returns nothing
set this.prev.next = this.next
set this.next.prev = this.prev
set this.next = this
set this.prev = this
endmethod
endmodule
/**============ struct AuraSysNode ============**/
struct AuraSysNode
// DONT TOUCH
implement ListNode
// The AuraSys this node points to
// Accessible in member methods, readonly
AuraSys as_sys
// The AuraBuff this node belongs to
// Accessible in member methods, readonly
AuraSysBuff as_buff
// on_apply callback. Called when a new node is inserted to the buff
// E.g. A unit gains the aura from a non-existing source
stub method on_apply takes nothing returns nothing
endmethod
// on_remove callback. Called when an existing node is removed from the buff
stub method on_remove takes nothing returns nothing
endmethod
endstruct
/**============End struct AuraSysNode ============**/
/**============ struct AuraSysBuff ============**/
struct AuraSysBuff
// DONT TOUCH
implement ListNode
// DONT TOUCH
AuraSysNode as_head
// The target unit of the buff
// Accessible in member methods, readonly
unit as_target
// on_apply callback. Called when a buff is applied to a unit
// useful for applying special effects
stub method on_apply takes nothing returns nothing
endmethod
// on_remove callback. Called when a buff is removed from a unit
stub method on_remove takes nothing returns nothing
endmethod
endstruct
/**============ End struct AuraSysBuff ============**/
struct AuraSys
// The source of the aura
// Accessible in member methods, readonly
unit as_source
// Group of units that are actively affected
// Accessible in member methods, readonly
group as_activeg
// Group of units that are lingering
// Accessible in member methods, readonly
group as_lingerg
/** start DONT TOUCH **/
private integer as_buff_spell_id
private integer as_buff_id
private group as_tmpg
private group as_enumg
private group as_removeg
private timer as_t
private Table as_linger_tbl
/** end DONT TOUCH **/
// the condition when the aura is considered active
// E.g. to disable aura upon unit death write "return IsUnitAliveBJ(this.as_source)"
stub method active_cond takes nothing returns boolean
return false
endmethod
// the filter for affected units. Returning true means can affect.
stub method filter takes unit u returns boolean
return false
endmethod
// the current range of the aura.
stub method get_range takes nothing returns real
return 0.0
endmethod
// the filter for lingering units. Returning true means can linger.
// E.g. to immediately remove buffs when an unit dies write "return IsUnitAliveBJ(this.as_source)"
stub method linger_filter takes unit u returns boolean
return IsUnitAliveBJ(u)
endmethod
// returns an instance of your custom node struct that extends AuraSysNode
stub method new_node takes nothing returns AuraSysNode
return 0
endmethod
// returns an instance of your custom buff struct that extends AuraSysBuff
stub method new_buff takes nothing returns AuraSysBuff
return 0
endmethod
// returns the typeid of your custom buff struct
stub method get_buff_typeid takes nothing returns integer
return 0
endmethod
// called when the aura is added to the source
stub method on_apply takes nothing returns nothing
endmethod
// called when the aura is removed from the source
stub method on_remove takes nothing returns nothing
endmethod
static method get_node_head takes AuraSysBuff buf returns AuraSysNode
return buf.as_head
endmethod
static method get_next_node takes AuraSysNode head, AuraSysNode cur, AuraSys sys returns AuraSysNode
set cur = cur.next
loop
exitwhen cur == head or sys == 0 or cur.as_sys == sys
set cur = cur.next
endloop
if cur == head then
set cur = 0
endif
return cur
endmethod
static method get_buff_head takes unit u returns AuraSysBuff
if not g_tbl.has(GetHandleId(u)) then
debug call BJDebugMsg("NOT HAVE")
return 0
endif
return g_tbl[GetHandleId(u)]
endmethod
static method get_next_buff takes AuraSysBuff head, AuraSysBuff cur, integer typeid returns AuraSysBuff
set cur = cur.next
loop
exitwhen cur == head or typeid == 0 or cur.getType() == typeid
set cur = cur.next
endloop
if cur == head then
set cur = 0
endif
return cur
endmethod
private method apply_buff takes unit u returns nothing
local AuraSysBuff buf_head = g_tbl[GetHandleId(u)]
local AuraSysBuff buf_first
local AuraSysNode node_new
local boolean newbuf = false
// ensure buf_head exists
if buf_head == 0 then
set buf_head = AuraSysBuff.create()
call buf_head.ln_init()
set g_tbl[GetHandleId(u)] = buf_head
debug call BJDebugMsg("unit " + I2S(GetHandleId(u)) + " buffhead insert " + I2S(buf_head))
endif
set buf_first = thistype.get_next_buff(buf_head, buf_head, this.get_buff_typeid())
if buf_first == 0 then
// add AuraSysBuff
call UnitAddAbility(u, this.as_buff_spell_id)
call UnitMakeAbilityPermanent(u, true, this.as_buff_spell_id)
set buf_first = this.new_buff()
call buf_first.ln_init()
set buf_first.as_target = u
set buf_first.as_head = AuraSysNode.create()
call buf_first.as_head.ln_init()
call buf_first.ln_insert(buf_head)
set newbuf = true
debug call BJDebugMsg("unit " + I2S(GetHandleId(u)) + " buff add " + I2S(buf_first))
endif
set node_new = this.new_node()
set node_new.as_sys = this
set node_new.as_buff = buf_first
call node_new.ln_init()
call node_new.ln_insert(buf_first.as_head)
debug call BJDebugMsg("unit " + I2S(GetHandleId(u)) + " node add " + I2S(node_new))
if newbuf then
call buf_first.on_apply()
endif
call node_new.on_apply()
endmethod
private method remove_buff takes unit u returns nothing
local AuraSysBuff buf_head = g_tbl[GetHandleId(u)]
local AuraSysBuff buf_first
local AuraSysNode node_first
if buf_head == 0 then
debug call BJDebugMsg("Removing from an empty head")
return
endif
set buf_first = thistype.get_next_buff(buf_head, buf_head, this.get_buff_typeid())
if buf_first == 0 then
debug call BJDebugMsg("Cannot find buff for removal")
return
else
// locate the node
set node_first = thistype.get_next_node(buf_first.as_head, buf_first.as_head, this)
if node_first == 0 then
debug call BJDebugMsg("Cannot find node for removal")
return
endif
// remove from buf
call node_first.ln_remove()
call node_first.on_remove()
call node_first.destroy()
debug call BJDebugMsg("unit " + I2S(GetHandleId(u)) + " node remove " + I2S(node_first))
// check for empty as_head
if buf_first.as_head.ln_empty() then
// remove buff
call UnitRemoveAbility(u, this.as_buff_spell_id)
call UnitRemoveAbility(u, this.as_buff_id)
call buf_first.ln_remove()
call buf_first.on_remove()
// cleanup
set buf_first.as_target = null
call buf_first.as_head.destroy()
call buf_first.destroy()
debug call BJDebugMsg("unit " + I2S(GetHandleId(u)) + " buff remove " + I2S(buf_first))
endif
// check for empty global buff
if buf_head.ln_empty() then
debug call BJDebugMsg("unit " + I2S(GetHandleId(u)) + " buffhead remove " + I2S(buf_head))
call buf_head.destroy()
call g_tbl.remove(GetHandleId(u))
endif
endif
endmethod
private method on_tick takes nothing returns nothing
local unit each
local integer i
local group g
call GroupClear(this.as_tmpg)
call GroupClear(this.as_removeg)
// process lingering stuff
loop
set each = FirstOfGroup(this.as_lingerg)
exitwhen each == null
set i = as_linger_tbl[GetHandleId(each)]
set i = i - 1
debug call BJDebugMsg("UNIT " + I2S(GetHandleId(each)) + " LINGER - " + I2S(i))
if i > 0 and this.linger_filter(each) then
set this.as_linger_tbl[GetHandleId(each)] = i
call GroupAddUnit(this.as_tmpg, each)
else
call this.as_linger_tbl.remove(GetHandleId(each))
call GroupAddUnit(this.as_removeg, each)
endif
call GroupRemoveUnit(this.as_lingerg, each)
endloop
set g = this.as_tmpg
set this.as_tmpg = this.as_lingerg
set this.as_lingerg = g
// as_tmpg == empty
if this.active_cond() then
call GroupClear(this.as_enumg)
call GroupEnumUnitsInRange(this.as_enumg, GetUnitX(this.as_source), GetUnitY(this.as_source), this.get_range(), null)
// delete aura from old units
loop
set each = FirstOfGroup(this.as_activeg)
exitwhen each == null
// remove units that do not meet the requirement
if ((not this.filter(each)) or (not IsUnitInGroup(each, this.as_enumg))) then
// let it linger
if this.linger_filter(each) then
call GroupAddUnit(this.as_lingerg, each)
set this.as_linger_tbl[GetHandleId(each)] = LINGER_UNIT
else
// immediately remove the buff
call GroupAddUnit(this.as_removeg, each)
endif
else
call GroupAddUnit(this.as_tmpg, each)
endif
call GroupRemoveUnit(this.as_activeg, each)
endloop
set g = this.as_activeg
set this.as_activeg = this.as_tmpg
set this.as_tmpg = g
// add aura to new units
loop
set each = FirstOfGroup(this.as_enumg)
exitwhen each == null
if this.filter(each) and not IsUnitInGroup(each, this.as_activeg) then
call GroupAddUnit(this.as_activeg, each)
if IsUnitInGroup(each, this.as_lingerg) then
// lingering units that regained the aura
call this.as_linger_tbl.remove(GetHandleId(each))
call GroupRemoveUnit(this.as_lingerg, each)
else
// new unit
call GroupAddUnit(this.as_tmpg, each)
endif
endif
call GroupRemoveUnit(this.as_enumg, each)
endloop
else
// add all active units to lingering
loop
set each = FirstOfGroup(this.as_activeg)
exitwhen each == null
if this.linger_filter(each) then
call GroupAddUnit(this.as_lingerg, each)
set this.as_linger_tbl[GetHandleId(each)] = LINGER_UNIT
else
call GroupAddUnit(this.as_removeg, each)
endif
call GroupRemoveUnit(this.as_activeg, each)
endloop
endif
// now that as_tmpg contains units need buff apply
// as_removeg contains units need buff removal
// as_activeg and as_lingerg is stable for the current epoch
loop
set each = FirstOfGroup(this.as_removeg)
exitwhen each == null
call this.remove_buff(each)
call GroupRemoveUnit(this.as_removeg, each)
endloop
loop
set each = FirstOfGroup(this.as_tmpg)
exitwhen each == null
call this.apply_buff(each)
call GroupRemoveUnit(this.as_tmpg, each)
endloop
set each = null
set g = null
endmethod
private static method timer_action takes nothing returns nothing
local thistype this = g_tbl[GetHandleId(GetExpiredTimer())]
// possibly delete fires in the same frame as timer
if this != 0 then
call this.on_tick()
endif
endmethod
method init takes unit u, integer buffid, integer buffspellid returns nothing
set this.as_source = u
set this.as_removeg = CreateGroup()
set this.as_activeg = CreateGroup()
set this.as_lingerg = CreateGroup()
set this.as_buff_id = buffid
set this.as_buff_spell_id = buffspellid
set this.as_enumg = CreateGroup()
set this.as_linger_tbl = Table.create()
set this.as_tmpg = CreateGroup()
set this.as_t = CreateTimer()
set g_tbl[GetHandleId(this.as_t)] = this
call TimerStart(this.as_t, UPDATE_INTERVAL ,true , function thistype.timer_action)
call this.on_apply()
call this.on_tick()
endmethod
method delete takes nothing returns nothing
local unit each
// delete everything active/linger
call GroupClear(this.as_tmpg)
call BlzGroupAddGroupFast(this.as_tmpg, this.as_activeg)
call BlzGroupAddGroupFast(this.as_tmpg, this.as_lingerg)
call GroupClear(this.as_activeg)
call GroupClear(this.as_lingerg)
// now activeg and lingerg are stable, call remove_buff
loop
set each = FirstOfGroup(this.as_tmpg)
exitwhen each == null
call this.remove_buff(each)
call GroupRemoveUnit(this.as_tmpg, each)
endloop
call this.on_remove()
// destroy the timer
call g_tbl.remove(GetHandleId(this.as_t))
call DestroyTimer(this.as_t)
set this.as_t = null
set this.as_source = null
call DestroyGroup(this.as_activeg)
set this.as_activeg = null
call DestroyGroup(this.as_tmpg)
set this.as_tmpg = null
call DestroyGroup(this.as_removeg)
set this.as_removeg = null
call DestroyGroup(this.as_lingerg)
set this.as_lingerg = null
call DestroyGroup(this.as_enumg)
set this.as_enumg = null
call this.as_linger_tbl.destroy()
set each = null
endmethod
endstruct
module AuraSysInit
static method new takes unit u returns AuraSys
local thistype ret = thistype.create()
call ret.init(u, BUFF_ID, BUFF_SPELL_ID)
return ret
endmethod
endmodule
private function init takes nothing returns nothing
set g_tbl = Table.create()
endfunction
endlibrary
library DummyRecycler /*
// DummyRecycler v1.25
// by Flux
//
// A system that recycles dummy units while considering their facing angle.
// It can be used as attachment dummies for visual effects or as dummy caster.
//
// Why is recycling a unit important?
// Because creating a unit is is one of the slowest function in the game
// and there are reports that will always leave a permanent tiny bit of
// memory (0.04 KB).
// On average, retrieving a pending Dummy is approximately 4x faster compared
// to creating a new one and recycling a Dummy compared to removing it is
// approximately 1.3x faster.
// Furthermore, if you're using a lot of "Unit has entered map" events,
// using this system will even result to even more better performance
// because retrieving Dummy units does not cause that event to run.
*/ requires /*
nothing
*/ optional Table/*
if not found, this system will use a hashtable. Hashtables are limited to
255 per map.
*/ optional WorldBounds /*
if not found, this system will initialize its own Map Boundaries.
//
//
// Features:
//
// -- Dummy Sharing
// When a Dummy List gets low on unit count, it will borrow Dummy Units
// from the Dummy List with the highest unit count. The transfer is not
// instant because the shared Dummy Unit has to turn to the appropriate
// angle of its new Dummy List before it can be recycled.
// See BORROW_REQUEST.
//
// -- Self-balancing recycling algorithm
// Recycled Dummy Units will be thrown to the List having the least number
// of Dummy Units.
//
// -- Recycling least used
// Allows recycling a Dummy from the Dummy List with the highest
// unit count. It is useful when the facing angle of the Dummy Unit
// does not matter.
// See GetRecycledDummyAnyAngle.
//
// -- Self-adaptation
// When there are no free Dummy Units from a Dummy List, it will end up creating
// a new unit instead but that unit will be permanently added as a Dummy
// Unit to be recycled increasing the overall total Dummy Unit count.
//
// -- Count control
// Allows limiting the overall number of Dummy Units.
// See MAX_DUMMY_COUNT.
//
// -- Delayed Recycle
// Allows recycling Dummy Units after some delay to allocate time for the
// death animation of Special Effects to be seen.
// See DummyAddRecycleTimer.
//
// ******************************************************************
// ***************************** API: *******************************
// ******************************************************************
//
// function GetRecycledDummy takes real x, real y, real z, real facing returns unit
// - Retrieve an unused Dummy Unit from the List.
// - The equivalent of CreateUnit.
// - To use as a Dummy Caster, follow it with PauseUnit(dummy, false).
//
// function GetRecycledDummyAnyAngle takes real x, real y, real z returns unit
// - Use this function if the facing angle of the Dummy doesn't matter to you.
// - It will return a unit from the list having the highest number of unused Dummy Units.
// - To use as a Dummy Caster, follow it with PauseUnit(dummy, false).
//
// function RecycleDummy takes unit u returns nothing
// - Recycle the Dummy unit for it to be used again later.
// - The equivalent of RemoveUnit.
//
// function DummyAddRecycleTimer takes unit u, real time returns nothing
// - Recycle the Dummy unit after a certain time.
// - Use this to allocate time for the the death animation of an effect attached to the
// Dummy Unit to finish..
// - The equivalent of UnitApplyTimedLife.
//
// function ShowDummy takes unit u, boolean flag returns nothing
// - Shows/hides Dummy Unit without conflicting with the Locust ability.
//
//--------------------
// CREDITS
//--------------------
// Bribe - for the MissileRecycler (vJASS) where I got this concept from
// http://www.hiveworkshop.com/forums/jass-resources-412/system-missilerecycler-206086/
// - for the optional Table
// http://www.hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/
// Vexorian - for the Attachable and Pitch Animation Model (dummy.mdx)
// http://www.wc3c.net/showthread.php?t=101150
// Maker and IcemanBo - for the unit permanent 0.04 KB memory leak of units.
// http://www.hiveworkshop.com/forums/trigger-gui-editor-tutorials-279/memory-leaks-263410/
// Nestharus - for the data structure
// http://www.hiveworkshop.com/forums/2809461-post7.html
// - for the optional WorldBounds
// http://githubusercontent.com/nestharus/JASS/master/jass/Systems/WorldBounds/script.j
// =============================================================== //
// ====================== CONFIGURATION ========================== //
// =============================================================== */
globals
//The rawcode of the Dummy Unit
private constant integer DUMMY_ID = 'dumi'
//The owner of the Dummy Unit
private constant player OWNER = Player(14)
//The number of indexed angle. The higher the value the:
// - Lesser the turning time for the Dummy Units.
// - Higher the total number of Dummy Units created at Map Initialization.
// Recommended Value: 10 (Max difference of 18 degrees)
private constant integer ANGLES_COUNT = 10
//The number of Dummy units per ANGLES_COUNT. The higher the value the:
// - Higher the number of units that can be recycled per angle, when
// no more units are in queue, the system will resort to use CreateUnit.
// - Higher the total number of Dummy Units created at Map Initialization.
// Recommended Value: 3 to 5 (for less overhead in Map Loading Screen)
private constant integer STORED_UNIT_COUNT = 3
//The maximum number of Dummy units that can exist. When the system resort
//to using CreateUnit, the unit will be permanently added to the Dummy
//List. To avoid spamming Dummy Units and having too much free Dummy
//Units to allocate, the maximum number of Dummy Units is capped.
// Recommended Value: 80 to 120
private constant integer MAX_DUMMY_COUNT = 100
//When a certain angle have less than BORROW_REQUEST units in its list,
//it will start to borrow Dummy Units from the list with the highest
//Dummy Unit count.
// Recommended Value: Half of maximum STORED_UNIT_COUNT
private constant integer BORROW_REQUEST = 5
//It will only return a Dummy if the current dummy is close
//to it's appropriate facing angle. This is to avoid returning
//a Dummy which is still turning to face it's list angle.
private constant real ANGLE_TOLERANCE = 10.0
//An additional option to automatically hide recycled dummy units in the
//corner of the map camera bounds
private constant boolean HIDE_ON_MAP_CORNER = true
endglobals
//Every time a new dummy unit is retrieved, it will apply this resets
//If it is redundant/you dont need it, remove it.
//! textmacro DUMMY_UNIT_RESET
call SetUnitScale(bj_lastCreatedUnit, 1, 0, 0)
call SetUnitVertexColor(bj_lastCreatedUnit, 255, 255, 255, 255)
call SetUnitAnimationByIndex(bj_lastCreatedUnit, 90)
call ShowDummy(bj_lastCreatedUnit, true)
//! endtextmacro
// =============================================================== //
// ==================== END CONFIGURATION ======================== //
// =============================================================== //
globals
private integer dummyCount = ANGLES_COUNT*STORED_UNIT_COUNT
private real array angle
private integer array count
private integer array countHead
private integer array countNext
private integer array countPrev
private integer array next
private integer array prev
private unit array dummy
private integer upper
private integer lower
private integer lastInstance
private constant real FACING_OFFSET = 180.0/ANGLES_COUNT
endglobals
static if HIDE_ON_MAP_CORNER and not LIBRARY_WorldBounds then
private module BoundsInit
readonly static real x
readonly static real y
private static method onInit takes nothing returns nothing
local rect map = GetWorldBounds()
set thistype.x = GetRectMaxX(map)
set thistype.y = GetRectMaxY(map)
call RemoveRect(map)
set map = null
endmethod
endmodule
private struct Bounds extends array
implement BoundsInit
endstruct
endif
private module M
static if LIBRARY_Table then
static Table tb
else
static hashtable hash = InitHashtable()
endif
private static method onInit takes nothing returns nothing
local real add = 360.0/ANGLES_COUNT
local real a = 0
local integer this = ANGLES_COUNT
local integer head = 0
local integer cHead = JASS_MAX_ARRAY_SIZE - 1 //avoid allocation collision
local integer i = R2I(MAX_DUMMY_COUNT/ANGLES_COUNT + 0.5)
set upper = STORED_UNIT_COUNT
set lower = STORED_UNIT_COUNT
static if LIBRARY_Table then
set tb = Table.create()
endif
//Initialize countHeads
loop
exitwhen i < 0
set countNext[cHead] = cHead
set countPrev[cHead] = cHead
set countHead[i] = cHead
set cHead = cHead - 1
set i = i - 1
endloop
set cHead = countHead[STORED_UNIT_COUNT] //All heads will be inserted here initially
//Create the Dummy units
loop
exitwhen a >= 360
//Initialize head
set next[head] = head
set prev[head] = head
set count[head] = STORED_UNIT_COUNT
set angle[head] = a
//Insert head in the Count List
set countNext[head] = cHead
set countPrev[head] = countPrev[cHead]
set countNext[countPrev[head]] = head
set countPrev[countNext[head]] = head
set i = 0
loop
exitwhen i >= STORED_UNIT_COUNT
//Queued Linked List
set next[this] = head
set prev[this] = prev[head]
set next[prev[this]] = this
set prev[next[this]] = this
static if HIDE_ON_MAP_CORNER then
static if LIBRARY_WorldBounds then
set dummy[this] = CreateUnit(OWNER, DUMMY_ID, WorldBounds.maxX, WorldBounds.maxY, a)
else
set dummy[this] = CreateUnit(OWNER, DUMMY_ID, Bounds.x, Bounds.y, a)
endif
else
set dummy[this] = CreateUnit(OWNER, DUMMY_ID, 0, 0, a)
endif
call PauseUnit(dummy[this], true)
static if LIBRARY_Table then
set tb[GetHandleId(dummy[this])] = this
else
call SaveInteger(hash, GetHandleId(dummy[this]), 0, this)
endif
set this = this + 1
set i = i + 1
endloop
set head = head + 1
set a = a + add
endloop
set lastInstance = this
endmethod
endmodule
private struct S extends array
implement M
endstruct
private function GetHead takes integer facing returns integer
if facing < 0 or facing >= 360 then
set facing = facing - (facing/360)*360
if facing < 0 then
set facing = facing + 360
endif
endif
return R2I((facing*ANGLES_COUNT/360.0))
endfunction
function ShowDummy takes unit u, boolean flag returns nothing
if IsUnitHidden(u) == flag then
call ShowUnit(u, flag)
if flag and GetUnitTypeId(u) == DUMMY_ID then
call UnitRemoveAbility(u, 'Aloc')
call UnitAddAbility(u, 'Aloc')
endif
endif
endfunction
function GetRecycledDummy takes real x, real y, real z, real facing returns unit
local integer head = GetHead(R2I(facing + FACING_OFFSET))
local integer this = next[head]
local integer cHead
//If there are Dummy Units in the Queue List already facing close to the appropriate angle
if this != head and RAbsBJ(GetUnitFacing(dummy[this]) - angle[head]) <= ANGLE_TOLERANCE then
//Remove from the Queue List
set next[prev[this]] = next[this]
set prev[next[this]] = prev[this]
//For double free protection
set next[this] = -1
//Unit Properties
set bj_lastCreatedUnit = dummy[this]
call SetUnitX(bj_lastCreatedUnit, x)
call SetUnitY(bj_lastCreatedUnit, y)
call SetUnitFacing(bj_lastCreatedUnit, facing)
call SetUnitFlyHeight(bj_lastCreatedUnit, z, 0)
//! runtextmacro DUMMY_UNIT_RESET()
//Update Count and Bounds
set count[head] = count[head] - 1
//------------------------------------------------
// Unit Sharing
//------------------------------------------------
if count[head] < BORROW_REQUEST and count[countNext[countHead[upper]]] > count[head] then
set count[head] = count[head] + 1
set this = next[countNext[countHead[upper]]]
call SetUnitFacing(dummy[this], angle[head])
//Remove
set next[prev[this]] = next[this]
set prev[next[this]] = prev[this]
//Add to the Current List
set next[this] = head
set prev[this] = prev[head]
set next[prev[this]] = this
set prev[next[this]] = this
set head = countNext[countHead[upper]]
set count[head] = count[head] - 1
endif
//---------------------------
//Update Count Lists
//---------------------------
//Remove from the current Count List
set countNext[countPrev[head]] = countNext[head]
set countPrev[countNext[head]] = countPrev[head]
//Add to the new Count List
set cHead = countHead[count[head]]
set countNext[head] = cHead
set countPrev[head] = countPrev[cHead]
set countNext[countPrev[head]] = head
set countPrev[countNext[head]] = head
//---------------------------
// Update Bounds
//---------------------------
set cHead = countHead[upper]
if countNext[cHead] == cHead then
set upper = upper - 1
endif
if count[head] < lower then
set lower = count[head]
endif
else
set bj_lastCreatedUnit = CreateUnit(OWNER, DUMMY_ID, x, y, facing)
call PauseUnit(bj_lastCreatedUnit, true)
call SetUnitFlyHeight(bj_lastCreatedUnit, z, 0)
if dummyCount < MAX_DUMMY_COUNT then
set this = lastInstance
//For double free protection
set next[this] = -1
set dummy[this] = bj_lastCreatedUnit
static if LIBRARY_Table then
set S.tb[GetHandleId(bj_lastCreatedUnit)] = this
else
call SaveInteger(S.hash, GetHandleId(bj_lastCreatedUnit), 0, this)
endif
set lastInstance = lastInstance + 1
endif
set dummyCount = dummyCount + 1
endif
return bj_lastCreatedUnit
endfunction
function RecycleDummy takes unit u returns nothing
static if LIBRARY_Table then
local integer this = S.tb[GetHandleId(u)]
else
local integer this = LoadInteger(S.hash, GetHandleId(u), 0)
endif
local integer head
local integer cHead
//If the unit is a legit Dummy Unit
if this > 0 and next[this] == -1 then
//Find where to insert based on the list having the least number of units
set head = countNext[countHead[lower]]
set next[this] = head
set prev[this] = prev[head]
set next[prev[this]] = this
set prev[next[this]] = this
//Update Status
call SetUnitFacing(u, angle[head])
call PauseUnit(u, true)
call SetUnitOwner(u, OWNER, false)
static if HIDE_ON_MAP_CORNER then
static if LIBRARY_WorldBounds then
call SetUnitX(u, WorldBounds.maxX)
call SetUnitY(u, WorldBounds.maxY)
else
call SetUnitX(u, Bounds.x)
call SetUnitY(u, Bounds.y)
endif
else
call SetUnitScale(u, 0, 0, 0)
call SetUnitVertexColor(u, 0, 0, 0, 0)
endif
set count[head] = count[head] + 1
//---------------------------
// Update Count Lists
//---------------------------
//Remove
set countNext[countPrev[head]] = countNext[head]
set countPrev[countNext[head]] = countPrev[head]
//Add to the new Count List
set cHead = countHead[count[head]]
set countNext[head] = cHead
set countPrev[head] = countPrev[cHead]
set countNext[countPrev[head]] = head
set countPrev[countNext[head]] = head
//---------------------------
// Update Bounds
//---------------------------
set cHead = countHead[lower]
if countNext[cHead] == cHead then
set lower = lower + 1
endif
if count[head] > upper then
set upper = count[head]
endif
elseif this == 0 then
call RemoveUnit(u)
debug elseif next[this] != -1 then
debug call BJDebugMsg("|cffffcc00[DummyRecycler]:|r Attempted to recycle a pending/free Dummy Unit.")
endif
endfunction
private function Expires takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer id = GetHandleId(t)
static if LIBRARY_Table then
call RecycleDummy(S.tb.unit[id])
call S.tb.unit.remove(id)
else
call RecycleDummy(LoadUnitHandle(S.hash, id, 0))
call FlushChildHashtable(S.hash, id)
endif
call DestroyTimer(t)
set t = null
endfunction
function DummyAddRecycleTimer takes unit u, real time returns nothing
local timer t = CreateTimer()
static if LIBRARY_Table then
set S.tb.unit[GetHandleId(t)] = u
else
call SaveUnitHandle(S.hash, GetHandleId(t), 0, u)
endif
call TimerStart(t, time, false, function Expires)
set t = null
endfunction
function GetRecycledDummyAnyAngle takes real x, real y, real z returns unit
return GetRecycledDummy(x, y, z, angle[countNext[countHead[upper]]])
endfunction
// runtextmacro DUMMY_DEBUG_TOOLS()
endlibrary
library TimerUtils initializer init
//*********************************************************************
//* TimerUtils (red+blue+orange flavors for 1.24b+) 2.0
//* ----------
//*
//* To implement it , create a custom text trigger called TimerUtils
//* and paste the contents of this script there.
//*
//* To copy from a map to another, copy the trigger holding this
//* library to your map.
//*
//* (requires vJass) More scripts: htt://www.wc3c.net
//*
//* For your timer needs:
//* * Attaching
//* * Recycling (with double-free protection)
//*
//* set t=NewTimer() : Get a timer (alternative to CreateTimer)
//* set t=NewTimerEx(x) : Get a timer (alternative to CreateTimer), call
//* Initialize timer data as x, instead of 0.
//*
//* ReleaseTimer(t) : Relese a timer (alt to DestroyTimer)
//* SetTimerData(t,2) : Attach value 2 to timer
//* GetTimerData(t) : Get the timer's value.
//* You can assume a timer's value is 0
//* after NewTimer.
//*
//* Multi-flavor:
//* Set USE_HASH_TABLE to true if you don't want to complicate your life.
//*
//* If you like speed and giberish try learning about the other flavors.
//*
//********************************************************************
//================================================================
globals
//How to tweak timer utils:
// USE_HASH_TABLE = true (new blue)
// * SAFEST
// * SLOWEST (though hash tables are kind of fast)
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = true (orange)
// * kinda safe (except there is a limit in the number of timers)
// * ALMOST FAST
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = false (red)
// * THE FASTEST (though is only faster than the previous method
// after using the optimizer on the map)
// * THE LEAST SAFE ( you may have to tweak OFSSET manually for it to
// work)
//
private constant boolean USE_HASH_TABLE = true
private constant boolean USE_FLEXIBLE_OFFSET = false
private constant integer OFFSET = 0x100000
private integer VOFFSET = OFFSET
//Timers to preload at map init:
private constant integer QUANTITY = 256
//Changing this to something big will allow you to keep recycling
// timers even when there are already AN INCREDIBLE AMOUNT of timers in
// the stack. But it will make things far slower so that's probably a bad idea...
private constant integer ARRAY_SIZE = 8190
endglobals
//==================================================================================================
globals
private integer array data[ARRAY_SIZE]
private hashtable ht
endglobals
//It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
function SetTimerData takes timer t, integer value returns nothing
static if(USE_HASH_TABLE) then
// new blue
call SaveInteger(ht,0,GetHandleId(t), value)
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-VOFFSET]=value
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-OFFSET]=value
endif
endfunction
function GetTimerData takes timer t returns integer
static if(USE_HASH_TABLE) then
// new blue
return LoadInteger(ht,0,GetHandleId(t) )
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-VOFFSET]
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-OFFSET]
endif
endfunction
//==========================================================================================
globals
private timer array tT[ARRAY_SIZE]
private integer tN = 0
private constant integer HELD=0x28829022
//use a totally random number here, the more improbable someone uses it, the better.
private boolean didinit = false
endglobals
private keyword init
//==========================================================================================
// I needed to decide between duplicating code ignoring the "Once and only once" rule
// and using the ugly textmacros. I guess textmacros won.
//
//! textmacro TIMERUTIS_PRIVATE_NewTimerCommon takes VALUE
// On second thought, no.
//! endtextmacro
function NewTimerEx takes integer value returns timer
if (tN==0) then
if (not didinit) then
//This extra if shouldn't represent a major performance drawback
//because QUANTITY rule is not supposed to be broken every day.
call init.evaluate()
set tN = tN - 1
else
//If this happens then the QUANTITY rule has already been broken, try to fix the
// issue, else fail.
debug call BJDebugMsg("NewTimer: Warning, Exceeding TimerUtils_QUANTITY, make sure all timers are getting recycled correctly")
set tT[0]=CreateTimer()
static if( not USE_HASH_TABLE) then
debug call BJDebugMsg("In case of errors, please increase it accordingly, or set TimerUtils_USE_HASH_TABLE to true")
static if( USE_FLEXIBLE_OFFSET) then
if (GetHandleId(tT[0])-VOFFSET<0) or (GetHandleId(tT[0])-VOFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
else
if (GetHandleId(tT[0])-OFFSET<0) or (GetHandleId(tT[0])-OFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
endif
endif
endif
else
set tN=tN-1
endif
call SetTimerData(tT[tN],value)
return tT[tN]
endfunction
function NewTimer takes nothing returns timer
return NewTimerEx(0)
endfunction
//==========================================================================================
function ReleaseTimer takes timer t returns nothing
if(t==null) then
debug call BJDebugMsg("Warning: attempt to release a null timer")
return
endif
if (tN==ARRAY_SIZE) then
debug call BJDebugMsg("Warning: Timer stack is full, destroying timer!!")
//stack is full, the map already has much more troubles than the chance of bug
call DestroyTimer(t)
else
call PauseTimer(t)
if(GetTimerData(t)==HELD) then
debug call BJDebugMsg("Warning: ReleaseTimer: Double free!")
return
endif
call SetTimerData(t,HELD)
set tT[tN]=t
set tN=tN+1
endif
endfunction
private function init takes nothing returns nothing
local integer i=0
local integer o=-1
local boolean oops = false
if ( didinit ) then
return
else
set didinit = true
endif
static if( USE_HASH_TABLE ) then
set ht = InitHashtable()
loop
exitwhen(i==QUANTITY)
set tT[i]=CreateTimer()
call SetTimerData(tT[i], HELD)
set i=i+1
endloop
set tN = QUANTITY
else
loop
set i=0
loop
exitwhen (i==QUANTITY)
set tT[i] = CreateTimer()
if(i==0) then
set VOFFSET = GetHandleId(tT[i])
static if(USE_FLEXIBLE_OFFSET) then
set o=VOFFSET
else
set o=OFFSET
endif
endif
if (GetHandleId(tT[i])-o>=ARRAY_SIZE) then
exitwhen true
endif
if (GetHandleId(tT[i])-o>=0) then
set i=i+1
endif
endloop
set tN = i
exitwhen(tN == QUANTITY)
set oops = true
exitwhen not USE_FLEXIBLE_OFFSET
debug call BJDebugMsg("TimerUtils_init: Failed a initialization attempt, will try again")
endloop
if(oops) then
static if ( USE_FLEXIBLE_OFFSET) then
debug call BJDebugMsg("The problem has been fixed.")
//If this message doesn't appear then there is so much
//handle id fragmentation that it was impossible to preload
//so many timers and the thread crashed! Therefore this
//debug message is useful.
elseif(DEBUG_MODE) then
call BJDebugMsg("There were problems and the new timer limit is "+I2S(i))
call BJDebugMsg("This is a rare ocurrence, if the timer limit is too low:")
call BJDebugMsg("a) Change USE_FLEXIBLE_OFFSET to true (reduces performance a little)")
call BJDebugMsg("b) or try changing OFFSET to "+I2S(VOFFSET) )
endif
endif
endif
endfunction
endlibrary
library GetDummy requires DummyRecycler
globals
private unit u = null
endglobals
function GetDummy takes player owner, integer abil, integer spell_lvl, real x, real y returns unit
set u = GetRecycledDummyAnyAngle(x, y, 0.)
call PauseUnit(u, false)
call SetUnitOwner(u, owner, false)
call UnitAddAbility(u, abil)
call SetUnitAbilityLevel(u, abil, spell_lvl)
return u
endfunction
function GetDummyLoc takes player owner, integer abil, integer spell_lvl, location loc returns unit
set u = GetRecycledDummyAnyAngle(GetLocationX(loc), GetLocationY(loc), 0.)
call PauseUnit(u, false)
call SetUnitOwner(u, owner, false)
call UnitAddAbility(u, abil)
call SetUnitAbilityLevel(u, abil, spell_lvl)
return u
endfunction
endlibrary
library UnitRemoveAbilityTimed requires TimerUtils, DummyRecycler
//! novjass
-------- API --------
call UnitRemoveAbilityTimed.create(unit Your Unit, integer Ability ID, real Timeout, boolean Recycle Unit)
/*
If you want to recycle the unit right after the ability is removed, set the boolean
(the final argument) to true
*/
//! endnovjass
struct UnitRemoveAbilityTimed
unit u
integer abil
boolean recycle
private method destroy takes nothing returns nothing
call this.deallocate()
set this.u = null
set this.abil = 0
set this.recycle = false
endmethod
private static method removeAbil takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = GetTimerData(t)
call UnitRemoveAbility(this.u, this.abil)
if this.recycle then
call RecycleDummy(this.u)
endif
call this.destroy()
call ReleaseTimer(t)
set t = null
endmethod
static method create takes unit source, integer abil_code, real timeout, boolean recycle_source returns UnitRemoveAbilityTimed
local thistype this = allocate()
local timer t = NewTimerEx(this)
set this.u = source
set this.abil = abil_code
set this.recycle = recycle_source
call TimerStart(t, timeout, false, function thistype.removeAbil)
set t = null
return this
endmethod
endstruct
endlibrary
/*
To automatically create a Dummy Unit in Object Editor, enable this trigger (Dummy Object Merger)
and configure it if you want.
Then save the map, it should take time in "Executing external commands"
Close the map, then re-open it. You should be able to see "Dummy (General Purpose)" in Object Editor.
After that, delete/disable this trigger (Dummy Object Merger).
*/
//! externalblock extension=lua ObjectMerger $FILENAME$
//Configuration
//! i local dummyRawcode = "dumi"
//! i local dummyModel = "war3mapImported\\dummy.mdl"
//End Configuration
//Create new units
//! i setobjecttype("units")
//! i createobject("ewsp",dummyRawcode)
//! i makechange(current,"uabi","Aloc,Arav")
//! i makechange(current,"ucbs","0.0")
//! i makechange(current,"ushr","0")
//! i makechange(current,"uico","ReplaceableTextures\\CommandButtons\\BTNSelectHeroOn.blp")
//! i makechange(current,"umxp","0.0")
//! i makechange(current,"umxr","0.0")
//! i makechange(current,"umdl",dummyModel)
//! i makechange(current,"uspa","")
//! i makechange(current,"umvr","3")
//! i makechange(current,"umvt","")
//! i makechange(current,"ufoo","0")
//! i makechange(current,"urac","creeps")
//! i makechange(current,"usid","0")
//! i makechange(current,"usin","0")
//! i makechange(current,"utyp","")
//! i makechange(current,"ubui","")
//! i makechange(current,"upgr","")
//! i makechange(current,"unam","Dummy")
//! i makechange(current,"unsf"," (General Purpose)")
//! endexternalblock
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
library WorldBounds /* v2.0.0.0
************************************************************************************
*
* struct WorldBounds extends array
*
* Fields
* -------------------------
*
* readonly static integer maxX
* readonly static integer maxY
* readonly static integer minX
* readonly static integer minY
*
* readonly static integer centerX
* readonly static integer centerY
*
* readonly static rect world
* readonly static region worldRegion
*
************************************************************************************/
private module WorldBoundInit
private static method onInit takes nothing returns nothing
set world = GetWorldBounds()
set maxX = R2I(GetRectMaxX(world))
set maxY = R2I(GetRectMaxY(world))
set minX = R2I(GetRectMinX(world))
set minY = R2I(GetRectMinY(world))
set centerX = R2I((maxX + minX)/2)
set centerY = R2I((minY + maxY)/2)
set playMaxX = GetRectMaxX(bj_mapInitialPlayableArea)
set playMaxY = GetRectMaxY(bj_mapInitialPlayableArea)
set playMinX = GetRectMinX(bj_mapInitialPlayableArea)
set playMinY = GetRectMinY(bj_mapInitialPlayableArea)
set worldRegion = CreateRegion()
call RegionAddRect(worldRegion, world)
endmethod
endmodule
struct WorldBounds extends array
readonly static integer maxX
readonly static integer maxY
readonly static integer minX
readonly static integer minY
readonly static integer centerX
readonly static integer centerY
readonly static rect world
readonly static region worldRegion
readonly static real playMaxX
readonly static real playMaxY
readonly static real playMinX
readonly static real playMinY
implement WorldBoundInit
endstruct
endlibrary
//TESH.scrollpos=3
//TESH.alwaysfold=0
library BuffAbilityLink initializer init
globals
private constant real TICK = 0.50 // How ofter the system checks for buff-ability links
private group all = CreateGroup ( )
private rect map = null
private balink array Links
private integer LinkN = 0
endglobals
struct balink
integer buffId = 0
integer abilId = 0
static method create takes integer buffId, integer abilId returns thistype
local thistype this = thistype.allocate ( )
set this.buffId = buffId
set this.abilId = abilId
set Links [ LinkN ] = this
set LinkN = LinkN + 1
return this
endmethod
endstruct
private function Enumeration takes nothing returns boolean
local integer i = LinkN
local unit u = GetFilterUnit ( )
loop
set i = i - 1
exitwhen i < 0
if GetUnitAbilityLevel ( u, Links [ i ].buffId ) > 0 then
call UnitAddAbility ( u, Links [ i ].abilId )
else
call UnitRemoveAbility ( u, Links [ i ].abilId )
endif
endloop
set u = null
return false
endfunction
private function Iteration takes nothing returns nothing
call GroupEnumUnitsInRect ( all, map, Filter ( function Enumeration ) )
endfunction
private function init takes nothing returns nothing
set map = GetWorldBounds ( )
call TimerStart ( CreateTimer ( ), TICK, true, function Iteration )
endfunction
endlibrary
//===========================================================================
//
// Damage Engine 5.7.1.2 - update requires replacing the JASS script.
//
/*
Three GUI Damage systems for the community of The Hive,
Seven vJass Damage systems for the JASS-heads on their pedestals high,
Nine competing Damage systems, doomed to die,
One for Bribe on his dark throne
In the Land of the Hive where the Workshop lies.
One Damage Engine to rule them all, One Damage Engine to find them,
One Damage Engine to bring them all and in cross-compatibility unite them.
*/
//! novjass
JASS API (work in progress - I have a lot of documentation to go through):
struct Damage extends array
readonly static unit source //stores udg_DamageEventSource
readonly static unit target //stores udg_DamageEventTarget
static real amount //stores udg_DamageEventAmount
readonly unit sourceUnit //stores udg_DamageEventSource by index
readonly unit targetUnit //stores udg_DamageEventTarget by index
real damage //stores udg_DamageEventAmount by index
readonly real prevAmt //stores udg_DamageEventPrevAmt by index
attacktype attackType //stores udg_DamageEventAttackT by index
damagetype damageType //stores udg_DamageEventDamageT by index
weapontype weaponType //stores udg_DamageEventWeaponT by index
integer userType //stores udg_DamageEventType by index
readonly integer eFilter //replaces the previous eventFilter variable
readonly boolean isAttack //stores udg_IsDamageAttack by index
readonly boolean isCode //stores udg_IsDamageCode by index
readonly boolean isMelee //stores udg_IsDamageMelee by index
readonly boolean isRanged //stores udg_IsDamageRanged by index
readonly boolean isSpell //stores udg_IsDamageSpell by index
real armorPierced //stores udg_DamageEventArmorPierced by index
integer armorType //stores udg_DamageEventArmorT by index
integer defenseType //stores udg_DamageEventDefenseT by index
static boolean operator enabled
- Set to false to disable the damage event triggers/false to reverse that
static method apply takes unit src, unit tgt, real amt, boolean a, boolean r, attacktype at, damagetype dt, weapontype wt returns Damage
- Same arguments as "UnitDamageTarget" but has the benefit of being performance-friendly during recursive events.
- Will automatically cause the damage to be registered as Code damage.
static method applySpell takes unit src, unit tgt, real amt, damagetype dt returns Damage
- A simplified version of the above function that autofills in the booleans, attack type and weapon type.
static method applyAttack takes unit src, unit tgt, real amt, boolean ranged, attacktype at, weapontype wt returns Damage
- A different variation of the above which autofills the "attack" boolean and sets the damagetype to DAMAGE_TYPE_NORMAL.
struct DamageTrigger extends array
method operator filter= takes integer filter returns nothing
// Apply primary filters such as DamageEngine_FILTER_MELEE/RANGED/SPELL which are based off of limitop handles to enable easier access for GUI folks
// Full filter list:
- global integer DamageEngine_FILTER_ATTACK
- global integer DamageEngine_FILTER_MELEE
- global integer DamageEngine_FILTER_OTHER
- global integer DamageEngine_FILTER_RANGED
- global integer DamageEngine_FILTER_SPELL
- global integer DamageEngine_FILTER_CODE
boolean configured //set to True after configuring any filters listed below.
method configure takes nothing returns nothing
// Apply custom filters after setting any desired udg_DamageFilter variables (for GUI).
// Alternatively, vJass users can set these instead. Just be mindful to set the variable
// "configured" to true after settings these.
unit source
unit target
integer sourceType
integer targetType
integer sourceBuff
integer targetBuff
real damageMin
integer attackType
integer damageType
integer userType
//The string in the aruments below requires the following API:
// "" for standard damage event
// "Modifier(or Mod if you prefer)/After/Lethal/AOE" for the others
static method getIndex takes trigger t, string eventName, real value returns integer
static method registerTrigger takes trigger whichTrig, string var, real weight returns nothing
static method unregister takes trigger t, string eventName, real value, boolean reset returns boolean
static method operator [] takes code c returns trigger
// Converts a code argument to a trigger, while checking if the same code had already been registered before.
//The accepted strings here use the same criteria as DamageTrigger.getIndex/registerTrigger/unregister
function TriggerRegisterDamageEngineEx takes trigger whichTrig, string eventName, real value, integer f returns nothing
function TriggerRegisterDamageEngine takes trigger whichTrig, string eventName, real value returns nothing
function RegisterDamageEngineEx takes code c, string eventName, real value, integer f returns nothing
function RegisterDamageEngine takes code c, string eventName, real value returns nothing
//! endnovjass
//===========================================================================
library DamageEngine
globals
private constant boolean USE_GUI = true //If you don't use any of the GUI events, set to false to slightly improve performance
private constant boolean USE_SCALING = USE_GUI //If you don't need or want to use DamageScalingUser/WC3 then set this to false
private constant boolean USE_EXTRA = true //If you don't use DamageEventLevel or AOEDamageEvent, set this to false
private constant boolean USE_ARMOR_MOD = true //If you do not modify nor detect armor/defense, set this to false
private constant boolean USE_MELEE_RANGE= true //If you do not detect melee nor ranged damage, set this to false
private constant boolean USE_LETHAL = true //If you do not use LethalDamageEvent nor negative damage (explosive) types, set this to false
private constant integer LIMBO = 16 //When manually-enabled recursion is enabled via DamageEngine_recurion, the engine will never go deeper than LIMBO.
public constant integer TYPE_CODE = 1 //Must be the same as udg_DamageTypeCode, or 0 if you prefer to disable the automatic flag.
public constant integer TYPE_PURE = 2 //Must be the same as udg_DamageTypePure
private constant real DEATH_VAL = 0.405 //In case Blizz ever changes this, it'll be a quick fix here.
private timer alarm = CreateTimer()
private boolean alarmSet = false
//Values to track the original pre-spirit Link/defensive damage values
private Damage lastInstance = 0
private boolean canKick = true
private boolean totem = false
private boolean array attacksImmune
private boolean array damagesImmune
//Made global in order to use enable/disable behavior.
private trigger t1 = CreateTrigger()
private trigger t2 = CreateTrigger()
private trigger t3 = CreateTrigger() //Catches, stores recursive events
//These variables coincide with Blizzard's "limitop" type definitions so as to enable users (GUI in particular) with some nice performance perks.
public constant integer FILTER_ATTACK = 0 //LESS_THAN
public constant integer FILTER_MELEE = 1 //LESS_THAN_OR_EQUAL
public constant integer FILTER_OTHER = 2 //EQUAL
public constant integer FILTER_RANGED = 3 //GREATER_THAN_OR_EQUAL
public constant integer FILTER_SPELL = 4 //GREATER_THAN
public constant integer FILTER_CODE = 5 //NOT_EQUAL
public constant integer FILTER_MAX = 6
private integer eventFilter = FILTER_OTHER
public boolean inception = false //When true, it allows your trigger to potentially go recursive up to LIMBO. However it must be set per-trigger throughout the game and not only once per trigger during map initialization.
private boolean dreaming = false
private integer sleepLevel = 0
private group proclusGlobal = CreateGroup() //track sources of recursion
private group fischerMorrow = CreateGroup() //track targets of recursion
private boolean kicking = false
private boolean eventsRun = false
private keyword run
private keyword trigFrozen
private keyword levelsDeep
private keyword inceptionTrig
private boolean hasLethal = false
endglobals
native UnitAlive takes unit u returns boolean
//GUI Vars:
/*
Retained from 3.8 and prior:
----------------------------
unit udg_DamageEventSource
unit udg_DamageEventTarget
unit udg_EnhancedDamageTarget
group udg_DamageEventAOEGroup
integer udg_DamageEventAOE
integer udg_DamageEventLevel
real udg_DamageModifierEvent
real udg_DamageEvent
real udg_AfterDamageEvent
real udg_DamageEventAmount
real udg_DamageEventPrevAmt
real udg_AOEDamageEvent
boolean udg_DamageEventOverride
boolean udg_NextDamageType
boolean udg_DamageEventType
boolean udg_IsDamageSpell
//Added in 5.0:
boolean udg_IsDamageMelee
boolean udg_IsDamageRanged
unit udg_AOEDamageSource
real udg_LethalDamageEvent
real udg_LethalDamageHP
real udg_DamageScalingWC3
integer udg_DamageEventAttackT
integer udg_DamageEventDamageT
integer udg_DamageEventWeaponT
//Added in 5.1:
boolean udg_IsDamageCode
//Added in 5.2:
integer udg_DamageEventArmorT
integer udg_DamageEventDefenseT
//Addded in 5.3:
real DamageEventArmorPierced
real udg_DamageScalingUser
//Added in 5.4.2 to allow GUI users to re-issue the exact same attack and damage type at the attacker.
attacktype array udg_CONVERTED_ATTACK_TYPE
damagetype array udg_CONVERTED_DAMAGE_TYPE
//Added after Reforged introduced the new native BlzGetDamageIsAttack
boolean udg_IsDamageAttack
//Added in 5.6 to give GUI users control over the "IsDamageAttack", "IsDamageRanged" and "DamageEventWeaponT" field
boolean udg_NextDamageIsAttack //The first boolean value in the UnitDamageTarget native
boolean udg_NextDamageIsMelee //Flag the damage classification as melee
boolean udg_NextDamageIsRanged //The second boolean value in the UnitDamageTarget native
integer udg_NextDamageWeaponT //Allows control over damage sound effect
//Added in 5.7 to enable efficient, built-in filtering (see the below "checkConfiguration" method - I recommend commenting-out anything you don't need in your map)
integer udg_DamageFilterAttackT
integer udg_DamageFilterDamageT //filter for a specific attack/damage type
unit udg_DamageFilterSource
unit udg_DamageFilterTarget //filter for a specific source/target
integer udg_DamageFilterSourceT
integer udg_DamageFilterTargetT //unit type of source/target
integer udg_DamageFilterType //which DamageEventType was used
integer udg_DamageFilterSourceB
integer udg_DamageFilterTargetB //if source/target has a buff
real udg_DamageFilterMinAmount //only allow a minimum damage threshold
*/
struct DamageTrigger extends array
//Map-makers should comment-out any booleans they will never need to check for.
method checkConfiguration takes nothing returns boolean
if this.userType != 0 and udg_DamageEventType != this.userType then
elseif this.source != null and this.source != udg_DamageEventSource then
elseif this.target != null and this.target != udg_DamageEventTarget then
elseif this.attackType >= 0 and this.attackType != udg_DamageEventAttackT then
elseif this.damageType >= 0 and this.damageType != udg_DamageEventDamageT then
elseif this.sourceType != 0 and GetUnitTypeId(udg_DamageEventSource) != this.sourceType then
elseif this.targetType != 0 and GetUnitTypeId(udg_DamageEventTarget) != this.targetType then
elseif this.sourceBuff != 0 and GetUnitAbilityLevel(udg_DamageEventSource, this.sourceBuff) == 0 then
elseif this.targetBuff != 0 and GetUnitAbilityLevel(udg_DamageEventTarget, this.targetBuff) == 0 then
elseif udg_DamageEventAmount > this.damageMin then
return true
endif
return false
endmethod
//The below variables are constant
readonly static thistype MOD = 1
readonly static thistype SHIELD = 4
readonly static thistype DAMAGE = 5
readonly static thistype ZERO = 6
readonly static thistype AFTER = 7
readonly static thistype LETHAL = 8
readonly static thistype AOE = 9
private static integer count = 9
static thistype lastRegistered = 0
private static thistype array trigIndexStack
static thistype eventIndex = 0
static boolean array filters
readonly string eventStr
readonly real weight
boolean configured
boolean usingGUI
//The below variables are private
private thistype next
private trigger rootTrig
boolean trigFrozen //Whether the trigger is currently disabled due to recursion
integer levelsDeep //How deep the user recursion currently is.
boolean inceptionTrig //Added in 5.4.2 to simplify the inception variable for very complex DamageEvent trigger.
unit source
unit target
integer sourceType
integer targetType
integer sourceBuff
integer targetBuff
real damageMin
integer attackType
integer damageType
integer userType
method configure takes nothing returns nothing
set this.attackType = udg_DamageFilterAttackT
set this.damageType = udg_DamageFilterDamageT
set this.source = udg_DamageFilterSource
set this.target = udg_DamageFilterTarget
set this.sourceType = udg_DamageFilterSourceT
set this.targetType = udg_DamageFilterTargetT
set this.sourceBuff = udg_DamageFilterSourceB
set this.targetBuff = udg_DamageFilterTargetB
set this.userType = udg_DamageFilterType
set this.damageMin = udg_DamageFilterMinAmount
set udg_DamageFilterAttackT =-1
set udg_DamageFilterDamageT =-1
set udg_DamageFilterSource = null
set udg_DamageFilterTarget = null
set udg_DamageFilterSourceT = 0
set udg_DamageFilterTargetT = 0
set udg_DamageFilterType = 0
set udg_DamageFilterSourceB = 0
set udg_DamageFilterTargetB = 0
set udg_DamageFilterMinAmount=0.00
set this.configured = true
endmethod
static method setGUIFromStruct takes boolean full returns nothing
set udg_DamageEventAmount = Damage.index.damage
set udg_DamageEventAttackT = GetHandleId(Damage.index.attackType)
set udg_DamageEventDamageT = GetHandleId(Damage.index.damageType)
set udg_DamageEventWeaponT = GetHandleId(Damage.index.weaponType)
set udg_DamageEventType = Damage.index.userType
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_DamageEventArmorPierced = Damage.index.armorPierced
set udg_DamageEventArmorT = Damage.index.armorType
set udg_DamageEventDefenseT = Damage.index.defenseType
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if full then
set udg_DamageEventSource = Damage.index.sourceUnit
set udg_DamageEventTarget = Damage.index.targetUnit
set udg_DamageEventPrevAmt = Damage.index.prevAmt
set udg_IsDamageAttack = Damage.index.isAttack
set udg_IsDamageCode = Damage.index.isCode
set udg_IsDamageSpell = Damage.index.isSpell
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_IsDamageMelee = Damage.index.isMelee
set udg_IsDamageRanged = Damage.index.isRanged
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endif
endmethod
static method setStructFromGUI takes nothing returns nothing
set Damage.index.damage = udg_DamageEventAmount
set Damage.index.attackType = ConvertAttackType(udg_DamageEventAttackT)
set Damage.index.damageType = ConvertDamageType(udg_DamageEventDamageT)
set Damage.index.weaponType = ConvertWeaponType(udg_DamageEventWeaponT)
set Damage.index.userType = udg_DamageEventType
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set Damage.index.armorPierced = udg_DamageEventArmorPierced
set Damage.index.armorType = udg_DamageEventArmorT
set Damage.index.defenseType = udg_DamageEventDefenseT
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endmethod
static method getVerboseStr takes string eventName returns string
if eventName == "Modifier" or eventName == "Mod" then
return "udg_DamageModifierEvent"
endif
return "udg_" + eventName + "DamageEvent"
endmethod
private static method getStrIndex takes string var, real lbs returns thistype
local integer root = R2I(lbs)
if var == "udg_DamageModifierEvent" then
if root >= 4 then
set root= SHIELD //4.00 or higher
else
set root= MOD //Less than 4.00
endif
elseif var == "udg_DamageEvent" then
if root == 2 or root == 0 then
set root= ZERO
else
set root= DAMAGE //Above 0.00 but less than 2.00, generally would just be 1.00
endif
elseif var == "udg_AfterDamageEvent" then
set root = AFTER
elseif var == "udg_LethalDamageEvent" then
set root = LETHAL
elseif var == "udg_AOEDamageEvent" then
set root = AOE
else
set root = 0
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_GDD()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_PDD()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_05()
endif
return root
endmethod
private method toggleAllFilters takes boolean flag returns nothing
set filters[this + FILTER_ATTACK] = flag
set filters[this + FILTER_MELEE] = flag
set filters[this + FILTER_OTHER] = flag
set filters[this + FILTER_RANGED] = flag
set filters[this + FILTER_SPELL] = flag
set filters[this + FILTER_CODE] = flag
endmethod
method operator filter= takes integer f returns nothing
set this = this*FILTER_MAX
if f == FILTER_OTHER then
call this.toggleAllFilters(true)
else
if f == FILTER_ATTACK then
set filters[this + FILTER_ATTACK] = true
set filters[this + FILTER_MELEE] = true
set filters[this + FILTER_RANGED] = true
else
set filters[this + f] = true
endif
endif
endmethod
static method registerVerbose takes trigger whichTrig, string var, real lbs, boolean GUI, integer filt returns thistype
local thistype index= getStrIndex(var, lbs)
local thistype i = 0
local thistype id = 0
if index == 0 then
return 0
elseif lastRegistered.rootTrig == whichTrig and lastRegistered.usingGUI then
set filters[lastRegistered*FILTER_MAX + filt] = true //allows GUI to register multiple different types of Damage filters to the same trigger
return 0
endif
if not hasLethal and index == LETHAL then
set hasLethal = true
endif
if trigIndexStack[0] == 0 then
set count = count + 1 //List runs from index 10 and up
set id = count
else
set id = trigIndexStack[0]
set trigIndexStack[0] = trigIndexStack[id]
endif
set lastRegistered = id
set id.filter = filt
set id.rootTrig = whichTrig
set id.usingGUI = GUI
set id.weight = lbs
set id.eventStr = var
//Next 2 lines added to fix a bug when using manual vJass configuration,
//discovered and solved by lolreported
set id.attackType = -1
set id.damageType = -1
loop
set i = index.next
exitwhen i == 0 or lbs < i.weight
set index = i
endloop
set index.next = id
set id.next = i
//call BJDebugMsg("Registered " + I2S(id) + " to " + I2S(index) + " and before " + I2S(i))
return lastRegistered
endmethod
static method registerTrigger takes trigger t, string var, real lbs returns thistype
return registerVerbose(t, DamageTrigger.getVerboseStr(var), lbs, false, FILTER_OTHER)
endmethod
private static thistype prev = 0
static method getIndex takes trigger t, string eventName, real lbs returns thistype
local thistype index = getStrIndex(getVerboseStr(eventName), lbs)
loop
set prev = index
set index = index.next
exitwhen index == 0 or index.rootTrig == t
endloop
return index
endmethod
static method unregister takes trigger t, string eventName, real lbs, boolean reset returns boolean
local thistype index = getIndex(t, eventName, lbs)
if index == 0 then
return false
endif
set prev.next = index.next
set trigIndexStack[index] = trigIndexStack[0]
set trigIndexStack[0] = index
if reset then
call index.configure()
set index.configured = false
set index = index*FILTER_MAX
call index.toggleAllFilters(false)
endif
return true
endmethod
method run takes nothing returns nothing
local integer cat = this
local Damage d = Damage.index
static if USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
local boolean structUnset = false
local boolean guiUnset = false
local boolean mod = cat <= DAMAGE
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if dreaming then
return
endif
set dreaming = true
call DisableTrigger(t1)
call DisableTrigger(t2)
call EnableTrigger(t3)
//call BJDebugMsg("Start of event running")
loop
set this = this.next
exitwhen this == 0
exitwhen cat == MOD and (udg_DamageEventOverride or udg_DamageEventType == TYPE_PURE)
exitwhen cat == SHIELD and udg_DamageEventAmount <= 0.00
static if USE_LETHAL then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
exitwhen cat == LETHAL and udg_LethalDamageHP > DEATH_VAL
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set eventIndex = this
if not this.trigFrozen and filters[this*FILTER_MAX + d.eFilter] and IsTriggerEnabled(this.rootTrig) and (not this.configured or this.checkConfiguration()) then
static if USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if mod then
if this.usingGUI then
if guiUnset then
set guiUnset = false
call setGUIFromStruct(false)
endif
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_PDD()
elseif structUnset then
set structUnset = false
call setStructFromGUI()
endif
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_05()
//JASS users who do not use actions can modify the below block to just evaluate.
//It should not make any perceptable difference in terms of performance.
if TriggerEvaluate(this.rootTrig) then
call TriggerExecute(this.rootTrig)
endif
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_05()
static if USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if mod then
if this.usingGUI then
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_PDD()
if cat != MOD then
set d.damage = udg_DamageEventAmount
else
set structUnset = true
endif
elseif cat != MOD then
set udg_DamageEventAmount = d.damage
else
set guiUnset = true
endif
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endif
endloop
static if USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if structUnset then
call setStructFromGUI()
endif
if guiUnset then
call setGUIFromStruct(false)
endif
else// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call setGUIFromStruct(false)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
//call BJDebugMsg("End of event running")
call DisableTrigger(t3)
call EnableTrigger(t1)
call EnableTrigger(t2)
set dreaming = false
endmethod
static trigger array autoTriggers
static boolexpr array autoFuncs
static integer autoN = 0
static method operator [] takes code c returns trigger
local integer i = 0
local boolexpr b = Filter(c)
loop
if i == autoN then
set autoTriggers[i] = CreateTrigger()
set autoFuncs[i] = b
call TriggerAddCondition(autoTriggers[i], b)
exitwhen true
endif
set i = i + 1
exitwhen b == autoFuncs[i]
endloop
return autoTriggers[i]
endmethod
endstruct
//! runtextmacro optional DAMAGE_EVENT_USER_STRUCT_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_USER_STRUCT_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_USER_STRUCT_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_USER_STRUCT_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_USER_STRUCT_PLUGIN_05()
struct Damage extends array
readonly unit sourceUnit //stores udg_DamageEventSource
readonly unit targetUnit //stores udg_DamageEventTarget
real damage //stores udg_DamageEventAmount
readonly real prevAmt //stores udg_DamageEventPrevAmt
attacktype attackType //stores udg_DamageEventAttackT
damagetype damageType //stores udg_DamageEventDamageT
weapontype weaponType //stores udg_DamageEventWeaponT
integer userType //stores udg_DamageEventType
readonly boolean isAttack //stores udg_IsDamageAttack
readonly boolean isCode //stores udg_IsDamageCode
readonly boolean isSpell //stores udg_IsDamageSpell
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
readonly boolean isMelee //stores udg_IsDamageMelee
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
readonly boolean isRanged //stores udg_IsDamageRanged
readonly integer eFilter //stores the previous eventFilter variable
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
real armorPierced //stores udg_DamageEventArmorPierced
integer armorType //stores udg_DamageEventArmorT
integer defenseType //stores udg_DamageEventDefenseT
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
readonly static Damage index = 0
private static Damage damageStack = 0
private static Damage prepped = 0
private static integer count = 0 //The number of currently-running queued or sequential damage instances
private Damage stackRef
private DamageTrigger recursiveTrig
private integer prevArmorT
private integer prevDefenseT
static method operator source takes nothing returns unit
return udg_DamageEventSource
endmethod
static method operator target takes nothing returns unit
return udg_DamageEventTarget
endmethod
static method operator amount takes nothing returns real
return Damage.index.damage
endmethod
static method operator amount= takes real r returns nothing
set Damage.index.damage = r
endmethod
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
private method setArmor takes boolean reset returns nothing
local real pierce
local integer at
local integer dt
if reset then
set pierce = udg_DamageEventArmorPierced
set at = Damage.index.prevArmorT
set dt = Damage.index.prevDefenseT
set udg_DamageEventArmorPierced = 0.00
set this.armorPierced = 0.00
else
set pierce = -udg_DamageEventArmorPierced
set at = udg_DamageEventArmorT
set dt = udg_DamageEventDefenseT
endif
if pierce != 0.00 then
call BlzSetUnitArmor(udg_DamageEventTarget, BlzGetUnitArmor(udg_DamageEventTarget) + pierce)
endif
if Damage.index.prevArmorT != udg_DamageEventArmorT then
call BlzSetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_ARMOR_TYPE, at)
endif
if Damage.index.prevDefenseT != udg_DamageEventDefenseT then
call BlzSetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_DEFENSE_TYPE, dt)
endif
endmethod
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
static if USE_EXTRA then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
private static method onAOEEnd takes nothing returns nothing
if udg_DamageEventAOE > 1 then
call DamageTrigger.AOE.run()
endif
set udg_DamageEventAOE = 0
set udg_DamageEventLevel = 0
set udg_EnhancedDamageTarget = null
set udg_AOEDamageSource = null
call GroupClear(udg_DamageEventAOEGroup)
endmethod
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
private static method afterDamage takes nothing returns nothing
if udg_DamageEventPrevAmt != 0.00 and udg_DamageEventDamageT != 0 then
call DamageTrigger.AFTER.run()
set udg_DamageEventDamageT = 0
set udg_DamageEventPrevAmt = 0.00
endif
endmethod
private method doPreEvents takes boolean natural returns boolean
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set this.armorType = BlzGetUnitIntegerField(this.targetUnit, UNIT_IF_ARMOR_TYPE)
set this.defenseType = BlzGetUnitIntegerField(this.targetUnit, UNIT_IF_DEFENSE_TYPE)
set this.prevArmorT = this.armorType
set this.prevDefenseT = this.defenseType
set this.armorPierced = 0.00
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set Damage.index = this
call DamageTrigger.setGUIFromStruct(true)
call GroupAddUnit(proclusGlobal, udg_DamageEventSource)
call GroupAddUnit(fischerMorrow, udg_DamageEventTarget)
//! runtextmacro optional DAMAGE_EVENT_PRE_VARS_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_PRE_VARS_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_PRE_VARS_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_PRE_VARS_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_PRE_VARS_PLUGIN_05()
if udg_DamageEventAmount != 0.00 then
set udg_DamageEventOverride = udg_DamageEventDamageT == 0
call DamageTrigger.MOD.run()
static if not USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call DamageTrigger.setGUIFromStruct(false)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if natural then
call BlzSetEventAttackType(this.attackType)
call BlzSetEventDamageType(this.damageType)
call BlzSetEventWeaponType(this.weaponType)
call BlzSetEventDamage(udg_DamageEventAmount)
endif
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call this.setArmor(false)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
return false
endif
return true
endmethod
private static method unfreeze takes nothing returns nothing
local Damage i = damageStack
loop
exitwhen i == 0
set i = i - 1
set i.stackRef.recursiveTrig.trigFrozen = false
set i.stackRef.recursiveTrig.levelsDeep = 0
endloop
call EnableTrigger(t1)
call EnableTrigger(t2)
set kicking = false
set damageStack = 0
set prepped = 0
set dreaming = false
set sleepLevel = 0
call GroupClear(proclusGlobal)
call GroupClear(fischerMorrow)
//call BJDebugMsg("Cleared up the groups")
endmethod
static method finish takes nothing returns nothing
local Damage i = 0
local integer exit
if eventsRun then
set eventsRun = false
call afterDamage()
endif
if canKick and not kicking then
if damageStack != 0 then
set kicking = true
loop
set sleepLevel = sleepLevel + 1
set exit = damageStack
loop
set prepped = i.stackRef
if UnitAlive(prepped.targetUnit) then //Added just in case dead units had issues.
call prepped.doPreEvents(false) //don't evaluate the pre-event
if prepped.damage > 0.00 then
call DisableTrigger(t1) //Force only the after armor event to run.
call EnableTrigger(t2) //in case the user forgot to re-enable this
set totem = true
call UnitDamageTarget(prepped.sourceUnit, prepped.targetUnit, prepped.damage, prepped.isAttack, prepped.isRanged, prepped.attackType, prepped.damageType, prepped.weaponType)
else
//No new events run at all in this case
if udg_DamageEventDamageT != 0 then
call DamageTrigger.DAMAGE.run()
endif
if prepped.damage < 0.00 then
//No need for BlzSetEventDamage here
call SetWidgetLife(prepped.targetUnit, GetWidgetLife(prepped.targetUnit) - prepped.damage)
endif
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call prepped.setArmor(true)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endif
call afterDamage()
endif
set i = i + 1
exitwhen i == exit
endloop
exitwhen i == damageStack
endloop
endif
call unfreeze()
endif
endmethod
private static method failsafeClear takes nothing returns nothing
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call Damage.index.setArmor(true)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set canKick = true
set kicking = false
set totem = false
if udg_DamageEventDamageT != 0 then
call DamageTrigger.DAMAGE.run()
set eventsRun = true
endif
call finish()
endmethod
static method operator enabled= takes boolean b returns nothing
if b then
if dreaming then
call EnableTrigger(t3)
else
call EnableTrigger(t1)
call EnableTrigger(t2)
endif
else
if dreaming then
call DisableTrigger(t3)
else
call DisableTrigger(t1)
call DisableTrigger(t2)
endif
endif
endmethod
static method operator enabled takes nothing returns boolean
return IsTriggerEnabled(t1)
endmethod
private static boolean arisen = false
private static method getOutOfBed takes nothing returns nothing
if totem then
call failsafeClear() //WarCraft 3 didn't run the DAMAGED event despite running the DAMAGING event.
else
set canKick = true
set kicking = false
call finish()
endif
static if USE_EXTRA then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call onAOEEnd()
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set arisen = true
endmethod
private static method wakeUp takes nothing returns nothing
set dreaming = false
set Damage.enabled = true
call ForForce(bj_FORCE_PLAYER[0], function thistype.getOutOfBed) //Moved to a new thread in case of a thread crash
if not arisen then
//call BJDebugMsg("DamageEngine issue: thread crashed!")
call unfreeze()
else
set arisen = false
endif
set Damage.count = 0
set Damage.index = 0
set alarmSet = false
//call BJDebugMsg("Timer wrapped up")
endmethod
private method addRecursive takes nothing returns nothing
if this.damage != 0.00 then
set this.recursiveTrig = DamageTrigger.eventIndex
if not this.isCode then
set this.isCode = true
set this.userType = TYPE_CODE
endif
set inception = inception or DamageTrigger.eventIndex.inceptionTrig
if kicking and IsUnitInGroup(this.sourceUnit, proclusGlobal) and IsUnitInGroup(this.targetUnit, fischerMorrow) then
if not inception then
set DamageTrigger.eventIndex.trigFrozen = true
elseif not DamageTrigger.eventIndex.trigFrozen then
set DamageTrigger.eventIndex.inceptionTrig = true
if DamageTrigger.eventIndex.levelsDeep < sleepLevel then
set DamageTrigger.eventIndex.levelsDeep = DamageTrigger.eventIndex.levelsDeep + 1
if DamageTrigger.eventIndex.levelsDeep >= LIMBO then
set DamageTrigger.eventIndex.trigFrozen = true
endif
endif
endif
endif
set damageStack.stackRef = this
set damageStack = damageStack + 1
//call BJDebugMsg("damageStack: " + I2S(damageStack) + " levelsDeep: " + I2S(DamageTrigger.eventIndex.levelsDeep) + " sleepLevel: " + I2S(sleepLevel))
endif
set inception = false
endmethod
private static method clearNexts takes nothing returns nothing
set udg_NextDamageIsAttack = false
set udg_NextDamageType = 0
set udg_NextDamageWeaponT = 0
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_NextDamageIsMelee = false
set udg_NextDamageIsRanged = false
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endmethod
static method create takes unit src, unit tgt, real amt, boolean a, attacktype at, damagetype dt, weapontype wt returns Damage
local Damage d = Damage.count + 1
set Damage.count = d
set d.sourceUnit = src
set d.targetUnit = tgt
set d.damage = amt
set d.prevAmt = amt
set d.attackType = at
set d.damageType = dt
set d.weaponType = wt
set d.isAttack = udg_NextDamageIsAttack or a
set d.isSpell = d.attackType == null and not d.isAttack
return d
endmethod
private static method createFromEvent takes nothing returns Damage
local Damage d = create(GetEventDamageSource(), GetTriggerUnit(), GetEventDamage(), BlzGetEventIsAttack(), BlzGetEventAttackType(), BlzGetEventDamageType(), BlzGetEventWeaponType())
set d.isCode = udg_NextDamageType != 0 or udg_NextDamageIsAttack or udg_NextDamageIsRanged or udg_NextDamageIsMelee or d.damageType == DAMAGE_TYPE_MIND or udg_NextDamageWeaponT != 0 or (d.damage != 0.00 and d.damageType == DAMAGE_TYPE_UNKNOWN)
if d.isCode then
if udg_NextDamageType != 0 then
set d.userType = udg_NextDamageType
else
set d.userType = TYPE_CODE
endif
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set d.isMelee = udg_NextDamageIsMelee
set d.isRanged = udg_NextDamageIsRanged
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set d.eFilter = FILTER_CODE
if udg_NextDamageWeaponT != 0 then
set d.weaponType = ConvertWeaponType(udg_NextDamageWeaponT)
set udg_NextDamageWeaponT = 0
endif
else
set d.userType = 0
if d.damageType == DAMAGE_TYPE_NORMAL and d.isAttack then
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set d.isMelee = IsUnitType(d.sourceUnit, UNIT_TYPE_MELEE_ATTACKER)
set d.isRanged = IsUnitType(d.sourceUnit, UNIT_TYPE_RANGED_ATTACKER)
if d.isMelee and d.isRanged then
set d.isMelee = d.weaponType != null // Melee units play a sound when damaging
set d.isRanged = not d.isMelee // In the case where a unit is both ranged and melee, the ranged attack plays no sound.
endif
if d.isMelee then
set d.eFilter = FILTER_MELEE
elseif d.isRanged then
set d.eFilter = FILTER_RANGED
else
set d.eFilter = FILTER_ATTACK
endif
else
set d.eFilter = FILTER_ATTACK
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
else
if d.isSpell then
set d.eFilter = FILTER_SPELL
else
set d.eFilter = FILTER_OTHER
endif
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set d.isMelee = false
set d.isRanged = false
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endif
endif
call clearNexts()
return d
endmethod
private static method onRecursion takes nothing returns boolean //New in 5.7
local Damage d = Damage.createFromEvent()
call d.addRecursive()
call BlzSetEventDamage(0.00)
return false
endmethod
private static method onDamaging takes nothing returns boolean
local Damage d = Damage.createFromEvent()
//call BJDebugMsg("Pre-damage event running for " + GetUnitName(GetTriggerUnit()))
if alarmSet then
if totem then //WarCraft 3 didn't run the DAMAGED event despite running the DAMAGING event.
if d.damageType == DAMAGE_TYPE_SPIRIT_LINK or d.damageType == DAMAGE_TYPE_DEFENSIVE or d.damageType == DAMAGE_TYPE_PLANT then
set totem = false
set lastInstance= Damage.index
set canKick = false
else
call failsafeClear() //Not an overlapping event - just wrap it up
endif
else
call finish() //wrap up any previous damage index
endif
static if USE_EXTRA then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if d.sourceUnit != udg_AOEDamageSource then
call onAOEEnd()
set udg_AOEDamageSource = d.sourceUnit
elseif d.targetUnit == udg_EnhancedDamageTarget then
set udg_DamageEventLevel= udg_DamageEventLevel + 1
elseif not IsUnitInGroup(d.targetUnit, udg_DamageEventAOEGroup) then
set udg_DamageEventAOE = udg_DamageEventAOE + 1
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
else
call TimerStart(alarm, 0.00, false, function Damage.wakeUp)
set alarmSet = true
static if USE_EXTRA then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_AOEDamageSource = d.sourceUnit
set udg_EnhancedDamageTarget= d.targetUnit
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endif
static if USE_EXTRA then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call GroupAddUnit(udg_DamageEventAOEGroup, d.targetUnit)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if d.doPreEvents(true) then
call DamageTrigger.ZERO.run()
set canKick = true
call finish()
endif
set totem = lastInstance == 0 or attacksImmune[udg_DamageEventAttackT] or damagesImmune[udg_DamageEventDamageT] or not IsUnitType(udg_DamageEventTarget, UNIT_TYPE_MAGIC_IMMUNE)
return false
endmethod
private static method onDamaged takes nothing returns boolean
local real r = GetEventDamage()
local Damage d = Damage.index
//call BJDebugMsg("Second damage event running for " + GetUnitName(GetTriggerUnit()))
if prepped > 0 then
set prepped = 0
elseif dreaming or d.prevAmt == 0.00 then
return false
elseif totem then
set totem = false
else
//This should only happen for stuff like Spirit Link or Thorns Aura/Carapace
call afterDamage()
set Damage.index = lastInstance
set lastInstance = 0
set d = Damage.index
set canKick = true
call DamageTrigger.setGUIFromStruct(true)
endif
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call d.setArmor(true)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
static if USE_SCALING then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if udg_DamageEventAmount != 0.00 and r != 0.00 then
set udg_DamageScalingWC3 = r / udg_DamageEventAmount
elseif udg_DamageEventAmount > 0.00 then
set udg_DamageScalingWC3 = 0.00
else
set udg_DamageScalingWC3 = 1.00
if udg_DamageEventPrevAmt == 0.00 then
set udg_DamageScalingUser = 0.00
else
set udg_DamageScalingUser = udg_DamageEventAmount/udg_DamageEventPrevAmt
endif
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_DamageEventAmount = r
set d.damage = r
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_GDD()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_PDD()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_05()
if udg_DamageEventAmount > 0.00 then
call DamageTrigger.SHIELD.run()
static if not USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_DamageEventAmount = d.damage
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
static if USE_LETHAL then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if hasLethal or udg_DamageEventType < 0 then
set udg_LethalDamageHP = GetWidgetLife(udg_DamageEventTarget) - udg_DamageEventAmount
if udg_LethalDamageHP <= DEATH_VAL then
if hasLethal then
call DamageTrigger.LETHAL.run()
set udg_DamageEventAmount = GetWidgetLife(udg_DamageEventTarget) - udg_LethalDamageHP
set d.damage = udg_DamageEventAmount
endif
if udg_DamageEventType < 0 and udg_LethalDamageHP <= DEATH_VAL then
call SetUnitExploded(udg_DamageEventTarget, true)
endif
endif
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
static if USE_SCALING then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if udg_DamageEventPrevAmt == 0.00 or udg_DamageScalingWC3 == 0.00 then
set udg_DamageScalingUser = 0.00
else
set udg_DamageScalingUser = udg_DamageEventAmount/udg_DamageEventPrevAmt/udg_DamageScalingWC3
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endif
if udg_DamageEventDamageT != 0 then
call DamageTrigger.DAMAGE.run()
endif
call BlzSetEventDamage(udg_DamageEventAmount)
set eventsRun = true
if udg_DamageEventAmount == 0.00 then
call finish()
endif
return false
endmethod
static method apply takes unit src, unit tgt, real amt, boolean a, boolean r, attacktype at, damagetype dt, weapontype wt returns Damage
local Damage d
if udg_NextDamageType == 0 then
set udg_NextDamageType = TYPE_CODE
endif
if dreaming then
set d = create(src, tgt, amt, a, at, dt, wt)
set d.isCode = true
set d.eFilter = FILTER_CODE
set d.userType = udg_NextDamageType
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if not d.isSpell then
set d.isRanged = udg_NextDamageIsRanged or r
set d.isMelee = not d.isRanged
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call d.addRecursive()
else
call UnitDamageTarget(src, tgt, amt, a, r, at, dt, wt)
set d = Damage.index
call finish()
endif
call clearNexts()
return d
endmethod
static method applySpell takes unit src, unit tgt, real amt, damagetype dt returns Damage
return apply(src, tgt, amt, false, false, null, dt, null)
endmethod
static method applyAttack takes unit src, unit tgt, real amt, boolean ranged, attacktype at, weapontype wt returns Damage
return apply(src, tgt, amt, true, ranged, at, DAMAGE_TYPE_NORMAL, wt)
endmethod
//===========================================================================
private static method onInit takes nothing returns nothing
call TriggerRegisterAnyUnitEventBJ(t1, EVENT_PLAYER_UNIT_DAMAGING)
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"
endfunction
//===========================================================================
//
// Setup of automatic events from GUI and custom ones from JASS alike
//
//===========================================================================
public function RegisterFromHook takes trigger whichTrig, string var, limitop op, real value returns nothing
call DamageTrigger.registerVerbose(whichTrig, var, value, true, GetHandleId(op))
endfunction
hook TriggerRegisterVariableEvent RegisterFromHook
function TriggerRegisterDamageEngineEx takes trigger whichTrig, string eventName, real value, integer f returns DamageTrigger
return DamageTrigger.registerVerbose(whichTrig, DamageTrigger.getVerboseStr(eventName), value, false, f)
endfunction
function TriggerRegisterDamageEngine takes trigger whichTrig, string eventName, real value returns DamageTrigger
return DamageTrigger.registerTrigger(whichTrig, eventName, value)
endfunction
function RegisterDamageEngineEx takes code c, string eventName, real value, integer f returns DamageTrigger
return TriggerRegisterDamageEngineEx(DamageTrigger[c], eventName, value, f)
endfunction
//Similar to TriggerRegisterDamageEvent, although takes code instead of trigger as the first argument.
function RegisterDamageEngine takes code c, string eventName, real value returns DamageTrigger
return RegisterDamageEngineEx(c, eventName, value, FILTER_OTHER)
endfunction
//For GUI to tap into more powerful vJass event filtering:
//! textmacro DAMAGE_TRIGGER_CONFIG
if not DamageTrigger.eventIndex.configured then
//! endtextmacro
//! textmacro DAMAGE_TRIGGER_CONFIG_END
call DamageTrigger.eventIndex.configure()
if not DamageTrigger.eventIndex.checkConfiguration() then
return
endif
endif
//! endtextmacro
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library NeutralHeroes initializer Init
function RestrictHeroToOne takes integer heroid returns nothing
local integer i = 0
loop
call SetPlayerTechMaxAllowed(Player(i),heroid,1)
set i = i+1
exitwhen i == bj_MAX_PLAYERS
endloop
endfunction
private function Init takes nothing returns nothing
// Neutral Heroes
call RestrictHeroToOne('Hlgr') // Dark Knight
call RestrictHeroToOne('Naka') // Elder Sage
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library HumanSetup initializer Init requires CustomRaceSystem
private function Init takes nothing returns nothing
local CustomRace c = CustomRace.create("Human",RACE_HUMAN,1.0)
local integer index = 0
local player indexPlayer
call c.setTownHall('h007') // Town Hall
call c.addWorkerType('h005',c.NEAR_MINE,5) // Peasant
call c.setAIScript("human.ai")
loop
set indexPlayer = Player(index)
call UseCustomConsole(GetTriggerPlayer(), 1)
if (GetPlayerSlotState(indexPlayer) == PLAYER_SLOT_STATE_PLAYING) then
if GetPlayerRace(indexPlayer) == RACE_HUMAN and GetPlayerHandicap(indexPlayer) == 1.0 then
if GetLocalPlayer() == indexPlayer then
call PlayMusic( gg_snd_newman_theme )
endif
endif
endif
set index = index + 1
exitwhen index == bj_MAX_PLAYERS
endloop
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library OrcSetup initializer Init requires CustomRaceSystem
private function Init takes nothing returns nothing
local CustomRace c = CustomRace.create("Orc",RACE_ORC,1.0)
call c.setTownHall('o00C') // Stronghold
call c.addWorkerType('o00I',c.NEAR_MINE,5) // Goblin
call c.setAIScript("poo.ai")
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library UndeadSetup initializer Init requires CustomRaceSystem
private function WorkerHideToggle takes nothing returns nothing
call ShowUnit(GetEnumUnit(),IsUnitHidden(GetEnumUnit()))
endfunction
private function HauntGoldMine takes player play, group workers, unit goldmine, unit townhall, unit randhero returns nothing
call ForGroup(workers,function WorkerHideToggle)
call BlightGoldMineForPlayerBJ(goldmine,play)
call ForGroup(workers,function WorkerHideToggle)
call DestroyGroup(workers)
endfunction
private function Init takes nothing returns nothing
local CustomRace c = CustomRace.create("Undead",RACE_UNDEAD,1.0)
call c.setTownHall('u006') // Necropolis
call c.addWorkerType('u007',c.NEAR_MINE,3) // Acolyte
call c.addWorkerType('u00C',c.NEAR_HALL,1) // Wight
//call c.addHeroType('Udea') // Death Knight
//call c.addHeroType('Ulic') // Lich
//call c.addHeroType('Udre') // Dreadlord
//call c.addHeroType('Ucrl') // Crypt Lord
call c.setCallback(CustomRaceCall.HauntGoldMine)
call c.setAIScript("undead.ai")
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library NightElfSetup initializer Init requires CustomRaceSystem
private function EntangleGoldMine takes player play, group workers, unit goldmine, unit townhall, unit randhero returns nothing
call SetUnitPosition(townhall,GetUnitX(goldmine),GetUnitY(goldmine))
call IssueTargetOrder(townhall, "entangleinstant", goldmine)
call DestroyGroup(workers)
endfunction
private function Init takes nothing returns nothing
local CustomRace c = CustomRace.create("Night Elf",RACE_NIGHTELF,1.0)
call c.setTownHall('etol') // Tree of Life
call c.addWorkerType('ewsp',c.NEAR_MINE,5) // Wisp
call c.addHeroType('Ekee') // Keeper of the Grove
call c.addHeroType('Emoo') // Priestess of the Moon
call c.addHeroType('Edem') // Demon Hunter
call c.addHeroType('Ewar') // Warden
call c.setCallback(CustomRaceCall.EntangleGoldMine)
call c.setAIScript("elf.ai")
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library SatyrSetup initializer Init requires CustomRaceSystem
private function EntangleGoldMine takes player play, group workers, unit goldmine, unit townhall, unit randhero returns nothing
call SetUnitPosition(townhall,GetUnitX(goldmine),GetUnitY(goldmine))
call IssueTargetOrder(townhall, "entangleinstant", goldmine)
call DestroyGroup(workers)
endfunction
private function Init takes nothing returns nothing
local CustomRace c = CustomRace.create("Satyrs",RACE_HUMAN,1.0)
call c.setTownHall('n003') // Corrupted Tree of Life
call c.addWorkerType('u000',c.NEAR_MINE,3) // Hellcaller
call c.addWorkerType('n002',c.NEAR_HALL,1) // Trickster
call c.setCallback(CustomRaceCall.EntangleGoldMine)
call c.setAIScript("elf.ai")
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library SatyrSetup initializer Init requires CustomRaceSystem
private function CorruptedTreeLoop takes nothing returns nothing
call UnitAddAbilityBJ( 'A006', GetEnumUnit() )
call AddUnitAnimationPropertiesBJ( true, "alternate", GetEnumUnit() )
endfunction
private function EntangleGoldMine takes player play, group workers, unit goldmine, unit townhall, unit randhero returns nothing
set udg_CorruptedLifeGroup = GetUnitsOfTypeIdAll('n003')
call ForGroupBJ( udg_CorruptedLifeGroup, function CorruptedTreeLoop )
call DestroyGroup(udg_CorruptedLifeGroup)
call SetUnitPosition(townhall,GetUnitX(goldmine),GetUnitY(goldmine))
call IssueTargetOrder(townhall, "entangleinstant", goldmine)
call DestroyGroup(workers)
endfunction
private function Init takes nothing returns nothing
local CustomRace c = CustomRace.create("Satyrs",RACE_NIGHTELF,0.9)
call c.setTownHall('n003') // Corrupted Tree of Life
call c.addWorkerType('n00D',c.NEAR_MINE,5) // Satyr
call c.addHeroType('E008') // Hellcaller
call c.addHeroType('U004') // Darkener
call c.addHeroType('E00L') // Skeleton King
call c.addHeroType('E00K') // Incinerator
//call c.addWorkerType('n002',c.NEAR_HALL,1) // Trickster
//set udg_CorruptedLifeGroup = GetUnitsOfTypeIdAll('n00G')
//call ForGroupBJ( udg_CorruptedLifeGroup, function CorruptedTreeLoop )
//call DestroyGroup(udg_CorruptedLifeGroup)
call c.setCallback(CustomRaceCall.EntangleGoldMine)
call c.setAIScript("elf.ai")
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library DemonSetup initializer Init requires CustomRaceSystem
private function WorkerHideToggle takes nothing returns nothing
call ShowUnit(GetEnumUnit(),IsUnitHidden(GetEnumUnit()))
endfunction
private function HauntGoldMine takes player play, group workers, unit goldmine, unit townhall, unit randhero returns nothing
call ForGroup(workers,function WorkerHideToggle)
call BlightGoldMineForPlayerBJ(goldmine,play)
call ForGroup(workers,function WorkerHideToggle)
call DestroyGroup(workers)
endfunction
private function Init takes nothing returns nothing
local CustomRace c = CustomRace.create("Demon",RACE_UNDEAD,0.9)
call c.setTownHall('n00O') // Demon Gate
call c.addWorkerType('o000',c.NEAR_MINE,5) // Engineer
call c.addWorkerType('n00P',c.NEAR_HALL,1) // Power Generator
//call c.addHeroType('Udea') // Death Knight
//call c.addHeroType('Ulic') // Lich
//call c.addHeroType('Udre') // Dreadlord
//call c.addHeroType('Ucrl') // Crypt Lord
//call c.setCallback(CustomRaceCall.HauntGoldMine)
call c.setAIScript("undead.ai")
endfunction
endlibrary
function Trig_Untitled_Trigger_009_Func002A takes nothing returns nothing
call UnitAddAbilityBJ( 'A006', GetEnumUnit() )
call AddUnitAnimationPropertiesBJ( true, "alternate", GetEnumUnit() )
endfunction
function Trig_Untitled_Trigger_009_Actions takes nothing returns nothing
set udg_CorruptedLifeGroup = GetUnitsOfTypeIdAll('n00G')
call ForGroupBJ( udg_CorruptedLifeGroup, function Trig_Untitled_Trigger_009_Func002A )
call DestroyGroup(udg_CorruptedLifeGroup)
endfunction
//===========================================================================
function InitTrig_Untitled_Trigger_009 takes nothing returns nothing
set gg_trg_Untitled_Trigger_009 = CreateTrigger( )
call TriggerAddAction( gg_trg_Untitled_Trigger_009, function Trig_Untitled_Trigger_009_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
//==============================================================================
// Custom Race System by Archmage Owenalacaster
//==============================================================================
//
// Purpose:
// - Creates the starting units for custom races and replaces the standard
// Melee Initialization trigger. Custom races are selected by race and
// handicap.
//
// Usage:
// - Register a new custom race with CustomRace.create(name, RACE, handicap)
// Handicaps: Valid handicap values are 1.0, 0.9, 0.8, 0.7, 0.6 and 0.5.
// - Register a new custom race for all handicaps of a single race with
// CustomRace.createAll(name, RACE)
// - Extend the registration of a race with c.register(RACE, handicap)
// - Set the townhall type with c.setTownHall(unitid)
// - Add a new worker type with c.addWorkerType(unitid, priority, qty)
// Priorities: c.NEAR_MINE spawns workers near the mine, where workers
// typically spawn.
// c.NEAR_HALL spawns workers near the town hall, where
// Ghouls spawn.
// - Add a random hero type with c.addHeroType(unitid)
// - Set the ai script used by computer players with c.setAIScript(stringpath)
// - Set a callback function with c.setCallback(CustomRaceCall.function)
// Callbacks: The callback is executed after all the starting units for a
// player are created, and its purpose is to provide enhanced
// initial behaviour for a race. A good example of this with the
// standard races would be the Undead Goldmine Haunting and
// Night Elves Goldmine Entangling.
// The callback function passes as arguments all the units
// generated in addition to the nearest goldmine detected.
// Please note that if a random hero is not created, the last
// argument will have a null value, so always do a check.
// - Get a player's custom race name string with GetPlayerCustomRaceName(player)
//
// Notes:
// - Supports a maximum of 24 custom races.
// - Maximum for worker and hero types are configurable.
//
// Requirements:
// - JassHelper version 0.9.E.0 or newer (older versions may still work).
//
// Installation:
// - Create a new trigger called CustomRaceSystem.
// - Convert it to custom text and replace all the code with this code.
//
// Special Thanks:
// - Alevice: He practically co-wrote the code.
// - cosmicat: His formula for circular unit formation.
// Co-developing the single-array registry.
//
//==============================================================================
library CustomRaceSystem initializer Init
//===========================================================================
// CONFIGURATION SECTION
//===========================================================================
globals
// Unit Type Constants
private constant integer MAX_WORKERTYPES = 4
private constant integer MAX_HEROTYPES = 4
endglobals
//===========================================================================
// END CONFIGURATION SECTION
//===========================================================================
function interface CustomRaceCall takes player play, group workers, unit goldmine, unit townhall, unit randhero returns nothing
private function r2S takes race r returns string
if r == RACE_HUMAN then
return "Human"
elseif r == RACE_ORC then
return "Orc"
elseif r == RACE_UNDEAD then
return "Undead"
elseif r == RACE_NIGHTELF then
return "Night Elf"
endif
return "Unknown"
endfunction
private function r2I takes race r returns integer
if r == RACE_HUMAN then
return 1
elseif r == RACE_ORC then
return 2
elseif r == RACE_UNDEAD then
return 3
elseif r == RACE_NIGHTELF then
return 4
endif
return 5
endfunction
globals
// Victory Defeat Variables
private string array KEY_STRUCTURE
private integer KEY_STRUCTURE_COUNT = 0
endglobals
//===========================================================================
// STRUCT DATA
//===========================================================================
private keyword createStartingUnits
struct CustomRace
string name
// Town Hall Variable
integer townhallType = 0
//string townhallName
// Town Hall name is not currently supported.
// Worker Variables
integer totalWorkerTypes = 0
integer array workerType[MAX_WORKERTYPES]
integer array workerPriority[MAX_WORKERTYPES]
integer array workerQty[MAX_WORKERTYPES]
// Random Hero Variables
integer totalHeroTypes = 0
integer array heroType[MAX_HEROTYPES]
// AI Script Directory String Variable
string aiscript = ""
// Callback Variable
private CustomRaceCall c
// Registry Variable
static integer array REGISTRY
// Spawn Priority Variables
static integer NEAR_MINE = 0
static integer NEAR_HALL = 1
static method get takes race r, real h returns CustomRace
return CustomRace(.REGISTRY[((r2I(r)-1)*6)+(10-R2I(h*10.))])
endmethod
method register takes race r, real h returns boolean
local CustomRace c = CustomRace.get(r,h)
if c != 0 then
debug call BJDebugMsg("|cffff0000Registration of "+.name+" failed due to conflict with "+c.name+" registered for "+r2S(r)+" race Handicap "+R2S(h))
return false
endif
set .REGISTRY[((r2I(r)-1)*6)+(10-R2I(h*10.))] = integer(this)
return true
endmethod
static method create takes string name, race r, real h returns CustomRace
local CustomRace c = CustomRace.allocate()
set c.name = name
if not c.register(r,h) then
call c.destroy()
return 0
endif
return c
endmethod
static method createAll takes string name, race r returns CustomRace
local CustomRace c = CustomRace.allocate()
set c.name = name
if not c.register(r,1.0) and not c.register(r,0.9) and not c.register(r,0.8) and not c.register(r,0.7) and not c.register(r,0.6) and not c.register(r,0.5) then
call c.destroy()
return 0
endif
return c
endmethod
method setTownHall takes integer hallid returns nothing
set .townhallType = hallid
set KEY_STRUCTURE[KEY_STRUCTURE_COUNT] = UnitId2String(hallid)
set KEY_STRUCTURE_COUNT = KEY_STRUCTURE_COUNT+1
endmethod
method addWorkerType takes integer workerid, integer priority, integer quantity returns nothing
set .workerType[.totalWorkerTypes] = workerid
set .workerPriority[.totalWorkerTypes] = priority
set .workerQty[.totalWorkerTypes] = quantity
set .totalWorkerTypes = .totalWorkerTypes+1
endmethod
method addHeroType takes integer heroid returns nothing
local integer i = 0
set .heroType[.totalHeroTypes] = heroid
set .totalHeroTypes = .totalHeroTypes+1
loop
call SetPlayerTechMaxAllowed(Player(i),heroid,1)
set i = i+1
exitwhen i == bj_MAX_PLAYERS
endloop
endmethod
private method getRandomHeroType takes nothing returns integer
local integer randomindex = GetRandomInt(0,.totalHeroTypes-1)
return .heroType[randomindex]
endmethod
method setAIScript takes string s returns nothing
set .aiscript = s
endmethod
method setCallback takes CustomRaceCall callb returns nothing
set .c = callb
endmethod
private method createRandomHero takes player p, location loc returns unit
local unit h = CreateUnitAtLoc(p, .getRandomHeroType(), loc, bj_UNIT_FACING)
if bj_meleeGrantHeroItems then
//call MeleeGrantItemsToHero(h)
endif
return h
endmethod
method createStartingUnits takes player p returns nothing
local location startLoc = GetPlayerStartLocationLoc(p)
local location nearMineLoc = startLoc
local location nearTownLoc = startLoc
local location spawnLoc = startLoc
local location heroLoc = startLoc
local unit nearestMine = MeleeFindNearestMine(startLoc, bj_MELEE_MINE_SEARCH_RADIUS)
local unit myTownhall = null
local unit myRandHero = null
local group workerGroup = CreateGroup()
local integer workertypeindex = 0
local integer workerqty = 0
local integer spawnPriority = 0
if nearestMine != null then
set nearMineLoc = MeleeGetProjectedLoc(GetUnitLoc(nearestMine),startLoc,320,0)
set nearTownLoc = MeleeGetProjectedLoc(startLoc,GetUnitLoc(nearestMine),288,0)
set heroLoc = MeleeGetProjectedLoc(GetUnitLoc(nearestMine),startLoc,384,45)
endif
set myTownhall = CreateUnitAtLoc(p,.townhallType,startLoc,bj_UNIT_FACING)
loop
exitwhen workertypeindex == .totalWorkerTypes
set spawnPriority = .workerPriority[workertypeindex]
if (spawnPriority==.NEAR_HALL) then
set spawnLoc = nearTownLoc
elseif(spawnPriority==.NEAR_MINE) then
set spawnLoc = nearMineLoc
endif
loop
call GroupAddUnit(workerGroup, CreateUnitAtLoc(p,.workerType[workertypeindex],PolarProjectionBJ(spawnLoc,65,(I2R(workerqty)*(360.00 / I2R(.workerQty[workertypeindex]))) + 90),bj_UNIT_FACING))
set workerqty = workerqty + 1
exitwhen workerqty >= .workerQty[workertypeindex]
endloop
call RemoveLocation(spawnLoc)
set workerqty = 0
set workertypeindex = workertypeindex+1
endloop
if (IsMapFlagSet(MAP_RANDOM_HERO) and .totalHeroTypes>0 ) then
set myRandHero = .createRandomHero(p,heroLoc)
else
call SetPlayerState(p,PLAYER_STATE_RESOURCE_HERO_TOKENS,bj_MELEE_STARTING_HERO_TOKENS)
endif
if(.c!=0) then
call .c.evaluate(p,workerGroup,nearestMine,myTownhall,myRandHero)
else
call DestroyGroup(workerGroup)
endif
if nearMineLoc != startLoc then
call RemoveLocation(nearMineLoc)
call RemoveLocation(nearTownLoc)
call RemoveLocation(heroLoc)
endif
call RemoveLocation(startLoc)
set startLoc = null
set nearMineLoc = null
set nearTownLoc = null
set spawnLoc = null
set heroLoc = null
set nearestMine = null
set myTownhall = null
set myRandHero = null
set workerGroup = null
endmethod
endstruct
globals
private string array PLAYER_RACE
endglobals
function GetPlayerCustomRaceName takes player p returns string
return PLAYER_RACE[GetPlayerId(p)]
endfunction
//===========================================================================
// UNIT CREATION SECTION
//===========================================================================
private function CreateStartingUnitsForAllPlayers takes nothing returns nothing
local integer index = 0
local player indexPlayer
local race playerRace
local CustomRace c
loop
set indexPlayer = Player(index)
if (GetPlayerSlotState(indexPlayer) == PLAYER_SLOT_STATE_PLAYING) then
set playerRace = GetPlayerRace(indexPlayer)
set c = CustomRace.get(playerRace,GetPlayerHandicap(indexPlayer)+0.01)
if (GetPlayerController(indexPlayer) == MAP_CONTROL_USER or (GetPlayerController(indexPlayer) == MAP_CONTROL_COMPUTER and c.aiscript != "" )) and c != 0 then
set PLAYER_RACE[index] = c.name
call c.createStartingUnits(indexPlayer)
elseif playerRace == RACE_HUMAN then
call MeleeStartingUnitsHuman(indexPlayer,GetStartLocationLoc(GetPlayerStartLocation(indexPlayer)),true,true,true)
elseif playerRace == RACE_ORC then
call MeleeStartingUnitsOrc(indexPlayer,GetStartLocationLoc(GetPlayerStartLocation(indexPlayer)),true,true,true)
elseif playerRace == RACE_NIGHTELF then
call MeleeStartingUnitsNightElf(indexPlayer,GetStartLocationLoc(GetPlayerStartLocation(indexPlayer)),true,true,true)
elseif playerRace == RACE_UNDEAD then
call MeleeStartingUnitsUndead(indexPlayer,GetStartLocationLoc(GetPlayerStartLocation(indexPlayer)),true,true,true)
else
call MeleeStartingUnitsUnknownRace(indexPlayer,GetStartLocationLoc(GetPlayerStartLocation(indexPlayer)),true,true,true)
endif
endif
set index = index + 1
exitwhen index == bj_MAX_PLAYERS
endloop
endfunction
//===========================================================================
// CUSTOM MELEE AI SECTION
//===========================================================================
private function CustomMeleeStartingAI takes nothing returns nothing
local integer index = 0
local player indexPlayer
local race indexRace
local CustomRace c
loop
set indexPlayer = Player(index)
if (GetPlayerSlotState(indexPlayer) == PLAYER_SLOT_STATE_PLAYING) then
set indexRace = GetPlayerRace(indexPlayer)
set c = CustomRace.get(indexRace,GetPlayerHandicap(indexPlayer)+0.01)
call SetPlayerHandicap(indexPlayer,1.0)
if (GetPlayerController(indexPlayer) == MAP_CONTROL_COMPUTER) then
// Run a race-specific melee AI script.
if c != 0 and c.aiscript != "" then
call StartMeleeAI(indexPlayer, c.aiscript)
elseif (indexRace == RACE_HUMAN) then
call PickMeleeAI(indexPlayer, "human.ai", null, null)
elseif (indexRace == RACE_ORC) then
call PickMeleeAI(indexPlayer, "orc.ai", null, null)
elseif (indexRace == RACE_UNDEAD) then
call PickMeleeAI(indexPlayer, "undead.ai", null, null)
call RecycleGuardPosition(bj_ghoul[index])
elseif (indexRace == RACE_NIGHTELF) then
call PickMeleeAI(indexPlayer, "elf.ai", null, null)
else
// Unrecognized race.
endif
call ShareEverythingWithTeamAI(indexPlayer)
endif
endif
set index = index + 1
exitwhen index == bj_MAX_PLAYERS
endloop
endfunction
//===========================================================================
// VICTORY DEFEAT SECTION
//===========================================================================
private function CustomGetAllyKeyStructureCount takes player whichPlayer returns integer
local integer i = 0
local integer keyStructs = 0
local integer playerIndex = 0
local player indexPlayer
loop
set indexPlayer = Player(playerIndex)
if (PlayersAreCoAllied(whichPlayer, indexPlayer)) then
set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "townhall", true, true)
set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "greathall", true, true)
set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "necropolis", true, true)
set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "treeoflife", true, true)
loop
set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, KEY_STRUCTURE[i], true, true)
set i = i+1
exitwhen i == KEY_STRUCTURE_COUNT
endloop
endif
set playerIndex = playerIndex + 1
exitwhen playerIndex == bj_MAX_PLAYERS
endloop
return keyStructs
endfunction
private function CustomPlayerIsCrippled takes player whichPlayer returns boolean
local integer allyStructures = MeleeGetAllyStructureCount(whichPlayer)
local integer allyKeyStructures = CustomGetAllyKeyStructureCount(whichPlayer)
return (allyStructures > 0) and (allyKeyStructures <= 0)
endfunction
private function CustomCheckForCrippledPlayers takes nothing returns nothing
local integer playerIndex
local player indexPlayer
local boolean isNowCrippled
call MeleeCheckForLosersAndVictors()
if bj_finishSoonAllExposed then
return
endif
set playerIndex = 0
loop
set indexPlayer = Player(playerIndex)
set isNowCrippled = CustomPlayerIsCrippled(indexPlayer)
if (not bj_playerIsCrippled[playerIndex] and isNowCrippled) then
set bj_playerIsCrippled[playerIndex] = true
call TimerStart(bj_crippledTimer[playerIndex], bj_MELEE_CRIPPLE_TIMEOUT, false, function MeleeCrippledPlayerTimeout)
if (GetLocalPlayer() == indexPlayer) then
call TimerDialogDisplay(bj_crippledTimerWindows[playerIndex], true)
call DisplayTimedTextToPlayer(indexPlayer, 0, 0, bj_MELEE_CRIPPLE_MSG_DURATION, GetLocalizedString("CRIPPLE_WARNING_HUMAN"))
endif
elseif (bj_playerIsCrippled[playerIndex] and not isNowCrippled) then
set bj_playerIsCrippled[playerIndex] = false
call PauseTimer(bj_crippledTimer[playerIndex])
if (GetLocalPlayer() == indexPlayer) then
call TimerDialogDisplay(bj_crippledTimerWindows[playerIndex], false)
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
call MeleeExposePlayer(indexPlayer, false)
endif
set playerIndex = playerIndex + 1
exitwhen playerIndex == bj_MAX_PLAYERS
endloop
endfunction
private function CustomInitVictoryDefeat takes nothing returns nothing
local trigger checker = CreateTrigger()
local trigger trig
local integer index
local player indexPlayer
set bj_finishSoonTimerDialog = CreateTimerDialog(null)
call TriggerAddAction(checker, function CustomCheckForCrippledPlayers)
set trig = CreateTrigger()
call TriggerRegisterGameEvent(trig, EVENT_GAME_TOURNAMENT_FINISH_SOON)
call TriggerAddAction(trig, function MeleeTriggerTournamentFinishSoon)
set trig = CreateTrigger()
call TriggerRegisterGameEvent(trig, EVENT_GAME_TOURNAMENT_FINISH_NOW)
call TriggerAddAction(trig, function MeleeTriggerTournamentFinishNow)
set index = 0
loop
set indexPlayer = Player(index)
if (GetPlayerSlotState(indexPlayer) == PLAYER_SLOT_STATE_PLAYING) then
set bj_meleeDefeated[index] = false
set bj_meleeVictoried[index] = false
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))
call TriggerRegisterPlayerUnitEvent(checker, indexPlayer, EVENT_PLAYER_UNIT_CONSTRUCT_CANCEL, null)
call TriggerRegisterPlayerUnitEvent(checker, indexPlayer, EVENT_PLAYER_UNIT_DEATH, null)
call TriggerRegisterPlayerUnitEvent(checker, indexPlayer, EVENT_PLAYER_UNIT_CONSTRUCT_START, null)
call TriggerRegisterPlayerAllianceChange(checker, indexPlayer, ALLIANCE_PASSIVE)
call TriggerRegisterPlayerStateEvent(checker, indexPlayer, PLAYER_STATE_ALLIED_VICTORY, EQUAL, 1)
set trig = CreateTrigger()
call TriggerRegisterPlayerEvent(trig, indexPlayer, EVENT_PLAYER_DEFEAT)
call TriggerAddAction(trig, function MeleeTriggerActionPlayerDefeated)
set trig = CreateTrigger()
call TriggerRegisterPlayerEvent(trig, indexPlayer, EVENT_PLAYER_LEAVE)
call TriggerAddAction(trig, function MeleeTriggerActionPlayerLeft)
else
set bj_meleeDefeated[index] = true
set bj_meleeVictoried[index] = false
if (IsPlayerObserver(indexPlayer)) then
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
call TimerStart(CreateTimer(), 2.0, false, function CustomCheckForCrippledPlayers)
endfunction
private function TimerAction takes nothing returns nothing
call SetFloatGameState(GAME_STATE_TIME_OF_DAY, bj_MELEE_STARTING_TOD)
//call MeleeStartingHeroLimit()
//call MeleeGrantHeroItems()
//call MeleeStartingResources()
call MeleeClearExcessUnits()
call CreateStartingUnitsForAllPlayers()
call CustomMeleeStartingAI()
call CustomInitVictoryDefeat()
call DestroyTimer(GetExpiredTimer())
endfunction
private function Init takes nothing returns nothing
call TimerStart(CreateTimer(),0,false,function TimerAction)
endfunction
endlibrary
function Trig_Corrupted_Blight_Life_Copy_Func002Func002Func020C takes nothing returns boolean
if ( not ( GetUnitAbilityLevelSwapped('Abgl', GetEnumUnit()) < 1 ) ) then
return false
endif
if ( not ( BlzGetUnitIntegerField(GetEnumUnit(), UNIT_IF_DEFENSE_TYPE) == 3 ) ) then
return false
endif
return true
endfunction
function Trig_Corrupted_Blight_Life_Copy_Func002Func002C takes nothing returns boolean
if ( not Trig_Corrupted_Blight_Life_Copy_Func002Func002Func020C() ) then
return false
endif
return true
endfunction
function Trig_Corrupted_Blight_Life_Copy_Func002Func003Func020C takes nothing returns boolean
if ( not ( GetUnitAbilityLevelSwapped('Abgl', GetEnumUnit()) >= 1 ) ) then
return false
endif
if ( not ( BlzGetUnitIntegerField(GetEnumUnit(), UNIT_IF_DEFENSE_TYPE) == 2 ) ) then
return false
endif
return true
endfunction
function Trig_Corrupted_Blight_Life_Copy_Func002Func003C takes nothing returns boolean
if ( not Trig_Corrupted_Blight_Life_Copy_Func002Func003Func020C() ) then
return false
endif
return true
endfunction
function Trig_Corrupted_Blight_Life_Copy_Func002A takes nothing returns nothing
if ( Trig_Corrupted_Blight_Life_Copy_Func002Func002C() ) then
call DisplayTextToForce( GetForceOfPlayer(Player(0)), "TRIGSTR_982" )
call UnitRemoveAbilityBJ( 'Abdl', GetEnumUnit() )
call UnitAddAbilityBJ( 'Abgl', GetEnumUnit() )
else
endif
if ( Trig_Corrupted_Blight_Life_Copy_Func002Func003C() ) then
call DisplayTextToForce( GetForceOfPlayer(Player(0)), "TRIGSTR_983" )
call UnitRemoveAbilityBJ( 'Abgl', GetEnumUnit() )
call UnitAddAbilityBJ( 'Abdl', GetEnumUnit() )
else
endif
endfunction
function Trig_Corrupted_Blight_Life_Copy_Actions takes nothing returns nothing
set bj_wantDestroyGroup = true
call ForGroupBJ( GetUnitsOfTypeIdAll('n003'), function Trig_Corrupted_Blight_Life_Copy_Func002A )
endfunction
//===========================================================================
function InitTrig_Corrupted_Blight_Life_Copy takes nothing returns nothing
set gg_trg_Corrupted_Blight_Life_Copy = CreateTrigger( )
call TriggerRegisterTimerEventPeriodic( gg_trg_Corrupted_Blight_Life_Copy, 0.25 )
call TriggerAddAction( gg_trg_Corrupted_Blight_Life_Copy, function Trig_Corrupted_Blight_Life_Copy_Actions )
endfunction
function Trig_Untitled_Trigger_013_Actions takes nothing returns nothing
call SetPlayerStateBJ( GetOwningPlayer(GetSpellAbilityUnit()), PLAYER_STATE_RESOURCE_GOLD, 750 )
endfunction
//===========================================================================
function InitTrig_Untitled_Trigger_013 takes nothing returns nothing
set gg_trg_Untitled_Trigger_013 = CreateTrigger( )
call TriggerAddAction( gg_trg_Untitled_Trigger_013, function Trig_Untitled_Trigger_013_Actions )
endfunction
function Trig_Call_of_Nightmares_Replacement_Copy_Conditions takes nothing returns boolean
if ( not ( GetSpellAbilityId() == 'A01H' ) ) then
return false
endif
return true
endfunction
function Trig_Call_of_Nightmares_Replacement_Copy_Func003001003 takes nothing returns boolean
return ( IsUnitDeadBJ(GetFilterUnit()) == true )
endfunction
function Trig_Call_of_Nightmares_Replacement_Copy_Func003Func002C takes nothing returns boolean
if ( not ( udg_NightmareCounter[GetConvertedPlayerId(GetOwningPlayer(GetSpellAbilityUnit()))] < 6 ) ) then
return false
endif
return true
endfunction
function Trig_Call_of_Nightmares_Replacement_Copy_Func003A takes nothing returns nothing
local unit u
if ( Trig_Call_of_Nightmares_Replacement_Copy_Func003Func002C() ) then
set udg_NightmareCounter[GetConvertedPlayerId(GetOwningPlayer(GetSpellAbilityUnit()))] = ( udg_NightmareCounter[GetConvertedPlayerId(GetOwningPlayer(GetSpellAbilityUnit()))] + 1 )
call GetDummy(GetOwningPlayer(GetSpellAbilityUnit()), 'A02U', 1, GetUnitX(GetSpellAbilityUnit()), GetUnitY(GetSpellAbilityUnit()))
set udg_Demo_Unit = GetLastCreatedUnit()
set u = udg_Demo_Unit
call IssueImmediateOrderBJ( udg_Demo_Unit, "spiritwolf" )
call UnitRemoveAbilityTimed.create(u, 'A02U', 5.0, true)
call RemoveUnit( GetEnumUnit() )
else
call DisplayTextToForce( GetForceOfPlayer(Player(0)), "TRIGSTR_696" )
exitwhen true
endif
endfunction
function Trig_Call_of_Nightmares_Replacement_Copy_Actions takes nothing returns nothing
set udg_Tmp_Loc = GetUnitLoc(GetSpellAbilityUnit())
set udg_NightmareCounter[GetConvertedPlayerId(GetOwningPlayer(GetSpellAbilityUnit()))] = 0
call ForGroupBJ( GetUnitsInRangeOfLocMatching(900.00, udg_Tmp_Loc, Condition(function Trig_Call_of_Nightmares_Replacement_Copy_Func003001003)), function Trig_Call_of_Nightmares_Replacement_Copy_Func003A )
call DisplayTextToForce( GetForceOfPlayer(Player(0)), "TRIGSTR_697" )
call RemoveLocation(udg_Tmp_Loc)
endfunction
//===========================================================================
function InitTrig_Call_of_Nightmares_Replacement_Copy takes nothing returns nothing
set gg_trg_Call_of_Nightmares_Replacement_Copy = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Call_of_Nightmares_Replacement_Copy, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Call_of_Nightmares_Replacement_Copy, Condition( function Trig_Call_of_Nightmares_Replacement_Copy_Conditions ) )
call TriggerAddAction( gg_trg_Call_of_Nightmares_Replacement_Copy, function Trig_Call_of_Nightmares_Replacement_Copy_Actions )
endfunction
scope eternalservitude initializer init
// this is an example of non-stacking aura
globals
private constant integer SPELL_ID = 'A02F'
private constant integer STR_LVL = 1
private Table g_tbl
endglobals
private struct AuraBuff extends AuraSysBuff
private static constant string TARGET_EFFECT = "Abilities\\Spells\\Other\\GeneralAuraTarget\\GeneralAuraTarget.mdl"
private effect el
private effect er
private timer t
private integer max_lvl
private integer cur_lvl
// called when this buff is applied to an unit the first time
method on_apply takes nothing returns nothing
set el = AddSpecialEffectTarget(TARGET_EFFECT, this.as_target, "origin")
//set er = AddSpecialEffectTarget(TARGET_EFFECT, this.as_target, "hand right")
set t = CreateTimer()
call TimerStart(t, 1.5, true, function thistype.on_tick)
set g_tbl[GetHandleId(t)] = this
endmethod
// called when the last AuraSys that inflicts this buff is removed from an unit
method on_remove takes nothing returns nothing
call g_tbl.remove(GetHandleId(t))
call PauseTimer(t)
call DestroyTimer(t)
set t = null
call DestroyEffect(el)
set el = null
//call DestroyEffect(er)
//set el = null
endmethod
static method on_tick takes nothing returns nothing
// periodically update level since the hero stat might change
local thistype this = g_tbl[GetHandleId(GetExpiredTimer())]
call this.update()
endmethod
method update takes nothing returns nothing
call this.update_lvl()
call this.update_buff()
endmethod
private method update_buff takes nothing returns nothing
local integer next = max_lvl
if next != this.cur_lvl then
call SetUnitAbilityLevel(this.as_target, 'A02O', max_lvl)
set this.cur_lvl = next
endif
endmethod
private method update_lvl takes nothing returns nothing
// keep track of the max_lvl
local AuraSysNode head = AuraSys.get_node_head(this)
local AuraSysNode next = head
local integer tmp = 0
local integer tmp2
// enum the highest score
loop
set next = AuraSys.get_next_node(head, next, 0)
exitwhen next == 0
set tmp2 = GetUnitAbilityLevel(next.as_sys.as_source, SPELL_ID)
if tmp < tmp2 then
set tmp = tmp2
endif
endloop
set this.max_lvl = tmp
endmethod
endstruct
private struct AuraNode extends AuraSysNode
// called everytime a new AuraSys is added to the buff
method on_apply takes nothing returns nothing
local AuraBuff buf = this.as_buff
call buf.update()
endmethod
// called everytime an AuraSys is removed from the buff
method on_remove takes nothing returns nothing
local AuraBuff buf = this.as_buff
call buf.update()
endmethod
endstruct
private struct Aura extends AuraSys
implement AuraSysInit
private static constant integer BUFF_SPELL_ID = 'A02O'
private static constant integer BUFF_ID = 'B00N'
private effect e
method get_range takes nothing returns real
return 900.0
endmethod
method active_cond takes nothing returns boolean
return UnitAlive(this.as_source)
endmethod
method filter takes unit u returns boolean
return IsUnitAlly(u, GetOwningPlayer(this.as_source)) and not (GetOwningPlayer(u) == Player(PLAYER_NEUTRAL_PASSIVE)) and not IsUnitType(u, UNIT_TYPE_STRUCTURE) and IsUnitType(u, UNIT_TYPE_SUMMONED) and IsUnitType(u, UNIT_TYPE_UNDEAD) and (GetUnitAbilityLevelSwapped('Aloc', u) == 0) and UnitAlive(u)
endmethod
method linger_filter takes unit u returns boolean
return UnitAlive(u)
endmethod
method new_node takes nothing returns AuraSysNode
return AuraNode.create()
endmethod
method new_buff takes nothing returns AuraSysBuff
return AuraBuff.create()
endmethod
method get_buff_typeid takes nothing returns integer
return AuraBuff.typeid
endmethod
method on_apply takes nothing returns nothing
set e = AddSpecialEffectTarget("war3mapImported\\UndeadSelectionAura.mdl", this.as_source, "origin")
endmethod
method on_remove takes nothing returns nothing
call DestroyEffect(e)
set e = null
endmethod
endstruct
private function learn_action takes nothing returns nothing
local Aura aura
set aura = Aura.new(GetTriggerUnit())
endfunction
function t_Conditions takes nothing returns boolean
if ( not ( GetSpellAbilityId() == 'A02H' ) ) then
return false
endif
return true
endfunction
//===========================================================================
private function init takes nothing returns nothing
local trigger t
set t = CreateTrigger()
//call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_HERO_SKILL)
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( t, Condition( function t_Conditions ) )
call TriggerAddAction(t, function learn_action)
set g_tbl = Table.create()
set t = null
endfunction
endscope
scope eternalservitude initializer init
// this is an example of non-stacking aura
globals
private constant integer SPELL_ID = 'A02F'
private constant integer STR_LVL = 1
private Table g_tbl
endglobals
private struct AuraBuff extends AuraSysBuff
private static constant string TARGET_EFFECT = "Abilities\\Spells\\Other\\GeneralAuraTarget\\GeneralAuraTarget.mdl"
private effect el
private effect er
private timer t
private integer max_lvl
private integer cur_lvl
// called when this buff is applied to an unit the first time
method on_apply takes nothing returns nothing
set el = AddSpecialEffectTarget(TARGET_EFFECT, this.as_target, "origin")
//set er = AddSpecialEffectTarget(TARGET_EFFECT, this.as_target, "hand right")
set t = CreateTimer()
call TimerStart(t, 1.5, true, function thistype.on_tick)
set g_tbl[GetHandleId(t)] = this
endmethod
// called when the last AuraSys that inflicts this buff is removed from an unit
method on_remove takes nothing returns nothing
call g_tbl.remove(GetHandleId(t))
call PauseTimer(t)
call DestroyTimer(t)
set t = null
call DestroyEffect(el)
set el = null
//call DestroyEffect(er)
//set el = null
endmethod
static method on_tick takes nothing returns nothing
// periodically update level since the hero stat might change
local thistype this = g_tbl[GetHandleId(GetExpiredTimer())]
call this.update()
endmethod
method update takes nothing returns nothing
call this.update_lvl()
call this.update_buff()
endmethod
private method update_buff takes nothing returns nothing
local integer next = max_lvl
if next != this.cur_lvl then
call SetUnitAbilityLevel(this.as_target, 'A02O', max_lvl)
set this.cur_lvl = next
endif
endmethod
private method update_lvl takes nothing returns nothing
// keep track of the max_lvl
local AuraSysNode head = AuraSys.get_node_head(this)
local AuraSysNode next = head
local integer tmp = 0
local integer tmp2
// enum the highest score
loop
set next = AuraSys.get_next_node(head, next, 0)
exitwhen next == 0
set tmp2 = GetUnitAbilityLevel(next.as_sys.as_source, SPELL_ID)
if tmp < tmp2 then
set tmp = tmp2
endif
endloop
set this.max_lvl = tmp
endmethod
endstruct
private struct AuraNode extends AuraSysNode
// called everytime a new AuraSys is added to the buff
method on_apply takes nothing returns nothing
local AuraBuff buf = this.as_buff
call buf.update()
endmethod
// called everytime an AuraSys is removed from the buff
method on_remove takes nothing returns nothing
local AuraBuff buf = this.as_buff
call buf.update()
endmethod
endstruct
private struct Aura extends AuraSys
implement AuraSysInit
private static constant integer BUFF_SPELL_ID = 'A02O'
private static constant integer BUFF_ID = 'B00N'
private effect e
method get_range takes nothing returns real
return 900.0
endmethod
method active_cond takes nothing returns boolean
return UnitAlive(this.as_source)
endmethod
method filter takes unit u returns boolean
return IsUnitAlly(u, GetOwningPlayer(this.as_source)) and not (GetOwningPlayer(u) == Player(PLAYER_NEUTRAL_PASSIVE)) and not IsUnitType(u, UNIT_TYPE_STRUCTURE) and IsUnitType(u, UNIT_TYPE_SUMMONED) and IsUnitType(u, UNIT_TYPE_UNDEAD) and (GetUnitAbilityLevelSwapped('Aloc', u) == 0) and UnitAlive(u)
endmethod
method linger_filter takes unit u returns boolean
return UnitAlive(u)
endmethod
method new_node takes nothing returns AuraSysNode
return AuraNode.create()
endmethod
method new_buff takes nothing returns AuraSysBuff
return AuraBuff.create()
endmethod
method get_buff_typeid takes nothing returns integer
return AuraBuff.typeid
endmethod
method on_apply takes nothing returns nothing
set e = AddSpecialEffectTarget("war3mapImported\\UndeadSelectionAura.mdl", this.as_source, "origin")
endmethod
method on_remove takes nothing returns nothing
call DestroyEffect(e)
set e = null
endmethod
endstruct
private function learn_action takes nothing returns nothing
local Aura aura
if (GetLearnedSkill() == SPELL_ID) and GetLearnedSkillLevel() == 1 then
set aura = Aura.new(GetTriggerUnit())
endif
endfunction
//===========================================================================
private function init takes nothing returns nothing
local trigger t
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_HERO_SKILL)
call TriggerAddAction(t, function learn_action)
set g_tbl = Table.create()
set t = null
endfunction
endscope
scope strengthaura initializer init
// this is an example of non-stacking aura
globals
private constant integer SPELL_ID = 'A02J'
private constant integer STR_LVL = 1
private Table g_tbl
endglobals
private struct AuraBuff extends AuraSysBuff
private static constant string TARGET_EFFECT = "Abilities\\Spells\\Other\\GeneralAuraTarget\\GeneralAuraTarget.mdl"
private effect el
private effect er
private timer t
private integer max_lvl
private integer cur_lvl
// called when this buff is applied to an unit the first time
method on_apply takes nothing returns nothing
set el = AddSpecialEffectTarget(TARGET_EFFECT, this.as_target, "origin")
//set er = AddSpecialEffectTarget(TARGET_EFFECT, this.as_target, "hand right")
set t = CreateTimer()
call TimerStart(t, 1.5, true, function thistype.on_tick)
set g_tbl[GetHandleId(t)] = this
endmethod
// called when the last AuraSys that inflicts this buff is removed from an unit
method on_remove takes nothing returns nothing
call g_tbl.remove(GetHandleId(t))
call PauseTimer(t)
call DestroyTimer(t)
set t = null
call DestroyEffect(el)
set el = null
//call DestroyEffect(er)
//set el = null
endmethod
static method on_tick takes nothing returns nothing
// periodically update level since the hero stat might change
local thistype this = g_tbl[GetHandleId(GetExpiredTimer())]
call this.update()
endmethod
method update takes nothing returns nothing
call this.update_lvl()
call this.update_buff()
endmethod
private method update_buff takes nothing returns nothing
local integer next = max_lvl
if next != this.cur_lvl then
call SetUnitAbilityLevel(this.as_target, 'A02I', max_lvl)
set this.cur_lvl = next
endif
endmethod
private method update_lvl takes nothing returns nothing
// keep track of the max_lvl
local AuraSysNode head = AuraSys.get_node_head(this)
local AuraSysNode next = head
local integer tmp = 0
local integer tmp2
// enum the highest score
loop
set next = AuraSys.get_next_node(head, next, 0)
exitwhen next == 0
set tmp2 = GetUnitAbilityLevel(next.as_sys.as_source, SPELL_ID)
if tmp < tmp2 then
set tmp = tmp2
endif
endloop
set this.max_lvl = tmp
endmethod
endstruct
private struct AuraNode extends AuraSysNode
// called everytime a new AuraSys is added to the buff
method on_apply takes nothing returns nothing
local AuraBuff buf = this.as_buff
call buf.update()
endmethod
// called everytime an AuraSys is removed from the buff
method on_remove takes nothing returns nothing
local AuraBuff buf = this.as_buff
call buf.update()
endmethod
endstruct
private struct Aura extends AuraSys
implement AuraSysInit
private static constant integer BUFF_SPELL_ID = 'A02I'
private static constant integer BUFF_ID = 'B00M'
private effect e
method get_range takes nothing returns real
return 900.0
endmethod
method active_cond takes nothing returns boolean
return UnitAlive(this.as_source)
endmethod
method filter takes unit u returns boolean
return IsUnitAlly(u, GetOwningPlayer(this.as_source)) and not (GetOwningPlayer(u) == Player(PLAYER_NEUTRAL_PASSIVE)) and not IsUnitType(u, UNIT_TYPE_STRUCTURE) and UnitAlive(u)
endmethod
method linger_filter takes unit u returns boolean
return UnitAlive(u)
endmethod
method new_node takes nothing returns AuraSysNode
return AuraNode.create()
endmethod
method new_buff takes nothing returns AuraSysBuff
return AuraBuff.create()
endmethod
method get_buff_typeid takes nothing returns integer
return AuraBuff.typeid
endmethod
method on_apply takes nothing returns nothing
set e = AddSpecialEffectTarget("war3mapImported\\Bone Guard.mdl", this.as_source, "origin")
endmethod
method on_remove takes nothing returns nothing
call DestroyEffect(e)
set e = null
endmethod
endstruct
private function learn_action takes nothing returns nothing
local Aura aura
if (GetLearnedSkill() == SPELL_ID) and GetLearnedSkillLevel() == 1 then
set aura = Aura.new(GetTriggerUnit())
endif
endfunction
//===========================================================================
private function init takes nothing returns nothing
local trigger t
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_HERO_SKILL)
call TriggerAddAction(t, function learn_action)
set g_tbl = Table.create()
set t = null
endfunction
endscope
function Trig_Necromancer_Toggle_Summoning_Ritual_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_START_SUMMONING_RITUAL or GetSpellAbilityId() == SB_STOP_SUMMONING_RITUAL
endfunction
function Trig_Necromancer_Toggle_Summoning_Ritual_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local location casterPos = null
if (GetSpellAbilityId() == SB_START_SUMMONING_RITUAL) then
set casterPos = GetUnitLoc(caster)
call SaveReal(udg_HashTable_UnitInfo, GetHandleId(caster), StringHash("FACING"), GetUnitFacing(caster))
call BlzSetUnitFacingEx(caster, bj_UNIT_FACING)
call IssuePointOrderLoc(caster, "root", casterPos)
call RemoveLocation(casterPos)
else
call ClearUnitTrainingQueue(caster)
call IssueImmediateOrder(caster, "unroot")
endif
call GroupAddUnit(udg_UnitGroup_TransformingNecros, caster)
call EnableTrigger(gg_trg_Necromancer_Ritual_Root_Loop)
endfunction
//===========================================================================
function InitTrig_Necromancer_Toggle_Summoning_Ritual takes nothing returns nothing
set gg_trg_Necromancer_Toggle_Summoning_Ritual = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Necromancer_Toggle_Summoning_Ritual, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Necromancer_Toggle_Summoning_Ritual, Condition( function Trig_Necromancer_Toggle_Summoning_Ritual_Conditions ) )
call TriggerAddAction( gg_trg_Necromancer_Toggle_Summoning_Ritual, function Trig_Necromancer_Toggle_Summoning_Ritual_Actions )
endfunction
function Trig_Necromancer_Toggle_Summoning_Ritual_Copy_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A020'
endfunction
function Trig_Advanced_Units_Func002001001 takes nothing returns boolean
return ( true == true )
endfunction
function Trig_Necromancer_Toggle_Summoning_Ritual_Copy_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local location casterPos = null
call DisplayTextToForce( GetPlayersMatching(Condition(function Trig_Advanced_Units_Func002001001)), "I'm really trying to get this to work" )
if (GetSpellAbilityId() == 'A020') then
call DisplayTextToForce( GetPlayersMatching(Condition(function Trig_Advanced_Units_Func002001001)), BlzGetAbilityTooltip(GetSpellAbilityId(), 0) )
else
//call ClearUnitTrainingQueue(caster)
call IssueImmediateOrder(caster, "unroot")
endif
//call GroupAddUnit(udg_UnitGroup_TransformingNecros, caster)
//call EnableTrigger(gg_trg_Necromancer_Ritual_Root_Loop)
endfunction
//===========================================================================
function InitTrig_Necromancer_Toggle_Summoning_Ritual_Copy takes nothing returns nothing
set gg_trg_Necromancer_Toggle_Summoning_Ritual_Copy = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Necromancer_Toggle_Summoning_Ritual_Copy, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Necromancer_Toggle_Summoning_Ritual_Copy, Condition( function Trig_Necromancer_Toggle_Summoning_Ritual_Copy_Conditions ) )
call TriggerAddAction( gg_trg_Necromancer_Toggle_Summoning_Ritual_Copy, function Trig_Necromancer_Toggle_Summoning_Ritual_Copy_Actions )
endfunction
function Trig_Untitled_Trigger_003_Func002001001 takes nothing returns boolean
return ( true == true )
endfunction
function Trig_Untitled_Trigger_003_Actions takes nothing returns nothing
call DisplayTextToForce( GetPlayersMatching(Condition(function Trig_Untitled_Trigger_003_Func002001001)), "Yes" )
endfunction
//===========================================================================
function InitTrig_Untitled_Trigger_003 takes nothing returns nothing
set gg_trg_Untitled_Trigger_003 = CreateTrigger( )
call TriggerAddAction( gg_trg_Untitled_Trigger_003, function Trig_Untitled_Trigger_003_Actions )
endfunction
function Trig_Advanced_Units_Test_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A020'
endfunction
function Trig_Advanced_Units_Func002001001 takes nothing returns boolean
return ( true == true )
endfunction
function Trig_Advanced_Units_Func003C takes nothing returns boolean
if ( not ( GetUnitAbilityLevelSwapped('A020', GetTriggerUnit()) == 1 ) ) then
return false
endif
return true
endfunction
function Trig_Advanced_Units_Test_Actions takes nothing returns nothing
call DisplayTextToForce( GetPlayersMatching(Condition(function Trig_Advanced_Units_Func002001001)), BlzGetAbilityTooltip(GetSpellAbilityId(), 0) )
if ( Trig_Advanced_Units_Func003C() ) then
call IncUnitAbilityLevelSwapped( 'A020', GetTriggerUnit() )
call SetPlayerUnitAvailableBJ( 'n00Q', false, GetOwningPlayer(GetTriggerUnit()) )
call SetPlayerUnitAvailableBJ( 'n00R', false, GetOwningPlayer(GetTriggerUnit()) )
call SetPlayerUnitAvailableBJ( 'n00U', false, GetOwningPlayer(GetTriggerUnit()) )
call SetPlayerUnitAvailableBJ( 'n00X', false, GetOwningPlayer(GetTriggerUnit()) )
call SetPlayerUnitAvailableBJ( 'n00V', false, GetOwningPlayer(GetTriggerUnit()) )
call SetPlayerUnitAvailableBJ( 'n012', false, GetOwningPlayer(GetTriggerUnit()) )
call SetPlayerUnitAvailableBJ( 'n00W', true, GetOwningPlayer(GetTriggerUnit()) )
call SetPlayerUnitAvailableBJ( 'n014', true, GetOwningPlayer(GetTriggerUnit()) )
call SetPlayerUnitAvailableBJ( 'n013', true, GetOwningPlayer(GetTriggerUnit()) )
call SetPlayerUnitAvailableBJ( 'n00S', true, GetOwningPlayer(GetTriggerUnit()) )
call SetPlayerUnitAvailableBJ( 'n00T', true, GetOwningPlayer(GetTriggerUnit()) )
else
call DecUnitAbilityLevelSwapped( 'A020', GetTriggerUnit() )
call SetPlayerUnitAvailableBJ( 'n00Q', true, GetOwningPlayer(GetTriggerUnit()) )
call SetPlayerUnitAvailableBJ( 'n00R', true, GetOwningPlayer(GetTriggerUnit()) )
call SetPlayerUnitAvailableBJ( 'n00U', true, GetOwningPlayer(GetTriggerUnit()) )
call SetPlayerUnitAvailableBJ( 'n00X', true, GetOwningPlayer(GetTriggerUnit()) )
call SetPlayerUnitAvailableBJ( 'n00V', true, GetOwningPlayer(GetTriggerUnit()) )
call SetPlayerUnitAvailableBJ( 'n012', true, GetOwningPlayer(GetTriggerUnit()) )
call SetPlayerUnitAvailableBJ( 'n00W', false, GetOwningPlayer(GetTriggerUnit()) )
call SetPlayerUnitAvailableBJ( 'n014', false, GetOwningPlayer(GetTriggerUnit()) )
call SetPlayerUnitAvailableBJ( 'n013', false, GetOwningPlayer(GetTriggerUnit()) )
call SetPlayerUnitAvailableBJ( 'n00S', false, GetOwningPlayer(GetTriggerUnit()) )
call SetPlayerUnitAvailableBJ( 'n00T', false, GetOwningPlayer(GetTriggerUnit()) )
endif
endfunction
//===========================================================================
function InitTrig_Advanced_Units_Test takes nothing returns nothing
set gg_trg_Advanced_Units_Test = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Advanced_Units_Test, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Advanced_Units_Test, Condition( function Trig_Advanced_Units_Test_Conditions ) )
call TriggerAddAction( gg_trg_Advanced_Units_Test, function Trig_Advanced_Units_Test_Actions )
endfunction