Name | Type | is_array | initial_value |
AfterDamageEvent | real | No | |
AggroTextOn | boolean | Yes | |
ALL_ROUND_STATS | integer | Yes | |
AMOVE_GROUPS | group | Yes | |
AMOVE_INDEX | integer | No | 1 |
AMOVE_SIZE | integer | No | 1 |
AOEDamageEvent | real | No | |
AOEDamageSource | unit | No | |
ArenaBoard | multiboard | No | |
ARMOR_TYPE_ETHEREAL | integer | No | |
ARMOR_TYPE_FLESH | integer | No | |
ARMOR_TYPE_METAL | integer | No | |
ARMOR_TYPE_NONE | integer | No | |
ARMOR_TYPE_STONE | integer | No | |
ARMOR_TYPE_WOOD | integer | No | |
ArmorDamageEvent | real | No | |
ArmorTypeDebugStr | string | Yes | |
ATTACK_TYPE_CHAOS | integer | No | |
ATTACK_TYPE_HERO | integer | No | |
ATTACK_TYPE_MAGIC | integer | No | |
ATTACK_TYPE_NORMAL | integer | No | |
ATTACK_TYPE_PIERCE | integer | No | |
ATTACK_TYPE_SIEGE | integer | No | |
ATTACK_TYPE_SPELLS | integer | No | |
AttackTypeDebugStr | string | Yes | |
BFUScale | real | No | 1.80 |
BFUStacks | integer | No | |
BFUStacksCap | integer | No | 5 |
BonusAttackFlat | integer | Yes | |
BossesInPlay | group | No | |
BossHealthMultiplier | real | No | |
BossPowerMultiplier | real | No | |
CALLBACK_HANDLE | integer | No | |
ClassItemWhitelist | hashtable | No | |
ClassShopMap | hashtable | No | |
ClassShops | unit | Yes | |
ColorPrefixes | string | Yes | |
CONVERTED_ATTACK_TYPE | attacktype | Yes | |
CONVERTED_DAMAGE_TYPE | damagetype | Yes | |
CreepsInPlay | group | No | |
CURRENT_PLAYABLE_AREA | integer | No | |
CurrentPlayerAggro | player | No | |
DAMAGE_TYPE_ACID | integer | No | |
DAMAGE_TYPE_COLD | integer | No | |
DAMAGE_TYPE_DEATH | integer | No | |
DAMAGE_TYPE_DEFENSIVE | integer | No | |
DAMAGE_TYPE_DEMOLITION | integer | No | |
DAMAGE_TYPE_DISEASE | integer | No | |
DAMAGE_TYPE_DIVINE | integer | No | |
DAMAGE_TYPE_ENHANCED | integer | No | |
DAMAGE_TYPE_FIRE | integer | No | |
DAMAGE_TYPE_FORCE | integer | No | |
DAMAGE_TYPE_LIGHTNING | integer | No | |
DAMAGE_TYPE_MAGIC | integer | No | |
DAMAGE_TYPE_MIND | integer | No | |
DAMAGE_TYPE_NORMAL | integer | No | |
DAMAGE_TYPE_PLANT | integer | No | |
DAMAGE_TYPE_POISON | integer | No | |
DAMAGE_TYPE_SHADOW_STRIKE | integer | No | |
DAMAGE_TYPE_SLOW_POISON | integer | No | |
DAMAGE_TYPE_SONIC | integer | No | |
DAMAGE_TYPE_SPIRIT_LINK | integer | No | |
DAMAGE_TYPE_UNIVERSAL | integer | No | |
DAMAGE_TYPE_UNKNOWN | integer | No | |
DamageEvent | real | No | |
DamageEventAmount | real | No | |
DamageEventAOE | integer | No | |
DamageEventAOEGroup | group | No | |
DamageEventArmorPierced | real | No | |
DamageEventArmorT | integer | No | |
DamageEventAttackT | integer | No | |
DamageEventDamageT | integer | No | |
DamageEventDefenseT | integer | No | |
DamageEventLevel | integer | No | |
DamageEventOverride | boolean | No | |
DamageEventPrevAmt | real | No | |
DamageEventSource | unit | No | |
DamageEventTarget | unit | No | |
DamageEventType | integer | No | |
DamageEventWeaponT | integer | No | |
DamageFilterAttackT | integer | No | |
DamageFilterDamageT | integer | No | |
DamageFilterFailChance | real | No | |
DamageFilterMinAmount | real | No | |
DamageFilterRunChance | real | No | |
DamageFilterSource | unit | No | |
DamageFilterSourceA | abilcode | No | |
DamageFilterSourceB | buffcode | No | |
DamageFilterSourceC | integer | No | |
DamageFilterSourceI | itemcode | No | |
DamageFilterSourceT | unitcode | No | |
DamageFilterTarget | unit | No | |
DamageFilterTargetA | abilcode | No | |
DamageFilterTargetB | buffcode | No | |
DamageFilterTargetC | integer | No | |
DamageFilterTargetI | itemcode | No | |
DamageFilterTargetT | unitcode | No | |
DamageFilterType | integer | No | |
DamageModifierEvent | real | No | |
DamageScalingUser | real | No | |
DamageScalingWC3 | real | No | |
DamageTypeBlocked | integer | No | |
DamageTypeCode | integer | No | |
DamageTypeCriticalStrike | integer | No | |
DamageTypeDebugStr | string | Yes | |
DamageTypeExplosive | integer | No | |
DamageTypeHeal | integer | No | |
DamageTypePure | integer | No | |
DamageTypePureExplosive | integer | No | |
DamageTypeReduced | integer | No | |
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 | |
DifficultyChangeEnabled | boolean | No | true |
DmgDuration | real | No | |
DmgSize | real | No | |
DmgStr | string | No | |
DummyToHeroMap | hashtable | No | |
EnhancedDamageTarget | unit | No | |
ExtraCharacters | unit | Yes | |
Gladiators | group | No | |
GladiatorsInPlay | group | No | |
HealEventAmount | real | No | |
HealEventSource | unit | No | |
HealEventTarget | unit | No | |
HeroPicked | boolean | Yes | |
HeroPickers | integer | No | |
HumanPlayers | force | No | |
IsDamageAttack | boolean | No | |
IsDamageCode | boolean | No | |
IsDamageMelee | boolean | No | |
IsDamageRanged | boolean | No | |
IsDamageSpell | boolean | No | |
ItemListDefensePackage | integer | Yes | |
ItemListOffensePackage | integer | Yes | |
ItemListSupportPackage | integer | Yes | |
LastWaveIndex | integer | No | |
LethalDamageEvent | real | No | |
LethalDamageHP | real | No | |
LightningSMap | hashtable | No | |
MainHeroes | unit | Yes | UnitNull |
ManaEventAmount | real | No | |
ManaEventSource | unit | No | |
ManaEventTarget | unit | No | |
NextDamageIsAttack | boolean | No | |
NextDamageIsMelee | boolean | No | |
NextDamageIsRanged | boolean | No | |
NextDamageType | integer | No | |
NextDamageWeaponT | integer | No | |
NotifyRegistry | hashtable | No | |
OnDamageEvent | real | No | |
OnHealEvent | real | No | |
OnManaEvent | real | No | |
OnStunHandleId | integer | No | |
OnUnitSpawn | real | No | |
PHASE | integer | No | |
PickBoard | multiboard | No | |
Pickers | unit | Yes | UnitNull |
PlayerCount | integer | No | |
PreDamageEvent | real | No | |
PreloadGroup | group | No | |
QuestDiff | quest | No | |
QuestPick | quest | No | |
RemoveDamageEvent | boolean | No | |
RepickTempDisabled | boolean | Yes | |
RepickTimer | timer | No | |
ReviveStats | hashtable | No | |
SeniorPaladinPhase | integer | No | |
SourceDamageEvent | real | No | |
StoppableTimerEnabled | boolean | No | |
TEX | trigger | No | |
Timer_Difficulty_Prompt | timer | No | |
TimerExtraCharsVote | timer | No | |
TimerHub | timer | No | |
TimerHubWindow | timerdialog | No | |
TotalInWave | integer | No | |
TotalSent | integer | No | |
UnavailablePickMask | image | Yes | |
UniqueEffectsMap | hashtable | No | |
UNIT_CLASS_ANCIENT | integer | No | |
UNIT_CLASS_ATTACKS_FLYING | integer | No | |
UNIT_CLASS_ATTACKS_GROUND | integer | No | |
UNIT_CLASS_DEAD | integer | No | |
UNIT_CLASS_ETHEREAL | integer | No | |
UNIT_CLASS_FLYING | integer | No | |
UNIT_CLASS_GIANT | integer | No | |
UNIT_CLASS_GROUND | integer | No | |
UNIT_CLASS_HERO | integer | No | |
UNIT_CLASS_MAGIC_IMMUNE | integer | No | |
UNIT_CLASS_MECHANICAL | integer | No | |
UNIT_CLASS_MELEE | integer | No | |
UNIT_CLASS_PEON | integer | No | |
UNIT_CLASS_PLAGUED | integer | No | |
UNIT_CLASS_POISONED | integer | No | |
UNIT_CLASS_POLYMORPHED | integer | No | |
UNIT_CLASS_RANGED | integer | No | |
UNIT_CLASS_RESISTANT | integer | No | |
UNIT_CLASS_SAPPER | integer | No | |
UNIT_CLASS_SLEEPING | integer | No | |
UNIT_CLASS_SNARED | integer | No | |
UNIT_CLASS_STRUCTURE | integer | No | |
UNIT_CLASS_STUNNED | integer | No | |
UNIT_CLASS_SUMMONED | integer | No | |
UNIT_CLASS_TAUREN | integer | No | |
UNIT_CLASS_TOWNHALL | integer | No | |
UNIT_CLASS_UNDEAD | integer | No | |
UnitRewardMap | hashtable | No | |
UnitSpawned | unit | No | UnitNull |
UTIL_UNIT | unit | No | |
UtilMap | hashtable | No | |
Variant | integer | No | |
VoteMap | hashtable | No | |
VoteWeight | integer | No | 1 |
VotingAltars | unit | Yes | |
Wave | integer | No | |
WaveBehaviorMap | hashtable | No | |
WaveIndex | integer | No | |
Waves | integer | Yes | |
WaveSelectionBoard | multiboard | 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 | |
WHITELIST_KEY_CONST | integer | No | |
ZeroDamageEvent | real | No |
struct CreditsToPlayer
private unit u
private player p
private integer i = 0
private method periodic takes nothing returns nothing
if ModuloInteger(T32_Tick, 32) == 0 and UnitAlive(u) then
call DisplayTimedTextToPlayer(p, GetUnitX(u), GetUnitY(u), 2, Credits.entries[i])
set i = i + 1
endif
if i == Credits.size then
set p = p
set u = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes unit u, player p returns thistype
local thistype this = thistype.allocate()
set this.u = u
set this.p = p
return this
endmethod
endstruct
struct Credits
public static integer size = 0
public static string array entries[100]
static method create takes integer utype, string prompt returns thistype
local thistype this = thistype.allocate()
return this
endmethod
static method push takes string s returns nothing
set entries[size] = s
set size = size + 1
endmethod
endstruct
function Trig_PLAY_CREDITS_Actions takes nothing returns nothing
local unit u = GetTriggerUnit()
local player p = GetOwningPlayer(u)
local integer i = 0
call CreditsToPlayer.create(u, p).startPeriodic()
set u = null
set p = null
endfunction
//===========================================================================
function InitTrig_PLAY_CREDITS takes nothing returns nothing
set gg_trg_PLAY_CREDITS = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_PLAY_CREDITS, gg_rct_CREDITS )
call TriggerAddAction( gg_trg_PLAY_CREDITS, function Trig_PLAY_CREDITS_Actions )
endfunction
function AngleBetweenUnits takes unit a, unit b returns real
return bj_RADTODEG * Atan2(GetUnitY(b) - GetUnitY(a), GetUnitX(b) - GetUnitX(a))
endfunction
function True_Filter takes nothing returns boolean
return true
endfunction
function EAnI_Filter takes nothing returns boolean // Enemy_Alive_NotInvul_Filter
local boolean retval
local unit u = GetFilterUnit()
local player p = GetOwningPlayer(GetTriggerUnit())
set retval = IsUnitEnemy(u,p) and UnitAlive(u) and GetUnitAbilityLevel(u,'Avul') < 1
set u = null
set p = null
return retval
endfunction
function AAnI_Filter takes nothing returns boolean // ally_Alive_NotInvul_Filter
local boolean retval
local unit u = GetFilterUnit()
local player p = GetOwningPlayer(GetTriggerUnit())
set retval = IsUnitAlly(u,p) and UnitAlive(u) and GetUnitAbilityLevel(u,'Avul') < 1
set u = null
set p = null
return retval
endfunction
function EAnI_FilterAttacker takes nothing returns boolean // Enemy_Alive_NotInvul_Filter
local boolean retval
local unit u = GetFilterUnit()
local player p = GetOwningPlayer(GetAttacker())
set retval = IsUnitEnemy(u,p) and UnitAlive(u) and GetUnitAbilityLevel(u,'Avul') < 1
set u = null
set p = null
return retval
endfunction
function EAnI_FilterUdgUnit takes nothing returns boolean // Enemy_Alive_NotInvul_Filter
local boolean retval
local unit u = GetFilterUnit()
local player p = GetOwningPlayer(udg_UTIL_UNIT)
set retval = IsUnitEnemy(u,p) and UnitAlive(u) and GetUnitAbilityLevel(u,'Avul') < 1
set u = null
set p = null
return retval
endfunction
function randomEnemyInRange takes unit u, real range returns unit
local group g = CreateGroup()
local integer i
local integer size
local unit random = null
set udg_UTIL_UNIT = u
call GroupEnumUnitsInRange(g, GetUnitX(u), GetUnitY(u), range, function EAnI_FilterUdgUnit)
set size = BlzGroupGetSize(g) - 1
if size > 0 then
set i = GetRandomInt(0, size - 1)
set random = BlzGroupUnitAt(g, i)
endif
call DestroyGroup(g)
set g = null
return random
endfunction
function FarthestInRange takes real range, location center, player enemyP returns unit
local unit farthest = null
local real distanceF = 0
local real distanceC
local unit c
local group g = CreateGroup()
local location lc
call GroupEnumUnitsInRangeOfLoc(g, center, range, function True_Filter)
loop
set c = FirstOfGroup(g)
exitwhen c == null
call GroupRemoveUnit(g, c)
if (IsUnitEnemy(c, enemyP) and UnitAlive(c) and GetUnitAbilityLevel(c,'Avul') < 1 ) then
set lc = GetUnitLoc(c)
set distanceC = DistanceBetweenPoints(center, lc)
if (distanceC > distanceF) then
set distanceF = distanceC
set farthest = c
endif
call RemoveLocation(lc)
endif
endloop
call DestroyGroup(g)
set lc = null
set c = null
set g = null
return farthest
endfunction
function ClosestInRange takes real range, location center, player enemyP returns unit
local unit closest = null
local real distanceF = range + 1
local real distanceC
local unit c
local group g = CreateGroup()
local location lc
call GroupEnumUnitsInRangeOfLoc(g, center, range, function True_Filter)
loop
set c = FirstOfGroup(g)
exitwhen c == null
call GroupRemoveUnit(g, c)
if (IsUnitEnemy(c, enemyP) and UnitAlive(c) and GetUnitAbilityLevel(c,'Avul') < 1 ) then
set lc = GetUnitLoc(c)
set distanceC = DistanceBetweenPoints(center, lc)
if (distanceC < distanceF) then
set distanceF = distanceC
set closest = c
endif
call RemoveLocation(lc)
endif
endloop
call DestroyGroup(g)
set lc = null
set c = null
set g = null
return closest
endfunction
library ClearItems requires optional WorldBounds
/*
This library fixes the leak and the lag caused by unremoved items,
including powerups and manually-destroyed items.
The dead items are periodically removed. You can adjust the period by changing
the constant CLEANING_PERIOD. Note that items' death animations need some time
to play so adjust the DEATH_TIME delay accordingly.
If you don't know exactly what you are doing, you shouldn't change the life
of a dead item; the items are no longer usable after their death but
you can still change their life. If you set their life to more than 0.405,
they won't be properly cleaned. You should also remove items manually
if you kill them when they are carried by a unit.
*/
globals
// Interval between item-cleanups.
private constant real CLEANING_PERIOD = 15
// Time for the item's death animation, optimized for tomes and runes.
private constant real DEATH_TIME = 1.5
endglobals
globals
private keyword S
private integer N = 0
private code s_code
private boolexpr s_bool
private timer s_timer = CreateTimer()
private item array I
endglobals
private function DeleteItems takes nothing returns nothing
loop
set N = N - 1
call SetWidgetLife(I[N], 1)
call RemoveItem(I[N])
set I[N] = null
exitwhen (N == 0)
endloop
call TimerStart(s_timer, CLEANING_PERIOD - DEATH_TIME, true, s_code)
endfunction
private function CleanItems takes nothing returns boolean
if (GetWidgetLife(GetFilterItem()) < 0.405) then
set I[N] = GetFilterItem()
set N = N + 1
endif
return false
endfunction
private function SweepItems takes nothing returns nothing
//call BJDebugMsg("working")
static if (LIBRARY_WorldBounds) then
call EnumItemsInRect(WorldBounds.world, s_bool, null)
else
call EnumItemsInRect(S.world, s_bool, null)
endif
if (N > 0) then
call TimerStart(s_timer, DEATH_TIME, false, function DeleteItems)
endif
endfunction
private struct S extends array
static if (not LIBRARY_WorldBounds) then
static rect world
endif
static method onInit takes nothing returns nothing
static if (not LIBRARY_WorldBounds) then
set world = GetWorldBounds()
endif
set s_code = function SweepItems
set s_bool = Filter(function CleanItems)
call TimerStart(s_timer, CLEANING_PERIOD, true, s_code)
endmethod
endstruct
endlibrary
function FindAggroUIndex takes integer k, unit u returns integer
local integer i = 0
local integer indexFound = -1
local integer count = LoadInteger(udg_WaveBehaviorMap, k, 9)
loop
exitwhen i == count
if LoadUnitHandle(udg_WaveBehaviorMap, k, 10 + i * 2) == u then
set indexFound = 10 + i * 2
exitwhen true
endif
set i = i + 1
endloop
return indexFound
endfunction
function GetAggro takes integer k, unit u returns real
local integer i = 0
local integer count = 0
local real prev = 0
local integer indexFound = FindAggroUIndex(k, u)
set count = LoadInteger(udg_WaveBehaviorMap, k, 9)
if indexFound > 9 then //update
return LoadReal(udg_WaveBehaviorMap, k , indexFound + 1)
endif
return 0.0
endfunction
function AddAggro takes integer k, unit u, real amount returns nothing
local integer i = 0
local integer count = 0
local real prev = 0
local integer indexFound = FindAggroUIndex(k, u)
/*if GetUnitAbilityLevel(u, 'A034') > 0 then
set multi = 0.2
endif*/
set count = LoadInteger(udg_WaveBehaviorMap, k, 9)
if indexFound > 9 then //update
set prev = LoadReal(udg_WaveBehaviorMap, k , indexFound + 1)
call SaveReal(udg_WaveBehaviorMap, k , indexFound + 1, prev + amount)
else //insert
call SaveInteger(udg_WaveBehaviorMap, k , 9, count + 1)
call SaveUnitHandle(udg_WaveBehaviorMap, k , 10 + count * 2, u)
call SaveReal(udg_WaveBehaviorMap, k , 10 + count * 2 + 1, amount)
endif
endfunction
// null if all aggro <= 0
function highestAggroInRange takes unit u, real range returns unit
local group g = CreateGroup()
local unit gu
local unit umax = null
local real max = -1
local integer index = -1
local player p = GetOwningPlayer(u)
local integer k = GetHandleId(u)
local integer count
local real prev
local integer i = 0
call GroupEnumUnitsInRange(g, GetUnitX(u), GetUnitY(u), range, function True_Filter)
loop
set gu = FirstOfGroup(g)
exitwhen gu == null
call GroupRemoveUnit(g, gu)
if (IsUnitEnemy(gu, p) and UnitAlive(gu) and GetUnitAbilityLevel(gu,'Avul') < 1 ) then
set index = FindAggroUIndex(k, gu)
if index > 9 then
if max < LoadReal(udg_WaveBehaviorMap, k, index + 1) then
set max = LoadReal(udg_WaveBehaviorMap, k, index + 1)
set umax = gu
endif
endif
endif
endloop
call DestroyGroup(g)
set g = null
set gu = null
if max > 0 then
return umax
endif
return null
endfunction
function ExecuteBoolexpUnit takes boolexpr be, unit u returns nothing
local triggercondition tc = TriggerAddCondition(udg_TEX, be)
//call BJDebugMsg(I2S(GetHandleId(be)))
//call BJDebugMsg(I2S(GetHandleId(tc)))
set udg_CALLBACK_HANDLE = GetHandleId(tc)
call SaveUnitHandle(udg_UtilMap, udg_CALLBACK_HANDLE, 0, u)
call TriggerEvaluate(udg_TEX)
call FlushChildHashtable(udg_UtilMap, udg_CALLBACK_HANDLE)
call TriggerRemoveCondition(udg_TEX, tc)
set tc = null
endfunction
function B2S takes boolean b returns string
if b then
return "true"
endif
return "false"
endfunction
function RestoreMana takes unit caster, unit target, real desiredAmount returns real restoredAmount
local real max
local real curMana
local real restoration
local effect se
set curMana= GetUnitState(target, UNIT_STATE_MANA)
set max = GetUnitState(target, UNIT_STATE_MAX_MANA) - curMana
set restoration = desiredAmount
if (desiredAmount > max) then
set restoration = max
endif
call SetUnitManaBJ(target, (curMana + restoration))
set udg_ManaEventAmount = restoration
set udg_ManaEventSource = caster
set udg_ManaEventTarget = target
set udg_OnManaEvent = 0.00
set udg_OnManaEvent = 1.00
set se = AddSpecialEffectTarget("Abilities\\Spells\\Other\\ANrl\\ANrlTarget.mdl", target, "overhead")
call DestroyAfterSpecialEffect.create(0.2, se).startPeriodic()
set se = null
return restoration
endfunction
function RestoreHealth takes unit caster, unit target, real desiredAmount returns real
local real max
local real curHp
local real restoration
set curHp= GetUnitState(target, UNIT_STATE_LIFE)
set max = GetUnitState(target, UNIT_STATE_MAX_LIFE) - curHp
set restoration = desiredAmount
if (desiredAmount > max) then
set restoration = max
endif
call SetUnitState(target, UNIT_STATE_LIFE, curHp + restoration)
set udg_HealEventAmount = restoration
set udg_HealEventSource = caster
set udg_HealEventTarget = target
set udg_OnHealEvent = 0.00
set udg_OnHealEvent = 1.00
return restoration
endfunction
function UnitDead takes unit u returns boolean
return UnitAlive(u) == false
endfunction
//hmmmm again
function IsUnitDead takes unit u returns boolean
return GetUnitTypeId(u) == 0 or IsUnitType(u, UNIT_TYPE_DEAD)
endfunction
function IsUnitAlive takes unit u returns boolean
return not IsUnitDead(u)
endfunction
function BossPrompt takes unit u, string prompt returns nothing
local texttag tt = CreateTextTag()
call SetTextTagTextBJ(tt, prompt, 12)
call SetTextTagPos(tt, GetUnitX(u), GetUnitY(u), 0)
call SetTextTagColor(tt, 0xff, 0x45, 0x00, 0xdf)
call SetTextTagPermanent(tt, false)
call SetTextTagLifespan(tt, 2.5)
set tt = null
endfunction
function UnitPrompt takes unit u, string prompt returns nothing
local texttag tt = CreateTextTag()
call SetTextTagTextBJ(tt, prompt, 10)
call SetTextTagPos(tt, GetUnitX(u), GetUnitY(u), 0)
call SetTextTagColor(tt, 0xff, 0x67, 0x2e, 0xdf)
call SetTextTagPermanent(tt, false)
call SetTextTagLifespan(tt, 2)
set tt = null
endfunction
function PolarProjectionUU takes unit source, unit target, real dist, real angle returns nothing
local real x = GetUnitX(source) + dist * Cos(angle * bj_DEGTORAD)
local real y = GetUnitY(source) + dist * Sin(angle * bj_DEGTORAD)
call SetUnitPosition(target, x, y)
endfunction
function PolarProjectionU takes unit source, real dist, real angle returns location l
local real x = GetUnitX(source) + dist * Cos(angle * bj_DEGTORAD)
local real y = GetUnitY(source) + dist * Sin(angle * bj_DEGTORAD)
return Location(x, y)
endfunction
function DistanceBetweenUnits takes unit locA, unit locB returns real
local real dx = GetUnitX(locB) - GetUnitX(locA)
local real dy = GetUnitY(locB) - GetUnitY(locA)
return SquareRoot(dx * dx + dy * dy)
endfunction
function PreloadUnit takes integer unitcode returns unit
local unit u = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), unitcode, GetRandomReal(GetRectMinX(gg_rct_BLACKMAGIC), GetRectMaxX(gg_rct_BLACKMAGIC)), GetRandomReal(GetRectMinY(gg_rct_BLACKMAGIC), GetRectMaxY(gg_rct_BLACKMAGIC)), bj_UNIT_FACING)
call GroupAddUnit(udg_PreloadGroup, u)
return u
endfunction
function Trig_LEVELS_CHEAT_Conditions takes nothing returns boolean
return GetPlayerName(GetTriggerPlayer()) == "Riky#2398" or GetPlayerName(GetTriggerPlayer()) == "WorldEdit"
//return true
endfunction
function Trig_LEVELS_CHEAT_Actions takes nothing returns nothing
local integer i = 0
local unit u
loop
exitwhen i == 10
set u = udg_MainHeroes[i]
if (u != null) then
call SetHeroLevel(u, GetHeroLevel(u) + 10, true)
endif
set i = i + 1
endloop
endfunction
//===========================================================================
function InitTrig_LEVELS_CHEAT takes nothing returns nothing
local integer i = 0
set gg_trg_LEVELS_CHEAT = CreateTrigger()
call TriggerRegisterPlayerChatEvent(gg_trg_LEVELS_CHEAT, Player(0), "LEVELS", true)
call TriggerAddCondition(gg_trg_LEVELS_CHEAT, Condition(function Trig_LEVELS_CHEAT_Conditions))
call TriggerAddAction(gg_trg_LEVELS_CHEAT, function Trig_LEVELS_CHEAT_Actions)
endfunction
function Trig_SET_WAVE_CHEAT_Conditions takes nothing returns boolean
return GetPlayerName(GetTriggerPlayer()) == "Riky#2398" or GetPlayerName(GetTriggerPlayer()) == "WorldEdit"
//return true
endfunction
function Trig_SET_WAVE_CHEAT_Actions takes nothing returns nothing
local integer len
local string arg
local integer target
local string message = GetEventPlayerChatString()
set len = StringLength(message)
set arg = SubString(message, 6, len)
set target = S2I(arg)
if (target > 0 and target < 11) then
set udg_WaveIndex = target - 1
call ExecuteFunc("Trig_CREATE_WAVE_SELECTION_Actions")
endif
endfunction
//===========================================================================
function InitTrig_SET_WAVE_CHEAT takes nothing returns nothing
local integer i = 0
set gg_trg_SET_WAVE_CHEAT = CreateTrigger()
call TriggerRegisterPlayerChatEvent(gg_trg_SET_WAVE_CHEAT, Player(0), "-wave ", false)
call TriggerAddCondition(gg_trg_SET_WAVE_CHEAT, Condition(function Trig_SET_WAVE_CHEAT_Conditions))
call TriggerAddAction(gg_trg_SET_WAVE_CHEAT, function Trig_SET_WAVE_CHEAT_Actions)
endfunction
function SetDifficulty takes integer diff, boolean showPrompt returns nothing
local Difficulty d = diff
set Difficulty.current = d
set Difficulty.level = Difficulty.current.diffLevel
if showPrompt then
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "Difficulty set to " + d.name)
endif
endfunction
function Trig_SET_DIFFICULTY_EASY_Conditions takes nothing returns boolean
return udg_DifficultyChangeEnabled
endfunction
function Trig_SET_DIFFICULTY_EASY_Actions takes nothing returns nothing
call SetDifficulty(Difficulty.easy, true)
endfunction
//===========================================================================
function InitTrig_SET_DIFFICULTY_EASY takes nothing returns nothing
set gg_trg_SET_DIFFICULTY_EASY = CreateTrigger()
call TriggerRegisterPlayerChatEvent(gg_trg_SET_DIFFICULTY_EASY, Player(0), "-solo", false)
call TriggerAddCondition(gg_trg_SET_DIFFICULTY_EASY, Condition(function Trig_SET_DIFFICULTY_EASY_Conditions))
call TriggerAddAction(gg_trg_SET_DIFFICULTY_EASY, function Trig_SET_DIFFICULTY_EASY_Actions)
endfunction
function Trig_SET_DIFFICULTY_NORMAL_Conditions takes nothing returns boolean
return udg_DifficultyChangeEnabled
endfunction
function Trig_SET_DIFFICULTY_NORMAL_Actions takes nothing returns nothing
call SetDifficulty(Difficulty.normal, true)
endfunction
//===========================================================================
function InitTrig_SET_DIFFICULTY_NORMAL takes nothing returns nothing
set gg_trg_SET_DIFFICULTY_NORMAL = CreateTrigger()
call TriggerRegisterPlayerChatEvent(gg_trg_SET_DIFFICULTY_NORMAL, Player(0), "-normal", false)
call TriggerAddCondition(gg_trg_SET_DIFFICULTY_NORMAL, Condition(function Trig_SET_DIFFICULTY_NORMAL_Conditions))
call TriggerAddAction(gg_trg_SET_DIFFICULTY_NORMAL, function Trig_SET_DIFFICULTY_NORMAL_Actions)
endfunction
function Trig_SET_DIFFICULTY_HARD_Conditions takes nothing returns boolean
return udg_DifficultyChangeEnabled //and GetPlayerName(GetTriggerPlayer()) == "Riky#2398"
endfunction
function Trig_SET_DIFFICULTY_HARD_Actions takes nothing returns nothing
call SetDifficulty(Difficulty.hard, true)
endfunction
//===========================================================================
function InitTrig_SET_DIFFICULTY_HARD takes nothing returns nothing
set gg_trg_SET_DIFFICULTY_HARD = CreateTrigger()
call TriggerRegisterPlayerChatEvent(gg_trg_SET_DIFFICULTY_HARD, Player(0), "-hard", false)
call TriggerAddCondition(gg_trg_SET_DIFFICULTY_HARD, Condition(function Trig_SET_DIFFICULTY_HARD_Conditions))
call TriggerAddAction(gg_trg_SET_DIFFICULTY_HARD, function Trig_SET_DIFFICULTY_HARD_Actions)
endfunction
function Trig_GOLD_CHEAT_Conditions takes nothing returns boolean
return GetPlayerName(GetTriggerPlayer()) == "Riky#2398" or GetPlayerName(GetTriggerPlayer()) == "WorldEdit"
//return true
endfunction
function Trig_GOLD_CHEAT_Actions takes nothing returns nothing
local integer i = 0
local unit u
loop
exitwhen i == 10
set u = udg_MainHeroes[i]
if (u != null) then
call SetPlayerState(Player(i), PLAYER_STATE_RESOURCE_GOLD, 5000)
endif
set i = i + 1
endloop
endfunction
//===========================================================================
function InitTrig_GOLD_CHEAT takes nothing returns nothing
local integer i = 0
set gg_trg_GOLD_CHEAT = CreateTrigger()
call TriggerRegisterPlayerChatEvent(gg_trg_GOLD_CHEAT, Player(0), "GOLD", true)
call TriggerAddCondition(gg_trg_GOLD_CHEAT, Condition(function Trig_GOLD_CHEAT_Conditions))
call TriggerAddAction(gg_trg_GOLD_CHEAT, function Trig_GOLD_CHEAT_Actions)
endfunction
function Trig_REPICK_Actions takes nothing returns nothing
local player p = GetTriggerPlayer()
local integer id = GetPlayerId(p)
local unit u
local location l
local location pp
local HeroPickers hps = udg_HeroPickers
local HeroPicker hp
if (udg_RepickTempDisabled[id]) then
call DisplayTextToPlayer(p, 0, 0, "Repick is temporary disabled")
elseif (udg_MainHeroes[id] != null) then
set u = udg_MainHeroes[id]
set l = GetUnitLoc(u)
set pp = PolarProjectionBJ(l, 150, 180)
call PauseTimer(udg_RepickTimer)
call SetUnitPositionLoc(u, pp)
call AddSpecialEffectLocBJ( l, "Abilities\\Spells\\Other\\Charm\\CharmTarget.mdl" )
call DestroyEffect( GetLastCreatedEffectBJ() )
call AddSpecialEffectLocBJ( pp, "Abilities\\Spells\\Other\\Charm\\CharmTarget.mdl" )
call DestroyEffect( GetLastCreatedEffectBJ() )
set hp = hps.heroPickers[GetRandomInt(0, hps.size - 1)]
call ReplaceUnitBJ( u, hp.pickerType, bj_UNIT_STATE_METHOD_MAXIMUM )
set u = GetLastReplacedUnitBJ()
call SelectUnitForPlayerSingle(u, p)
set udg_MainHeroes[id] = null
set udg_HeroPicked[id] = false
set udg_Pickers[id] = u
call buildPrompt(hp, p)
call TriggerExecute(gg_trg_UPDATE_PICK_BOARD)
call RemoveLocation(l)
call RemoveLocation(pp)
set pp = null
set l = null
set u = null
set p = null
endif
endfunction
//===========================================================================
function InitTrig_REPICK takes nothing returns nothing
local integer i = 0
set gg_trg_REPICK = CreateTrigger( )
loop
exitwhen i == 10
call TriggerRegisterPlayerChatEvent( gg_trg_REPICK, Player(i), "repick", true )
call TriggerRegisterPlayerChatEvent( gg_trg_REPICK, Player(i), "-repick", true )
set i = i + 1
endloop
call TriggerAddAction( gg_trg_REPICK, function Trig_REPICK_Actions )
endfunction
function Trig_SHOW_AGGRO_Actions takes nothing returns nothing
local player p = GetTriggerPlayer()
local integer id = GetPlayerId(p)
set udg_AggroTextOn[id] = true
endfunction
//===========================================================================
function InitTrig_SHOW_AGGRO takes nothing returns nothing
local integer i = 0
set gg_trg_SHOW_AGGRO = CreateTrigger( )
loop
exitwhen i == 10
call TriggerRegisterPlayerChatEvent( gg_trg_SHOW_AGGRO, Player(i), "showaggro", true )
call TriggerRegisterPlayerChatEvent( gg_trg_SHOW_AGGRO, Player(i), "-showaggro", true )
set i = i + 1
endloop
call TriggerAddAction( gg_trg_SHOW_AGGRO, function Trig_SHOW_AGGRO_Actions )
endfunction
function Trig_HIDE_AGGRO_Actions takes nothing returns nothing
local player p = GetTriggerPlayer()
local integer id = GetPlayerId(p)
set udg_AggroTextOn[id] = false
endfunction
//===========================================================================
function InitTrig_HIDE_AGGRO takes nothing returns nothing
local integer i = 0
set gg_trg_HIDE_AGGRO = CreateTrigger( )
loop
exitwhen i == 10
call TriggerRegisterPlayerChatEvent( gg_trg_HIDE_AGGRO, Player(i), "hideaggro", true )
call TriggerRegisterPlayerChatEvent( gg_trg_HIDE_AGGRO, Player(i), "-hideaggro", true )
set i = i + 1
endloop
call TriggerAddAction( gg_trg_HIDE_AGGRO, function Trig_HIDE_AGGRO_Actions )
endfunction
function Trig_KICK_Conditions takes nothing returns boolean
return GetPlayerName(GetTriggerPlayer()) == "Riky#2398"
//return true
endfunction
function Trig_KICK_Actions takes nothing returns nothing
local integer len
local string arg
local integer target
local string message = GetEventPlayerChatString()
set len = StringLength(message)
set arg = SubString(message, 6, len)
set target = S2I(arg)
/* local player p = GetTriggerPlayer()
local integer id = GetPlayerId(p)
call DisplayTextToForce(GetPlayersAll(), "Player " + udg_ColorPrefixes[GetPlayerId(p)] + GetPlayerName(GetTriggerPlayer()) + "|r has left the game")
set udg_MainHeroes[id] = null
set udg_HeroPicked[id] = false
set bj_wantDestroyGroup = true
call ForGroupBJ(GetUnitsOfPlayerAll(p), function Trig_DC1_Func001A )
call ForceRemovePlayer(udg_HumanPlayers, p)
set p = null
call TriggerExecute(gg_trg_DC)*/
if (target > 0 and target < 11) then
if GetLocalPlayer() == Player(target - 1) then
call EndGame(true)
endif
//call CustomDefeatBJ( ConvertedPlayer(target), "KICKED BY HOST")
endif
endfunction
//===========================================================================
function InitTrig_KICK takes nothing returns nothing
set gg_trg_KICK = CreateTrigger( )
call TriggerRegisterPlayerChatEvent( gg_trg_KICK, ConvertedPlayer(1), "-kick ", false )
call TriggerAddCondition( gg_trg_KICK, Condition( function Trig_KICK_Conditions ) )
call TriggerAddAction( gg_trg_KICK, function Trig_KICK_Actions )
endfunction
library BoundSentinel initializer init
//*************************************************
//* BoundSentinel
//* -------------
//* Don't leave your units unsupervised, naughty
//* them may try to get out of the map bounds and
//* crash your game.
//*
//* To implement, just get a vJass compiler and
//* copy this library/trigger to your map.
//*
//*************************************************
//==================================================
//=========================================================================================
globals
private constant boolean ALLOW_OUTSIDE_PLAYABLE_MAP_AREA = false
private real maxx
private real maxy
private real minx
private real miny
endglobals
//=======================================================================
private function dis takes nothing returns boolean
local unit u=GetTriggerUnit()
local real x=GetUnitX(u)
local real y=GetUnitY(u)
if(x>maxx) then
set x=maxx
elseif(x<minx) then
set x=minx
endif
if(y>maxy) then
set y=maxy
elseif(y<miny) then
set y=miny
endif
call SetUnitX(u,x)
call SetUnitY(u,y)
set u=null
return false
endfunction
private function init takes nothing returns nothing
local trigger t = CreateTrigger()
local region r = CreateRegion()
local rect map
local rect rc
if ALLOW_OUTSIDE_PLAYABLE_MAP_AREA then
set map = GetWorldBounds()
else
set map = bj_mapInitialPlayableArea
endif
set minx = GetRectMinX(map)
set miny = GetRectMinY(map)
set maxx = GetRectMaxX(map)
set maxy = GetRectMaxY(map)
set rc=Rect(minx,miny,maxx,maxy)
call RegionAddRect(r, rc)
call RemoveRect(rc)
if ALLOW_OUTSIDE_PLAYABLE_MAP_AREA then
call RemoveRect(map)
endif
call TriggerRegisterLeaveRegion(t,r, null)
call TriggerAddCondition(t, Condition(function dis))
set rc=null
set map = null
endfunction
endlibrary
library xebasic
//**************************************************************************
//
// xebasic 0.4
// =======
// XE_DUMMY_UNITID : Rawcode of the dummy unit in your map. It should
// use the dummy.mdx model, so remember to import it as
// well, just use copy&paste to copy the dummy from the
// xe map to yours, then change the rawcode.
//
// XE_HEIGHT_ENABLER: Medivh's raven form ability, you may need to change
// this rawcode to another spell that morphs into a flier
// in case you modified medivh's spell in your map.
//
// XE_TREE_RECOGNITION: The ancients' Eat tree ability, same as with medivh
// raven form, you might have to change it.
//
// XE_ANIMATION_PERIOD: The global period of animation used by whatever
// timer that depends on it, if you put a low value
// the movement will look good but it may hurt your
// performance, if instead you use a high value it
// will not lag but will be fast.
//
// XE_MAX_COLLISION_SIZE: The maximum unit collision size in your map, if
// you got a unit bigger than 197.0 it would be
// a good idea to update this constant, since some
// enums will not find it. Likewise, if none of
// your units can go bellow X and X is much smaller
// than 197.0, it would be a good idea to update
// as well, since it will improve the performance
// those enums.
//
// Notice you probably don't have to update this library, unless I specify
// there are new constants which would be unlikely.
//
//**************************************************************************
//===========================================================================
globals
constant integer XE_DUMMY_UNITID = 'h005'
constant integer XE_HEIGHT_ENABLER = 'Amrf'
constant integer XE_TREE_RECOGNITION = 'Aeat'
constant real XE_ANIMATION_PERIOD = 0.025
constant real XE_MAX_COLLISION_SIZE = 197.0
endglobals
endlibrary
library xepreload requires xebasic, optional TimerUtils
//******************************************************************************
// xepreload 0.9
// ---------
// Ah, the joy of preloading abilities, it is such a necessary evil...
// Notice you are not supposed to use this system in places outside map init
//
// This one does the preloading and tries to minimize the hit on loading time
// for example, it only needs one single native call per ability preloaded.
//
//******************************************************************************
//==============================================================================
globals
private unit dum=null
endglobals
private keyword DebugIdInteger2IdString
//inline friendly (when debug mode is off..)
function XE_PreloadAbility takes integer abilid returns nothing
call UnitAddAbility(dum, abilid)
static if DEBUG_MODE then
if(dum==null) then
call BJDebugMsg("XE_PreloadAbility: do not load abilities after map init or during modules' onInit")
elseif GetUnitAbilityLevel(dum, abilid) == 0 then
call BJDebugMsg("XE_PreloadAbility: Ability "+DebugIdInteger2IdString.evaluate(abilid)+" does not exist.")
endif
endif
endfunction
// ................................................................................
//================================================================================
// Convert a integer id value into a 4-letter id code.
// * Taken from cheats.j so I don't have to code it again.
// * Used only on debug so making a whole library for it seemed silly
// * Private so people don't begin using xepreload just to call this function....
// * It will not work correctly if you paste this code in the custom script section
// due to the infamous % bug. Then again, if you do that then you probably
// deserve it....
//
private function DebugIdInteger2IdString takes integer value returns string
local string charMap = ".................................!.#$%&'()*+,-./0123456789:;<=>.@ABCDEFGHIJKLMNOPQRSTUVWXYZ[.]^_`abcdefghijklmnopqrstuvwxyz{|}~................................................................................................................................."
local string result = ""
local integer remainingValue = value
local integer charValue
local integer byteno
set byteno = 0
loop
set charValue = ModuloInteger(remainingValue, 256)
set remainingValue = remainingValue / 256
set result = SubString(charMap, charValue, charValue + 1) + result
set byteno = byteno + 1
exitwhen byteno == 4
endloop
return result
endfunction
//--------------------------------
private function kill takes nothing returns nothing
call RemoveUnit(dum)
set dum=null
static if (LIBRARY_TimerUtils ) then
call ReleaseTimer( GetExpiredTimer() )
else
call DestroyTimer(GetExpiredTimer())
endif
endfunction
private struct init extends array
private static method onInit takes nothing returns nothing
local timer t
set dum = CreateUnit( Player(15), XE_DUMMY_UNITID, 0,0,0)
if( dum == null) then
debug call BJDebugMsg("xePreload : XE_DUMMY_UNITID ("+DebugIdInteger2IdString.evaluate(XE_DUMMY_UNITID)+") not added correctly to the map.")
endif
static if (LIBRARY_TimerUtils) then
set t=NewTimer()
else
set t=CreateTimer()
endif
call TimerStart(t,0.0,false,function kill)
set t=null
endmethod
endstruct
endlibrary
library xedummy requires xebasic
//******************************************************************************
// xedummy 0.9
// ------
// For all your xe dummy recycling needs.
//
//******************************************************************************
//==============================================================================
globals
// The number of different angles at which the dummy units will be stored.
private constant integer ANGLE_RESOLUTION = 12
// The total number of xe dummy units that will be preloaded on map initialization.
private constant integer INITIAL_DUMMY_COUNT = 36
// Don't allow to keep more than DUMMY_STACK_LIMIT inactive dummy units.
private constant integer DUMMY_STACK_LIMIT = 240
endglobals
// END OF CALIBRATION SECTION
// ================================================================
private keyword xedummy
private struct recycleQueue extends array
recycleQueue next
recycleQueue prev
real angle
integer size
xedummy first
xedummy last
static method onInit takes nothing returns nothing
local integer i=0
loop
exitwhen i==ANGLE_RESOLUTION
set i=i+1
set recycleQueue(i).prev=recycleQueue(i-1)
set recycleQueue(i).next=recycleQueue(i+1)
set recycleQueue(i).angle=(i-0.5)*(360.0/ANGLE_RESOLUTION)
endloop
set recycleQueue(1).prev=recycleQueue(i)
set recycleQueue(i).next=recycleQueue(1)
endmethod
static method get takes real angle returns recycleQueue
return recycleQueue(R2I(angle/360.0*ANGLE_RESOLUTION)+1)
endmethod
endstruct
// ================================================================
struct xedummy
private static group g=CreateGroup()
private unit u
// ----------------------------------------------------------------
private xedummy next
private method queueInsert takes recycleQueue q returns nothing
call SetUnitFacing(.u, q.angle)
if q.size==0 then
set q.first=this
else
set q.last.next=this
endif
set q.last=this
set .next=0
// Recursively check adajcent queues and migrate xedummies as needed.
if q.size>q.next.size then
set this=q.first
set q.first=.next
call .queueInsert(q.next)
elseif q.size>q.prev.size then
set this=q.first
set q.first=.next
call .queueInsert(q.prev)
else
set q.size=q.size+1
endif
endmethod
private static method queueRemove takes recycleQueue q returns xedummy
// Recursively check adajcent queues and migrate xedummies as needed.
local xedummy this
if q.size<q.next.size then
set this=q.last
set q.last=.queueRemove(q.next)
set .next=q.last
call SetUnitFacing(q.last.u, q.angle)
elseif q.size<q.prev.size then
set this=q.last
set q.last=.queueRemove(q.prev)
set .next=q.last
call SetUnitFacing(q.last.u, q.angle)
else
set q.size=q.size-1
if q.size==0 then
set q.last=0
endif
endif
set this=q.first
set q.first=.next
set .next=0
return this
endmethod
// ----------------------------------------------------------------
private static method create takes unit u returns xedummy
local xedummy this
if GetUnitTypeId(u)!=XE_DUMMY_UNITID then
debug call BJDebugMsg("ReleaseXEDummy error: Method called on a unit of an incorrect type.")
elseif IsUnitInGroup(u, .g) then
debug call BJDebugMsg("ReleaseXEDummy error: Method called on an already released unit.")
else
set this=.allocate()
if integer(this)>DUMMY_STACK_LIMIT then
call RemoveUnit(u)
call .deallocate()
return 0
endif
set .u=u
call GroupAddUnit(.g, u)
call .queueInsert(recycleQueue.get(GetUnitFacing(u)))
call SetUnitAnimationByIndex(u, 90)
call SetUnitScale(u, 1, 0, 0)
call SetUnitVertexColor(u, 255, 255, 255, 255)
// call ShowUnit(u, false) // Do not hide the unit, it is rather costly and not needed.
return this
endif
return 0
endmethod
private method destroy takes nothing returns nothing
call GroupRemoveUnit(.g, .u)
call ShowUnit(.u, true) // Show the unit in case it was hidden before being recycled.
set .u=null
call .deallocate()
endmethod
// ----------------------------------------------------------------
private static unit dummy
private static method onInit takes nothing returns nothing
local integer i=INITIAL_DUMMY_COUNT
local recycleQueue q=recycleQueue(1)
if i>DUMMY_STACK_LIMIT then
debug call BJDebugMsg("xedummy error: INITIAL_DUMMY_COUNT can not be larger than DUMMY_STACK_LIMIT.")
set i=DUMMY_STACK_LIMIT
endif
loop
exitwhen i==0
set .dummy = CreateUnit(Player(15), XE_DUMMY_UNITID, 0.0,0.0,q.angle)
call UnitAddAbility(.dummy,XE_HEIGHT_ENABLER)
call UnitAddAbility(.dummy,'Aloc')
call UnitRemoveAbility(.dummy,XE_HEIGHT_ENABLER)
call .create(.dummy)
set i=i-1
set q=q.next
endloop
endmethod
// ----------------------------------------------------------------
static method new takes player p, real x, real y, real face returns unit
local recycleQueue q
local xedummy this
loop
exitwhen face>0.0
set face=face+360.0
endloop
loop
exitwhen face<360.0
set face=face-360.0
endloop
set q=recycleQueue.get(face)
if q.size==0 then
set .dummy = CreateUnit(p, XE_DUMMY_UNITID, x,y,face)
call UnitAddAbility(.dummy,XE_HEIGHT_ENABLER)
call UnitAddAbility(.dummy,'Aloc')
call UnitRemoveAbility(.dummy,XE_HEIGHT_ENABLER)
call SetUnitX(.dummy, x)
call SetUnitY(.dummy, y)
else
set this=.queueRemove(q)
set .dummy=.u
call .destroy()
call SetUnitX(.dummy, x)
call SetUnitY(.dummy, y)
call SetUnitFacing(.dummy, face)
call SetUnitOwner(.dummy, p, true)
endif
return .dummy
endmethod
static method release takes unit u returns nothing
call .create(u)
endmethod
endstruct
// ================================================================
function XE_NewDummyUnit takes player p, real x, real y, real face returns unit
return xedummy.new( p,x,y,face )
endfunction
function XE_ReleaseDummyUnit takes unit u returns nothing
call xedummy.release( u )
endfunction
endlibrary
library xecast initializer init requires xebasic
//******************************************************************************
// xecast 0.9
// ------
// Because dummy casters REALLY ARE this complicated!
//
//******************************************************************************
//==============================================================================
globals
private constant integer MAXINSTANCES = 8190
//this is a lot, unless you leak xecast objects (which is a bad thing)
private constant integer INITIAL_DUMMY_COUNT = 12
//don't allow to keep more than DUMMY_STACK_LIMIT innactive dummy units :
private constant integer DUMMY_STACK_LIMIT = 50
// If your map does not give visibility to all players, or
// for other reasons, you might want xecast to work on
// units that are not visible to the player, in that case
// change this to true, else it is just a performance loss.
private constant boolean FORCE_INVISIBLE_CAST = false
//When AUTO_RESET_MANA_COOLDOWN is set to true, xecast will reset
// the dummy unit's cooldown and mana before casting every spell.
// it is a performance penalty, so if you are sure that all dummy spells
// in your map got 0 mana and cooldown cost, you may set it to false.
private constant boolean AUTO_RESET_MANA_COOLDOWN = true
endglobals
//=========================================================================
// Please notice all textmacros in this library are considered private.
// in other words: DON'T RUN THOSE TEXTMACROS!
//
private keyword structinit
globals
private real EPSILON=0.001 //noticed in war3 this is the sort of precision we want...
endglobals
struct xecast[MAXINSTANCES]
public integer abilityid = 0 //ID (rawcode) of the ability to cast
public integer level = 1 //Level of the ability to cast
public real recycledelay = 0.0 //Please notice, some spells need a recycle delay
// This is, a time period before they get recycle.
// For example, some spells are not instant, there is
// also the problem with damaging spells, this recycle
// delay must be large enough to contain all the time
// in which the spell can do damage.
public player owningplayer=Player(15) //which player to credit for the ability cast?
//notice this can also affect what units are targeteable
//==================================================================================================
// You need an order id for the ability so the dummy unit is able to cast it, two ways to assign it
// set instance.orderid = 288883 //would assign an integer orderid
// set instance.orderstring = "chainlightning" //would assign an orderstring
// (as those in the object editor)
//
method operator orderid= takes integer v returns nothing
set .oid=v
endmethod
method operator orderstring= takes string s returns nothing
set .oid=OrderId(s)
endmethod
//=================================================================================================
// Finally, you can determine from which point to cast the ability: z is the height coordinate.
//
public boolean customsource=false //Use a custom casting source?
public real sourcex // Determine the casting source for the dummy spell, require customsource =true
public real sourcey // You might prefer to use the setSourcePoint method
public real sourcez=0.0 //
method setSourcePoint takes real x, real y, real z returns nothing
set .sourcex=x
set .sourcey=y
set .sourcez=z
set .customsource=true
endmethod
method setSourceLoc takes location loc, real z returns nothing
set .sourcex=GetLocationX(loc)
set .sourcey=GetLocationY(loc)
set .sourcez=z
set .customsource=true
endmethod
private boolean autodestroy = false
//========================================================================================================
// you are always allowed to use .create() but you can also use createBasic which sets some things that
// are usually necessary up.
//
public static method createBasic takes integer abilityID, integer orderid, player owner returns xecast
local xecast r=xecast.allocate()
if(r==0) then
debug call BJDebugMsg("Warning: unbelievable but you actually used all xecast instances in your map! Please make sure you are not forgetting to destroy those what you create intensively, if that's not the case, then you'll have to increase xecast MAXINSTANCES")
endif
set r.oid=orderid
set r.abilityid=abilityID
set r.owningplayer=owner
return r
endmethod
//========================================================================================================
// Just like the above one, but the instance will self destruct after a call to any cast method
// (recommended)
//
public static method createBasicA takes integer abilityID, integer orderid, player owner returns xecast
local xecast r=xecast.allocate()
if(r==0) then
debug call BJDebugMsg("Warning: unbelievable but you actually used all xecast instances in your map! Please make sure you are not forgetting to destroy those what you create intensively, if that's not the case, then you'll have to increase xecast MAXINSTANCES")
endif
set r.oid=orderid
set r.abilityid=abilityID
set r.owningplayer=owner
set r.autodestroy=true
return r
endmethod
//==========================================================================================================
// Just like create, but the struct instance self destructs after a call to any cast method
// (Recommended)
//
public static method createA takes nothing returns xecast
local xecast r=xecast.allocate()
set r.autodestroy=true
return r
endmethod
//==========================================================================================================
// So, create the dummy, assign options and cast the skill!
// .castOnTarget(u) : If you want to hit a unit u with the ability, supports FORCE_INVISIBLE_CAST.
// .castOnWidgetTarget(w) : If you want to hit a widget w with the ability.
// .castOnPoint(x,y) : If you want to hit a point (x,y) with the ability.
// .castInPoint(x,y) : For spells like warstomp which do not have a target.
// .castOnAOE(x,y,radius) : Classic area of effect cast. Considers collision size.
// .castOnGroup(g) : Cast unit the unit group g, notice it will empty the group yet not destroy it.
//
//**********************************************************************************************************
// The implementation of such methods follows:
private static unit array dummystack
private static integer top=0
private static unit instantdummy
private integer oid=0
private static timer gametime
private static timer T
private static unit array recycle
private static real array expiretime
private static integer rn=0
//==========================================================================================================
// private dorecycle method, sorry but I need this up here.
//
private static method dorecycle takes nothing returns nothing
local unit u =.recycle[0]
local integer l
local integer r
local integer p
local real lt
call IssueImmediateOrder(u,"stop")// bugfix, see: http://www.wc3c.net/showpost.php?p=1131163&postcount=5
call UnitRemoveAbility(u,GetUnitUserData(u))
call SetUnitUserData(u,0)
call SetUnitFlyHeight(u,0,0)
call PauseUnit(u,false)
if(.top==DUMMY_STACK_LIMIT) then
call RemoveUnit(u)
else
set .dummystack[.top]=u
set .top=.top+1
endif
set .rn=.rn-1
if(.rn==0) then
return
endif
set p=0
set lt=.expiretime[.rn]
loop
set l=p*2+1
exitwhen l>=.rn
set r=p*2+2
if(r>=.rn)then
if(.expiretime[l]<lt) then
set .expiretime[p]=.expiretime[l]
set .recycle[p]=.recycle[l]
set p=l
else
exitwhen true
endif
elseif (lt<=.expiretime[l]) and (lt<=.expiretime[r]) then
exitwhen true
elseif (.expiretime[l]<.expiretime[r]) then
set .expiretime[p]=.expiretime[l]
set .recycle[p]=.recycle[l]
set p=l
else
set .expiretime[p]=.expiretime[r]
set .recycle[p]=.recycle[r]
set p=r
endif
endloop
set .recycle[p]=.recycle[.rn]
set .expiretime[p]=lt
call TimerStart(.T, .expiretime[0]-TimerGetElapsed(.gametime), false, function xecast.dorecycle)
endmethod
private static trigger abilityRemove
// Repetitive process and no inline implemented for large functions, so for now it is a textmacro:
//! textmacro xecast_allocdummy
if(.recycledelay<EPSILON) then
set dummy=.instantdummy
call SetUnitOwner(dummy,.owningplayer,false)
elseif (.top>0) then
set .top=.top-1
set dummy=.dummystack[.top]
call SetUnitOwner(dummy,.owningplayer,false)
else
set dummy=CreateUnit(.owningplayer,XE_DUMMY_UNITID,0,0,0)
call TriggerRegisterUnitEvent(.abilityRemove,dummy,EVENT_UNIT_SPELL_ENDCAST)
call UnitAddAbility(dummy,'Aloc')
call UnitAddAbility(dummy,XE_HEIGHT_ENABLER)
call UnitRemoveAbility(dummy,XE_HEIGHT_ENABLER)
endif
call UnitAddAbility(dummy, abilityid)
static if AUTO_RESET_MANA_COOLDOWN then
call UnitResetCooldown(dummy)
call SetUnitState(dummy, UNIT_STATE_MANA, 10000.0)
endif
if(level>1) then
call SetUnitAbilityLevel(dummy, abilityid, level)
endif
//! endtextmacro
private static integer cparent
private static integer current
private static real cexpire
//! textmacro xecast_deallocdummy
if(.recycledelay>=EPSILON) then
set .cexpire=TimerGetElapsed(.gametime)+.recycledelay
set .current=.rn
set .rn=.rn+1
loop
exitwhen (.current==0)
set .cparent=(.current-1)/2
exitwhen (.expiretime[.cparent]<=.cexpire)
set .recycle[.current]=.recycle[.cparent]
set .expiretime[.current]=.expiretime[.cparent]
set .current=.cparent
endloop
set .expiretime[.current]=.cexpire
set .recycle[.current]=dummy
call SetUnitUserData(dummy,.abilityid)
call TimerStart(.T, .expiretime[0]-TimerGetElapsed(.gametime), false, function xecast.dorecycle)
else
call SetUnitUserData(dummy,0)
call SetUnitFlyHeight(dummy,0,0)
call UnitRemoveAbility(dummy,.abilityid)
endif
//! endtextmacro
method castOnTarget takes unit target returns nothing
local unit dummy
local unit tar
//! runtextmacro xecast_allocdummy()
if (.customsource) then
call SetUnitX(dummy,.sourcex)
call SetUnitY(dummy,.sourcey)
call SetUnitFlyHeight(dummy,.sourcez,0.0)
else
call SetUnitX(dummy,GetWidgetX(target))
call SetUnitY(dummy,GetWidgetY(target))
endif
static if (FORCE_INVISIBLE_CAST) then
call UnitShareVision(target, .owningplayer, true)
call IssueTargetOrderById(dummy,this.oid,target)
call UnitShareVision(target, .owningplayer, false)
else
call IssueTargetOrderById(dummy,this.oid,target)
endif
//! runtextmacro xecast_deallocdummy()
if(.autodestroy ) then
call this.destroy()
endif
endmethod
//accepts units, items and destructables, if you know it is
// a unit it is better to use castOnTarget since that would
// be able to use FORCE_INVISIBLE_CAST if necessary.
//
method castOnWidgetTarget takes widget target returns nothing
local unit dummy
local unit tar
//! runtextmacro xecast_allocdummy()
if (.customsource) then
call SetUnitX(dummy,.sourcex)
call SetUnitY(dummy,.sourcey)
call SetUnitFlyHeight(dummy,.sourcez,0.0)
else
call SetUnitX(dummy,GetWidgetX(target))
call SetUnitY(dummy,GetWidgetY(target))
endif
call IssueTargetOrderById(dummy,this.oid,target)
//! runtextmacro xecast_deallocdummy()
if(.autodestroy ) then
call this.destroy()
endif
endmethod
method castOnPoint takes real x, real y returns nothing
local unit dummy
//! runtextmacro xecast_allocdummy()
if (.customsource) then
call SetUnitX(dummy,.sourcex)
call SetUnitY(dummy,.sourcey)
call SetUnitFlyHeight(dummy,.sourcez,0.0)
else
call SetUnitX(dummy,x)
call SetUnitY(dummy,y)
endif
call IssuePointOrderById(dummy,this.oid,x,y)
//! runtextmacro xecast_deallocdummy()
if(.autodestroy ) then
call this.destroy()
endif
endmethod
method castOnLoc takes location loc returns nothing
//debug call BJDebugMsg("Warning: Locations are in use")
//nah but I should
call .castOnPoint(GetLocationX(loc),GetLocationY(loc))
endmethod
//ignores custom source x and y (for obvious reasons)
method castInPoint takes real x, real y returns nothing
local unit dummy
//! runtextmacro xecast_allocdummy()
if (.customsource) then
call SetUnitFlyHeight(dummy,.sourcez,0.0)
endif
call SetUnitX(dummy, x)
call SetUnitY(dummy, y)
call IssueImmediateOrderById(dummy,this.oid)
//! runtextmacro xecast_deallocdummy()
if(.autodestroy ) then
call this.destroy()
endif
endmethod
method castInLoc takes location loc returns nothing
//debug call BJDebugMsg("Warning: Locations are in use")
//nah but I should
call .castInPoint(GetLocationX(loc),GetLocationY(loc))
endmethod
//===================================================================================================
// For method castOnAOE:
//
private static group enumgroup
private static real aoex
private static real aoey
private static real aoeradius
private static xecast cinstance
private static boolexpr aoefunc
// Might look wrong, but this is the way to make it consider collision size, a spell that
// got a target circle and uses this method will let the user know which units it will
// hit with the mass cast.
static method filterAOE takes nothing returns boolean
local unit u=GetFilterUnit()
if IsUnitInRangeXY(u, .aoex, .aoey, .aoeradius) then
call .cinstance.castOnTarget(u)
endif
set u=null
return false
endmethod
//
method castOnAOE takes real x, real y, real radius returns nothing
local boolean ad=this.autodestroy
if(ad) then
set this.autodestroy=false
endif
set .aoex=x
set .aoey=y
set .aoeradius=radius
set .cinstance=this
call GroupEnumUnitsInRange(.enumgroup,x,y,radius + XE_MAX_COLLISION_SIZE , .aoefunc)
if(ad) then
call this.destroy()
endif
endmethod
method castOnAOELoc takes location loc,real radius returns nothing
call .castOnAOE(GetLocationX(loc),GetLocationY(loc),radius)
endmethod
//==================================================================================================
// A quick and dirt castOnGroup method, perhaps it'll later have castOntarget inlined, but not now
//
method castOnGroup takes group g returns nothing
local boolean ad=this.autodestroy
local unit t
if(ad) then
set this.autodestroy=false
endif
loop
set t=FirstOfGroup(g)
exitwhen(t==null)
call GroupRemoveUnit(g,t)
call .castOnTarget(t)
endloop
if(ad) then
call this.destroy()
endif
endmethod
private static method removeAbility takes nothing returns boolean
local unit u=GetTriggerUnit()
if(GetUnitUserData(u)!=0) then
call PauseUnit(u,true)
endif
//This is necessary, picture a value for recycle delay that's higher than the casting time,
//for example if the spell does dps, if you leave the dummy caster with the ability and it
//is owned by an AI player it will start casting the ability on player units, so it is
// a good idea to pause it...
set u=null
return true
endmethod
//===================================================================================================
// structinit is a scope private keyword.
//
static method structinit takes nothing returns nothing
local integer i=INITIAL_DUMMY_COUNT+1
local unit u
set .aoefunc=Condition(function xecast.filterAOE)
set .enumgroup=CreateGroup()
set .abilityRemove = CreateTrigger()
loop
exitwhen (i==0)
set u=CreateUnit(Player(15),XE_DUMMY_UNITID,0,0,0)
call TriggerRegisterUnitEvent(.abilityRemove,u,EVENT_UNIT_SPELL_ENDCAST)
call UnitAddAbility(u,'Aloc')
call UnitAddAbility(u,XE_HEIGHT_ENABLER)
call UnitRemoveAbility(u,XE_HEIGHT_ENABLER)
set .dummystack[.top]=u
set .top=.top+1
set i=i-1
endloop
call TriggerAddCondition(.abilityRemove, Condition(function xecast.removeAbility ) )
set .top=.top-1
set .instantdummy=.dummystack[.top]
set .T=CreateTimer()
set .gametime=CreateTimer()
call TimerStart(.gametime,12*60*60,false,null)
endmethod
endstruct
private function init takes nothing returns nothing
call xecast.structinit()
endfunction
endlibrary
library xefx initializer init requires xebasic, optional xedummy
//**************************************************
// xefx 0.9
// --------
// Recommended: ARGB (adds ARGBrecolor method)
// For your movable fx needs
//
//**************************************************
//==================================================
globals
private constant integer MAX_INSTANCES = 8190 //change accordingly.
//Delay in order to show the death animation of the effect correctly when xefx is destroyed.
//You may need to increase this if you are using effects with longer death animations.
private constant real MIN_RECYCLE_DELAY = 4.0
//The delay does not need to be exact so we do cleanup in batches instead of individually.
//This determines how often the recycler runs, should be less than MIN_RECYCLE_DELAY.
private constant real RECYCLE_INTERVAL = 0.5
//if this is true and the xedummy library is present, units will be recycled instead of removed.
private constant boolean RECYCLE_DUMMY_UNITS = true
private timer recycler
endglobals
private struct recyclebin
unit u
private recyclebin next=0
private static recyclebin array list
private static integer readindex=1
private static integer writeindex=0
private static integer count=0
static method Recycle takes nothing returns nothing
local recyclebin this = .list[readindex]
loop
exitwhen this==0
static if RECYCLE_DUMMY_UNITS and LIBRARY_xedummy then
call XE_ReleaseDummyUnit(this.u)
else
call RemoveUnit(this.u)
endif
set this.u=null
set .count=.count-1
call this.destroy()
set this=this.next
endloop
set .list[readindex]=0
set .writeindex=.readindex
set .readindex=.readindex+1
if .readindex>R2I(MIN_RECYCLE_DELAY/RECYCLE_INTERVAL+1.0) then
set .readindex=0
endif
if count!=0 then
call TimerStart(recycler, RECYCLE_INTERVAL, false, function recyclebin.Recycle)
endif
endmethod
static method create takes unit u returns recyclebin
local recyclebin this=recyclebin.allocate()
if .count==0 then
call TimerStart(recycler, RECYCLE_INTERVAL, false, function recyclebin.Recycle)
endif
set .count=.count+1
set .u=u
call SetUnitOwner(u,Player(15),false)
set .next=.list[.writeindex]
set .list[.writeindex]=this
return this
endmethod
endstruct
private function init takes nothing returns nothing
set recycler=CreateTimer()
endfunction
struct xefx[MAX_INSTANCES]
public integer tag=0
private unit dummy
private effect fx=null
private real zang=0.0
private integer r=255
private integer g=255
private integer b=255
private integer a=255
private integer abil=0
static method create takes real x, real y, real facing returns xefx
local xefx this=xefx.allocate()
static if RECYCLE_DUMMY_UNITS and LIBRARY_xedummy then
set this.dummy= XE_NewDummyUnit(Player(15), x,y, facing*bj_RADTODEG)
else
set this.dummy= CreateUnit(Player(15), XE_DUMMY_UNITID, x,y, facing*bj_RADTODEG)
call UnitAddAbility(this.dummy,XE_HEIGHT_ENABLER)
call UnitAddAbility(this.dummy,'Aloc')
call UnitRemoveAbility(this.dummy,XE_HEIGHT_ENABLER)
call SetUnitX(this.dummy,x)
call SetUnitY(this.dummy,y)
endif
return this
endmethod
method operator owner takes nothing returns player
return GetOwningPlayer(this.dummy)
endmethod
method operator owner= takes player p returns nothing
call SetUnitOwner(this.dummy,p,false)
endmethod
method operator teamcolor= takes playercolor c returns nothing
call SetUnitColor(this.dummy,c)
endmethod
method operator scale= takes real value returns nothing
call SetUnitScale(this.dummy,value,value,value)
endmethod
//! textmacro XEFX_colorstuff takes colorname, colorvar
method operator $colorname$ takes nothing returns integer
return this.$colorvar$
endmethod
method operator $colorname$= takes integer value returns nothing
set this.$colorvar$=value
call SetUnitVertexColor(this.dummy,this.r,this.g,this.b,this.a)
endmethod
//! endtextmacro
//! runtextmacro XEFX_colorstuff("red","r")
//! runtextmacro XEFX_colorstuff("green","g")
//! runtextmacro XEFX_colorstuff("blue","b")
//! runtextmacro XEFX_colorstuff("alpha","a")
method recolor takes integer r, integer g , integer b, integer a returns nothing
set this.r=r
set this.g=g
set this.b=b
set this.a=a
call SetUnitVertexColor(this.dummy,this.r,this.g,this.b,this.a)
endmethod
implement optional ARGBrecolor
method operator abilityid takes nothing returns integer
return this.abil
endmethod
method operator abilityid= takes integer a returns nothing
if(this.abil!=0) then
call UnitRemoveAbility(this.dummy,this.abil)
endif
if(a!=0) then
call UnitAddAbility(this.dummy,a)
endif
set this.abil=a
endmethod
method operator abilityLevel takes nothing returns integer
return GetUnitAbilityLevel( this.dummy, this.abil)
endmethod
method operator abilityLevel= takes integer newLevel returns nothing
call SetUnitAbilityLevel(this.dummy, this.abil, newLevel)
endmethod
method flash takes string fx returns nothing
call DestroyEffect(AddSpecialEffectTarget(fx,this.dummy,"origin"))
endmethod
method operator xyangle takes nothing returns real
return GetUnitFacing(this.dummy)*bj_DEGTORAD
endmethod
method operator xyangle= takes real value returns nothing
call SetUnitFacing(this.dummy,value*bj_RADTODEG)
endmethod
method operator zangle takes nothing returns real
return this.zang
endmethod
method operator zangle= takes real value returns nothing
local integer i=R2I(value*bj_RADTODEG+90.5)
set this.zang=value
if(i>=180) then
set i=179
elseif(i<0) then
set i=0
endif
call SetUnitAnimationByIndex(this.dummy, i )
endmethod
method operator x takes nothing returns real
return GetUnitX(this.dummy)
endmethod
method operator y takes nothing returns real
return GetUnitY(this.dummy)
endmethod
method operator z takes nothing returns real
return GetUnitFlyHeight(this.dummy)
endmethod
method operator z= takes real value returns nothing
call SetUnitFlyHeight(this.dummy,value,0)
endmethod
method operator x= takes real value returns nothing
call SetUnitX(this.dummy,value)
endmethod
method operator y= takes real value returns nothing
call SetUnitY(this.dummy,value)
endmethod
method operator fxpath= takes string newpath returns nothing
if (this.fx!=null) then
call DestroyEffect(this.fx)
endif
if (newpath=="") then
set this.fx=null
else
set this.fx=AddSpecialEffectTarget(newpath,this.dummy,"origin")
endif
endmethod
method hiddenReset takes string newfxpath, real newfacing returns nothing
local real x = GetUnitX(this.dummy)
local real y = GetUnitY(this.dummy)
local real z = this.z
local real za = this.zangle
local integer level = this.abilityLevel
set .fxpath=null
static if RECYCLE_DUMMY_UNITS and LIBRARY_xedummy then
if(this.abil!=0) then
call UnitRemoveAbility(this.dummy,this.abil)
endif
call recyclebin.create(this.dummy)
set this.dummy=XE_NewDummyUnit(Player(15), x,y, newfacing*bj_RADTODEG)
else
call RemoveUnit(this.dummy)
set this.dummy= CreateUnit(Player(15), XE_DUMMY_UNITID, x,y, newfacing*bj_RADTODEG)
call UnitAddAbility(this.dummy,XE_HEIGHT_ENABLER)
call UnitAddAbility(this.dummy,'Aloc')
call UnitRemoveAbility(this.dummy,XE_HEIGHT_ENABLER)
call SetUnitX(this.dummy,x)
call SetUnitY(this.dummy,y)
endif
set .fxpath=newfxpath
if(level != 0) then
call UnitAddAbility(this.dummy, this.abil)
call SetUnitAbilityLevel(this.dummy, this.abil, level)
endif
set this.z = z
set zangle = za
endmethod
method destroy takes nothing returns nothing
if(this.abil!=0) then
call UnitRemoveAbility(this.dummy,this.abil)
endif
if(this.fx!=null) then
call DestroyEffect(this.fx)
set this.fx=null
endif
call recyclebin.create(this.dummy)
set this.dummy=null
call this.deallocate()
endmethod
method hiddenDestroy takes nothing returns nothing
call ShowUnit(dummy,false)
call destroy()
endmethod
endstruct
endlibrary
library xedamage initializer init requires xebasic
//************************************************************************
// xedamage 0.8
// --------
// For all your damage and targetting needs.
//
//************************************************************************
//===========================================================================================================
globals
private constant integer MAX_SUB_OPTIONS = 3
private constant real FACTOR_TEST_DAMAGE = 0.01
// a low damage to do on units to test their damage factors for specific
// attacktype/damagetype combos.
// You'll need something as high as 20.0 to make it work well with armor resistances.
// (Yes, you read it correctly, 20 ...
//
// If you use such a large value, there may be conflicts with some things relying on damage
// (ie they are not away of the isDummyDamage tag that xedamage posseses.) which may be quite bad if you think about it...
// then maybe it is better to change it to 0.01 ... then will work fine, just fine - but it will generally ignore armor -
// I am leaving it as 0.01 by default, because honestly, I'd rather make it ignore armor than have a lot of people sending me
// rants about how they detect 20.0 damage where none is visible...
private constant real MAX_DAMAGE_FACTOR = 3.00
// The maximum damage factor in the map. I think 3 is fine.
//=======================================================
private constant real EPSILON = 0.000000001
private unit dmger
private constant integer MAX_SPACE = 8190 // MAX_SPACE/MAX_SUB_OPTIONS is the instance limit for xedamage, usually big enough...
endglobals
private keyword structInit
struct xedamage[MAX_SPACE]
//----
// fields and methods for a xedamage object, they aid determining valid targets and special
// damage factor conditions.
//
// Notice the default values.
//
boolean damageSelf = false // the damage and factor methods usually have a source unit parameter
// xedamage would consider this unit as immune unless you set damageSelf to true
boolean damageAllies = false // Alliance dependent target options.
boolean damageEnemies = true // *
boolean damageNeutral = true // *
boolean ranged = true // Is the attack ranged? This has some effect on the AI of the affected units
// true by default, you may not really need to modify this.
boolean visibleOnly = false // Should only units that are visible for source unit's owner be affected?
boolean deadOnly = false // Should only corpses be affected by "the damage"? (useful when using xedamage as a target selector)
boolean alsoDead = false // Should even corpses and alive units be considered?
boolean damageTrees = false //Also damage destructables? Notice this is used only in certain methods.
//AOE for example targets a circle, so it can affect the destructables
//in that circle, a custom spell using xedamage for targetting configuration
//could also have an if-then-else implemented so it can verify if it is true
//then affect trees manually.
//
// Damage type stuff:
// .dtype : the "damagetype" , determines if the spell is physical, magical or ultimate.
// .atype : the "attacktype" , deals with armor.
// .wtype : the "weapontype" , determines the sound effect to be played when damage is done.
//
// Please use common.j/blizzard.j/ some guide to know what damage/attack/weapon types can be used
//
damagetype dtype = DAMAGE_TYPE_UNIVERSAL
attacktype atype = ATTACK_TYPE_NORMAL
weapontype wtype = WEAPON_TYPE_WHOKNOWS
//
// Damage type 'tag' people might use xedamage.isInUse() to detect xedamage usage, there are other static
// variables like xedamage.CurrentDamageType and xedamage.CurrentDamageTag. The tag allows you to specify
// a custom id for the damage type ** Notice the tag would aid you for some spell stuff, for example,
// you can use it in a way similar to Rising_Dusk's damage system.
//
integer tag = 0
//
// if true, forceDamage will make xedamage ignore dtype and atype and try as hard as possible to deal 100%
// damage.
boolean forceDamage = false
//
// Ally factor! Certain spells probably have double purposes and heal allies while harming enemies. This
// field allows you to do such thing.
//
real allyfactor = 1.0
//
// field: .exception = SOME_UNIT_TYPE
// This field adds an exception unittype (classification), if the unit belongs to this unittype it will
// be ignored.
//
method operator exception= takes unittype ut returns nothing
set this.use_ex=true
set this.ex_ut=ut
endmethod
//
// field: .required = SOME_UNIT_TYPE
// This field adds a required unittype (classification), if the unit does not belong to this unittype
// it will be ignored.
//
method operator required= takes unittype ut returns nothing
set this.use_req=true
set this.req_ut=ut
endmethod
private boolean use_ex = false
private unittype ex_ut = null
private boolean use_req = false
private unittype req_ut = null
private unittype array fct[MAX_SUB_OPTIONS]
private real array fc[MAX_SUB_OPTIONS]
private integer fcn=0
//
// method .factor(SOME_UNIT_TYPE, factor)
// You might call factor() if you wish to specify a special damage factor for a certain classification,
// for example call d.factor(UNIT_TYPE_STRUCTURE, 0.5) makes xedamage do half damage to structures.
//
method factor takes unittype ut, real fc returns nothing
if(this.fcn==MAX_SUB_OPTIONS) then
debug call BJDebugMsg("In one instance of xedamage, you are doing too much calls to factor(), please increase MAX_SUB_OPTIONS to allow more, or cut the number of factor() calls")
return
endif
set this.fct[this.fcn] = ut
set this.fc[this.fcn] = fc
set this.fcn = this.fcn+1
endmethod
private integer array abifct[MAX_SUB_OPTIONS]
private real array abifc[MAX_SUB_OPTIONS]
private integer abifcn=0
//
// method .abilityFactor('abil', factor)
// You might call abilityFactor() if you wish to specify a special damage factor for units that have a
// certain ability/buff.
// for example call d.abilityFactor('A000', 1.5 ) makes units that have the A000 ability take 50% more
// damage than usual.
//
method abilityFactor takes integer abilityId, real fc returns nothing
if(this.abifcn==MAX_SUB_OPTIONS) then
debug call BJDebugMsg("In one instance of xedamage, you are doing too much calls to abilityFactor(), please increase MAX_SUB_OPTIONS to allow more, or cut the number of abilityFactor() calls")
return
endif
set this.abifct[this.abifcn] = abilityId
set this.abifc[this.abifcn] = fc
set this.abifcn = this.abifcn+1
endmethod
private boolean usefx = false
private string fxpath
private string fxattach
//
// method .useSpecialEffect("effect\\path.mdl", "origin")
// Makes it add (and destroy) an effect when damage is performed.
//
method useSpecialEffect takes string path, string attach returns nothing
set this.usefx = true
set this.fxpath=path
set this.fxattach=attach
endmethod
//********************************************************************
//* Now, the usage stuff:
//*
//================================================================================
// static method xedamage.isInUse() will return true during a unit damaged
// event in case this damage was caused by xedamage, in this case, you can
// read variables like CurrentDamageType, CurrentAttackType and CurrentDamageTag
// to be able to recognize what sort of damage was done.
//
readonly static damagetype CurrentDamageType=null
readonly static attacktype CurrentAttackType=null
readonly static integer CurrentDamageTag =0
private static integer inUse = 0
static method isInUse takes nothing returns boolean
return (inUse>0) //inline friendly.
endmethod
readonly static boolean isDummyDamage = false
//========================================================================================================
// This function calculates the damage factor caused by a certain attack and damage
// type, it is static : xedamage.getDamageTypeFactor(someunit, ATTAcK_TYPE_NORMAL, DAMAGE_TYPE_FIRE, 100)
//
static method getDamageTypeFactor takes unit u, attacktype a, damagetype d returns real
local real hp=GetWidgetLife(u)
local real mana=GetUnitState(u,UNIT_STATE_MANA)
local real r
local real fc = FACTOR_TEST_DAMAGE
//Since a unit is in that point, we don't need checks.
call SetUnitX(dmger,GetUnitX(u))
call SetUnitY(dmger,GetUnitY(u))
call SetUnitOwner(dmger,GetOwningPlayer(u),false)
set r=hp
if (hp< FACTOR_TEST_DAMAGE*MAX_DAMAGE_FACTOR) then
call SetWidgetLife(u, hp + FACTOR_TEST_DAMAGE*MAX_DAMAGE_FACTOR )
set r = hp + FACTOR_TEST_DAMAGE*MAX_DAMAGE_FACTOR
set fc = GetWidgetLife(u)-hp + EPSILON
endif
set isDummyDamage = true
call UnitDamageTarget(dmger,u, fc ,false,false,a,d,null)
static if DEBUG_MODE then
if IsUnitType(u, UNIT_TYPE_DEAD) and (hp>0.405) then
call BJDebugMsg("xedamage: For some reason, the unit being tested by getDamageTypeFactor has died. Verify MAX_DAMAGE_FACTOR is set to a correct value. ")
endif
endif
set isDummyDamage = false
call SetUnitOwner(dmger,Player(15),false)
if (mana>GetUnitState(u,UNIT_STATE_MANA)) then
//Unit had mana shield, return 1 and restore mana too.
call SetUnitState(u,UNIT_STATE_MANA,mana)
set r=1
else
set r= (r-GetWidgetLife(u)) / fc
endif
call SetWidgetLife(u,hp)
return r
endmethod
private method getTargetFactorCore takes unit source, unit target, boolean usetypes returns real
local player p=GetOwningPlayer(source)
local boolean allied=IsUnitAlly(target,p)
local boolean enemy =IsUnitEnemy(target,p)
local boolean neutral=allied
local real f
local real negf=1.0
local integer i
if(this.damageAllies != this.damageNeutral) then
set neutral= allied and not (GetPlayerAlliance(GetOwningPlayer(target),p, ALLIANCE_HELP_REQUEST ))
//I thought accuracy was not as important as speed , I think that REQUEST is false is enough to consider
// it neutral.
//set neutral= allied and not (GetPlayerAlliance(GetOwningPlayer(target),p, ALLIANCE_HELP_RESPONSE ))
//set neutral= allied and not (GetPlayerAlliance(GetOwningPlayer(target),p, ALLIANCE_SHARED_XP ))
//set neutral= allied and not (GetPlayerAlliance(GetOwningPlayer(target),p, ALLIANCE_SHARED_SPELLS ))
set allied= allied and not(neutral)
endif
if (not this.damageAllies) and allied then
return 0.0
elseif (not this.damageEnemies) and enemy then
return 0.0
elseif( (not this.damageSelf) and (source==target) ) then
return 0.0
elseif (not this.damageNeutral) and neutral then
return 0.0
elseif( this.use_ex and IsUnitType(target, this.ex_ut) ) then
return 0.0
elseif( this.visibleOnly and not IsUnitVisible(target,p) ) then
return 0.0
elseif ( this.deadOnly and not IsUnitType(target,UNIT_TYPE_DEAD) ) then
return 0.0
elseif ( not(this.alsoDead) and IsUnitType(target,UNIT_TYPE_DEAD) ) then
return 0.0
endif
set f=1.0
if ( IsUnitAlly(target,p) ) then
set f=f*this.allyfactor
if(f<=-EPSILON) then
set f=-f
set negf=-1.0
endif
endif
if (this.use_req and not IsUnitType(target,this.req_ut)) then
return 0.0
endif
set i=.fcn-1
loop
exitwhen (i<0)
if( IsUnitType(target, this.fct[i] ) ) then
set f=f*this.fc[i]
if(f<=-EPSILON) then
set f=-f
set negf=-1.0
endif
endif
set i=i-1
endloop
set i=.abifcn-1
loop
exitwhen (i<0)
if( GetUnitAbilityLevel(target,this.abifct[i] )>0 ) then
set f=f*this.abifc[i]
if(f<=-EPSILON) then
set f=-f
set negf=-1.0
endif
endif
set i=i-1
endloop
set f=f*negf
if ( f<EPSILON) and (f>-EPSILON) then
return 0.0
endif
if( this.forceDamage or not usetypes ) then
return f
endif
set f=f*xedamage.getDamageTypeFactor(target,this.atype,this.dtype)
if ( f<EPSILON) and (f>-EPSILON) then
return 0.0
endif
return f
endmethod
//====================================================================
// With this you might decide if a unit is a valid target for a spell.
//
method getTargetFactor takes unit source, unit target returns real
return this.getTargetFactorCore(source,target,true)
endmethod
//======================================================================
// a little better, I guess
//
method allowedTarget takes unit source, unit target returns boolean
return (this.getTargetFactorCore(source,target,false)!=0.0)
endmethod
//=======================================================================
// performs damage to the target unit, for unit 'source'.
//
method damageTarget takes unit source, unit target, real damage returns boolean
local damagetype dt=.CurrentDamageType
local attacktype at=.CurrentAttackType
local integer tg=.CurrentDamageTag
local real f = this.getTargetFactorCore(source,target,false)
local real pl
if(f!=0.0) then
set .CurrentDamageType = .dtype
set .CurrentAttackType = .atype
set .CurrentDamageTag = .tag
set .inUse = .inUse +1
set pl=GetWidgetLife(target)
call UnitDamageTarget(source,target, f*damage, true, .ranged, .atype, .dtype, .wtype )
set .inUse = .inUse -1
set .CurrentDamageTag = tg
set .CurrentDamageType = dt
set .CurrentAttackType = at
if(pl != GetWidgetLife(target) ) then
if(usefx) then
call DestroyEffect( AddSpecialEffectTarget(this.fxpath, target, this.fxattach) )
endif
return true
endif
endif
return false
endmethod
//=======================================================================================
// The same as damageTarget, but it forces a specific damage value, good if you already
// know the target.
//
method damageTargetForceValue takes unit source, unit target, real damage returns nothing
local damagetype dt=.CurrentDamageType
local attacktype at=.CurrentAttackType
local integer tg=.CurrentDamageTag
set .CurrentDamageType = .dtype
set .CurrentAttackType = .atype
set .CurrentDamageTag = .tag
if( usefx) then
call DestroyEffect( AddSpecialEffectTarget(this.fxpath, target, this.fxattach) )
endif
set .inUse = .inUse +1
call UnitDamageTarget(source,target, damage, true, .ranged, null, null, .wtype )
set .inUse = .inUse -1
set .CurrentDamageTag = tg
set .CurrentDamageType = dt
set .CurrentAttackType = at
endmethod
//=====================================================================================
// Notice: this will not Destroy the group, but it will certainly empty the group.
//
method damageGroup takes unit source, group targetGroup, real damage returns integer
local damagetype dt=.CurrentDamageType
local attacktype at=.CurrentAttackType
local integer tg=.CurrentDamageTag
local unit target
local real f
local integer count=0
local real hp
set .CurrentDamageType = .dtype
set .CurrentAttackType = .atype
set .CurrentDamageTag = .tag
set .inUse = .inUse +1
loop
set target=FirstOfGroup(targetGroup)
exitwhen (target==null)
call GroupRemoveUnit(targetGroup,target)
set f= this.getTargetFactorCore(source,target,false)
if (f!=0.0) then
set count=count+1
if(usefx) then
set hp = GetWidgetLife(target)
endif
call UnitDamageTarget(source,target, f*damage, true, .ranged, .atype, .dtype, .wtype )
if(usefx and (hp > GetWidgetLife(target)) ) then
call DestroyEffect( AddSpecialEffectTarget(this.fxpath, target, this.fxattach) )
endif
endif
endloop
set .inUse = .inUse -1
set .CurrentDamageTag=tg
set .CurrentDamageType = dt
set .CurrentAttackType = at
return count
endmethod
private static xedamage instance
private integer countAOE
private unit sourceAOE
private real AOEx
private real AOEy
private real AOEradius
private real AOEdamage
private static boolexpr filterAOE
private static boolexpr filterDestAOE
private static group enumgroup
private static rect AOERect
private static method damageAOE_Enum takes nothing returns boolean
local unit target=GetFilterUnit()
local xedamage this=.instance //adopting a instance.
local real f
local real hp
if( not IsUnitInRangeXY(target,.AOEx, .AOEy, .AOEradius) ) then
set target=null
return false
endif
set f=.getTargetFactorCore(.sourceAOE, target, false)
if(f!=0.0) then
set .countAOE=.countAOE+1
if(this.usefx) then
set hp =GetWidgetLife(target)
endif
call UnitDamageTarget(.sourceAOE,target, f*this.AOEdamage, true, .ranged, .atype, .dtype, .wtype )
if(this.usefx and (hp > GetWidgetLife(target) ) ) then
call DestroyEffect( AddSpecialEffectTarget(this.fxpath, target, this.fxattach) )
endif
endif
set .instance= this //better restore, nesting IS possible!
set target=null
return false
endmethod
private static method damageAOE_DestructablesEnum takes nothing returns boolean
local destructable target=GetFilterDestructable()
local xedamage this=.instance //adopting a instance.
local real dx=.AOEx-GetDestructableX(target)
local real dy=.AOEy-GetDestructableY(target)
if( dx*dx + dy*dy >= .AOEradius+EPSILON ) then
set target=null
return false
endif
set .countAOE=.countAOE+1
if(.usefx) then
call DestroyEffect( AddSpecialEffectTarget(this.fxpath, target, this.fxattach) )
endif
call UnitDamageTarget(.sourceAOE,target, this.AOEdamage, true, .ranged, .atype, .dtype, .wtype )
set .instance= this //better restore, nesting IS possible!
set target=null
return false
endmethod
//==========================================================================================
// will affect trees if damageTrees is true!
//
method damageAOE takes unit source, real x, real y, real radius, real damage returns integer
local damagetype dt=.CurrentDamageType
local attacktype at=.CurrentAttackType
local integer tg=.CurrentDamageTag
set .CurrentDamageType = .dtype
set .CurrentAttackType = .atype
set .CurrentDamageTag = .tag
set .inUse = .inUse +1
set .instance=this
set .countAOE=0
set .sourceAOE=source
set .AOEx=x
set .AOEradius=radius
set .AOEy=y
set .AOEdamage=damage
call GroupEnumUnitsInRange(.enumgroup,x,y,radius+XE_MAX_COLLISION_SIZE, .filterAOE)
if(.damageTrees) then
call SetRect(.AOERect, x-radius, y-radius, x+radius, y+radius)
set .AOEradius=.AOEradius*.AOEradius
call EnumDestructablesInRect(.AOERect, .filterDestAOE, null)
endif
set .inUse = .inUse -1
set .CurrentDamageTag = tg
set .CurrentDamageType = dt
set .CurrentAttackType = at
return .countAOE
endmethod
method damageAOELoc takes unit source, location loc, real radius, real damage returns integer
return .damageAOE(source, GetLocationX(loc), GetLocationY(loc), radius, damage)
endmethod
//==========================================================================================
// only affects trees, ignores damageTrees
//
method damageDestructablesAOE takes unit source, real x, real y, real radius, real damage returns integer
set .instance=this
set .countAOE=0
set .sourceAOE=source
set .AOEx=x
set .AOEradius=radius*radius
set .AOEy=y
set .AOEdamage=damage
//if(.damageTrees) then
call SetRect(.AOERect, x-radius, y-radius, x+radius, y+radius)
call EnumDestructablesInRect(.AOERect, .filterDestAOE, null)
//endif
return .countAOE
endmethod
method damageDestructablesAOELoc takes unit source, location loc, real radius, real damage returns integer
return .damageDestructablesAOE(source,GetLocationX(loc), GetLocationY(loc), radius, damage)
endmethod
//'friend' with the library init
static method structInit takes nothing returns nothing
set .AOERect= Rect(0,0,0,0)
set .filterAOE= Condition(function xedamage.damageAOE_Enum)
set .filterDestAOE = Condition( function xedamage.damageAOE_DestructablesEnum)
set .enumgroup = CreateGroup()
endmethod
endstruct
private function init takes nothing returns nothing
set dmger=CreateUnit(Player(15), XE_DUMMY_UNITID , 0.,0.,0.)
call UnitAddAbility(dmger,'Aloc')
call xedamage.structInit()
endfunction
endlibrary
library xecollider initializer init requires xefx, xebasic
//****************************************************************
//*
//* xecollider 0.9
//* --------------
//* A xecollider object is a special effect that has a collision
//* size that can trigger a hit event and also many options to
//* configure its automatic movement.
//*
//* Please use .terminate() instead of .destroy() this ensures
//* that it will be safe to destroy it (else you would have to
//* worry about destroying it during the animation loop/etc.)
//*
//* To use this struct is a little different than the other
//* current parts of xe. Instead of just creating the xecollider
//* (which works, but it would only be a xefx that can have speed)
//* you probably need to make it do something special on the
//* unit hit event... For this reason, you need to make a new
//* struct extending xecollider that declares an onUnitHit method
//* you may also declare a loopControl method, very useful, can
//* help you reduce 'attaching'.
//*
//****************************************************************
//================================================================
globals
private constant real DEFAULT_COLLISION_SIZE = 50.0 // These are defaults, on one hand you can change them
private constant real DEFAULT_MAX_SPEED = 1500.0 // on the other hand, if a spell relies on the defaults
private constant real DEFAULT_EXPIRATION_TIME = 5.0 // changing them would make the behavior vary...
private constant real PI2 = 6.28318 //It might not be wise to change this
endglobals
//===========================================================================
// So, this exists merely so you can declare your own event handler methods
// if interfaces make your brain blow out, please skip the next four lines.
//
private interface eventHandler
method onUnitHit takes unit hitTarget returns nothing defaults nothing
method loopControl takes nothing returns nothing defaults nothing
endinterface
//===========================================================================
struct xecollider extends eventHandler
// use terminate() instead of .destroy() to "kill" the collider.
// don't worry, terminate will call destroy automatically.
//============================================================================
// delegates:
// We are delegating a xefx object so that people call all the xefx methods
// and member from a xecollider object. This means that from a user
// perspective a xecollider is also an instance of xefx.
//
// Notable ones are: .x , .y , .fxpath and .z ,
// check out xefx's documentation for more info.
//
private delegate xefx fx
//##==========================================================================
// public variables:
//
public real expirationTime = DEFAULT_EXPIRATION_TIME
// Movement speed for the missile.
public real speed = 0.0
// Speed added per second (notice you can use a negative value here)
public real acceleration = 0.0
// If there is acceleration, it is wise to have a cap...
public real maxSpeed = DEFAULT_MAX_SPEED
public real minSpeed = 0.0
public real angleSpeed = 0.0 //The increment in radians per second to the
// direction angle, allows curved movement.
private static integer lastSeen = 0
private group seen
//##==========================================================================
// public methods:
//
//----
// Well, it is a good idea to actually create the missiles.
// notice that if your custom missile struct needs to declare its own create
// method, you can call this as allocate(x,y,dir).
//
// Sorry, no Loc version.
//
public static method create takes real x, real y, real dir returns xecollider
local xecollider xc= xecollider.allocate()
set xc.fx = xefx.create(x,y,dir)
set xc.dir=dir
set xecollider.V[xecollider.N]=xc
set xecollider.N=xecollider.N+1
if(xecollider.N==1) then
call TimerStart(xecollider.T, XE_ANIMATION_PERIOD, true, xecollider.timerLoopFunction )
endif
if(.lastSeen < integer(xc)) then //with this I do group recycling
set .lastSeen = integer(xc)
set xc.seen = CreateGroup()
endif
return xc
endmethod
//----
// The direction is just the angle in radians to which the missile's model faces
// and the automatic movement uses.
//
method operator direction takes nothing returns real
return this.dir
endmethod
method operator direction= takes real v returns nothing
set this.dir=v
set this.fx.xyangle=v
endmethod
//----
// The collisionSize
//
method operator collisionSize takes nothing returns real
return this.csize
endmethod
method operator collisionSize= takes real value returns nothing
set this.csize = value
//good long attribute name, but we use csize in the loop
//don't worry this gets inlined, it would also be helpful if
//I ever decide to add a control for assignment.
endmethod
//---
// targetUnit is a unit to follow (or try to follow), notice that homing
// options require an angleSpeed different to 0.0
//
public method operator targetUnit takes nothing returns unit
return this.homingTargetUnit
endmethod
public method operator targetUnit= takes unit u returns nothing
if(u==null) then
set this.angleMode= ANGLE_NO_MOVEMENT
else
set this.angleMode= ANGLE_HOMING_UNIT
endif
set this.homingTargetUnit=u
endmethod
//----
// targetPoint is a point to reach (or try to reach), notice that homing
// options require an angleSpeed different to 0.0
//
public method setTargetPoint takes real x, real y returns nothing
set this.angleMode= ANGLE_HOMING_POINT
set this.homingTargetX=x
set this.homingTargetY=y
endmethod
public method setTargetPointLoc takes location loc returns nothing
set this.angleMode= ANGLE_HOMING_POINT
set this.homingTargetX=GetLocationX(loc)
set this.homingTargetY=GetLocationY(loc)
endmethod
//----
// Call this in case you used targetUnit or TargetPoint so the missile
// forgets the order to home that target.
//
public method forgetTarget takes nothing returns nothing
set this.angleMode = ANGLE_NO_MOVEMENT
endmethod
public method operator rotating takes nothing returns boolean
return (angleMode ==ANGLE_ROTATING)
endmethod
public method operator rotating= takes boolean val returns nothing
if(val) then
set angleMode = ANGLE_ROTATING
elseif (angleMode == ANGLE_ROTATING) then
set angleMode = ANGLE_NO_MOVEMENT
endif
endmethod
private boolean silent = false
private method destroy takes nothing returns nothing
call GroupClear(this.seen)
if(this.silent) then
call this.fx.hiddenDestroy()
else
call this.fx.destroy()
endif
call .deallocate()
endmethod
method terminate takes nothing returns nothing
set this.dead=true
set this.fxpath=""
endmethod
// declare hiddenDestroy so people don't call directly on the delegate xefx
method hiddenDestroy takes nothing returns nothing
set silent = true
call terminate()
endmethod
//--------
private static timer T
private static integer N=0
private static xecollider array V
private static code timerLoopFunction //I use a code var so create can be above the timerloop function, more readable
private boolean dead=false
private real csize = DEFAULT_COLLISION_SIZE
private real dir
private static constant integer ANGLE_HOMING_UNIT =1
private static constant integer ANGLE_HOMING_POINT=2
private static constant integer ANGLE_NO_MOVEMENT=0
private static constant integer ANGLE_ROTATING=3
private integer angleMode =0
private unit homingTargetUnit = null
private real homingTargetX
private real homingTargetY
private static real newx
private static real newy
private static group enumGroup
private static group tempGroup
private static unit array picked
private static integer pickedN
static method timerLoop takes nothing returns nothing
local integer i=0
local integer c=0
local xecollider this
local real d
local real ns
local real wa
local real df1
local real df2
local unit u
local group g
loop
exitwhen (i== xecollider.N )
set this=.V[i] //adopt-a-instance
set this.expirationTime = this.expirationTime - XE_ANIMATION_PERIOD
if(.dead or (this.expirationTime <=0.0) ) then
call this.destroy()
else
set ns=this.angleSpeed*XE_ANIMATION_PERIOD
if (ns!=0.0) then
if(this.angleMode== ANGLE_HOMING_UNIT ) then
set u=this.homingTargetUnit
if ( (GetUnitTypeId(u)==0) or IsUnitType(u, UNIT_TYPE_DEAD) ) then
set this.angleMode= ANGLE_NO_MOVEMENT
set this.homingTargetUnit = null
else
set this.homingTargetX=GetUnitX(u)
set this.homingTargetY=GetUnitY(u)
endif
set u=null
endif
if (this.angleMode == ANGLE_ROTATING) then
//nothing (ns is already ns)
elseif( this.angleMode != ANGLE_NO_MOVEMENT) then
if(ns<=0) then
set ns=-ns
endif
set wa=Atan2(this.homingTargetY - this.y , this.homingTargetX-this.x)
//if(wa<0.0) then
// set wa=wa+PI2
//endif
set df1=wa-this.dir
set df2=(PI2+wa)-this.dir
if (df1<=0) then
if(df2<=0) then
if(df2>=df1) then
set df1=df2
endif
else
if(-df1>=df2) then
set df1=df2
endif
endif
else
if(df2<=0) then
if(-df2<=df1) then
set df1=df2
endif
else
if(df2<=df1) then
set df1=df2
endif
endif
endif
if(df1<=0) then
if(-df1>=ns) then
set ns=-ns
else
set ns=df1
endif
else
if(df1<=ns) then
set ns=df1
endif
endif
else
set ns = 0
endif
set d=this.dir
set d = d + ns
if(d>=PI2) then
set d=d - PI2
elseif(d<0) then
set d=d + PI2
endif
set this.dir = d
set this.xyangle = d
endif
// function calls are expensive, damned we are, long code inside of loop
// correct software dev. tells us this should go to another function,
// but this is Jass, not real life.
set ns = this.speed + this.acceleration*XE_ANIMATION_PERIOD
if ( ns<this.minSpeed) then
set ns=this.minSpeed
elseif (ns>this.maxSpeed) then
set ns=this.maxSpeed
endif
set d=((this.speed+ns)/2) * XE_ANIMATION_PERIOD
set this.speed=ns
set .newx= .x+d*Cos(this.dir)
set .newy= .y+d*Sin(this.dir)
set .x=.newx
set .y=.newy
call GroupEnumUnitsInRange( .enumGroup, .newx, .newy, .csize + XE_MAX_COLLISION_SIZE, null)
loop
set u=FirstOfGroup(.enumGroup)
exitwhen u==null
call GroupRemoveUnit(.enumGroup, u)
if not IsUnitType(u, UNIT_TYPE_DEAD) and not(this.dead) and (GetUnitTypeId(u)!=XE_DUMMY_UNITID) and IsUnitInRangeXY(u, .newx, .newy, .csize) then
call GroupAddUnit(.tempGroup, u)
if not IsUnitInGroup (u, this.seen ) then
call this.onUnitHit(u)
endif
endif
endloop
set g=.tempGroup
call GroupClear(this.seen)
set .tempGroup=this.seen
set this.seen=g
set g=null
set .V[c]=this
set c=c+1
if( this.loopControl.exists and not this.dead ) then
call this.loopControl()
endif
endif
set i=i+1
endloop
//call BJDebugMsg("}")
set xecollider.N=c
if(c==0) then
call PauseTimer(xecollider.T)
endif
endmethod
//============================================================================
// you aren't supposed to call doInit yourself, try not to do it.
//
static method doInit takes nothing returns nothing
set xecollider.enumGroup = CreateGroup()
set xecollider.tempGroup = CreateGroup()
set xecollider.timerLoopFunction = (function xecollider.timerLoop)
set xecollider.T=CreateTimer()
endmethod
endstruct
private function init takes nothing returns nothing
call xecollider.doInit()
endfunction
endlibrary
library xemissile requires xefx, xebasic
//****************************************************************
//*
//* xemissile 0.9
//* -------------
//* A xemissile object is a special effect that moves like a
//* WC3's attack or spell missile.
//*
//* Please use .terminate() instead of .destroy() this ensures
//* that it will be safe to destroy it (else you would have to
//* worry about destroying it during the animation loop/etc.)
//*
//* This struct is used similarly to xecollider. Instead of just
//* creating the xemissile (which works, but it would only be a
//* xefx that can move like a missile) you probably need to make
//* it do something special when it reaches its target...
//* For this reason, you need to make a new struct extending
//* xemissile that declares an onHit method, you may also declare
//* a loopControl method.
//*
//****************************************************************
//===========================================================================
// So, this exists merely so you can declare your own event handler methods
// if interfaces make your brain blow out, please skip the next four lines.
//
private interface eventHandler
method onHit takes nothing returns nothing defaults nothing
method loopControl takes nothing returns nothing defaults nothing
endinterface
//===========================================================================
private struct missile extends eventHandler
private delegate xefx fx
// movement duration parameter.
private real time
// xy movement parameters.
private real mx
private real my
private real mvx
private real mvy
private real mvxy = 1.0
// z movement parameters.
private real mz
private real mvz
private real maz
private static location l = Location(0.0,0.0)
// target parameters.
private real tx = 0.0
private real ty = 0.0
private real tz = 0.0
private unit tu = null
public real zoffset = 0.0
private boolean update = true
private boolean launched = false
private boolean dead = false
public method operator x takes nothing returns real
return .mx
endmethod
public method operator y takes nothing returns real
return .my
endmethod
public method operator z takes nothing returns real
call MoveLocation(.l, .mx,.my)
return mz-GetLocationZ(.l)
endmethod
public method operator x= takes real r returns nothing
set .update=true
set .mx=r
endmethod
public method operator y= takes real r returns nothing
set .update=true
set .my=r
endmethod
public method operator z= takes real r returns nothing
set .update=true
call MoveLocation(.l, .mx,.my)
set .mz=r+GetLocationZ(.l)
endmethod
public method operator speed takes nothing returns real
return .mvxy/XE_ANIMATION_PERIOD
endmethod
public method operator speed= takes real newspeed returns nothing
local real factor=newspeed*XE_ANIMATION_PERIOD/.mvxy
if newspeed<=0.0 then
debug call BJDebugMsg("xemissile speed error: speed must be a non-zero positive value.")
return
endif
set .mvxy=newspeed*XE_ANIMATION_PERIOD
if .launched then
set .time=.time/factor
set .mvx=.mvx*factor
set .mvy=.mvy*factor
set .mvz=.mvz*factor
set .maz=.maz*factor*factor
endif
endmethod
public method operator targetUnit takes nothing returns unit
return this.tu
endmethod
public method operator targetUnit= takes unit u returns nothing
set .update=true
set .tu=u
set .tx=GetUnitX(u)
set .ty=GetUnitY(u)
call MoveLocation(.l, .tx,.ty)
set .tz=GetUnitFlyHeight(u)+GetLocationZ(.l)+.zoffset
endmethod
public method setTargetPoint takes real x, real y, real z returns nothing
set .update=true
set .tu=null
set .tx=x
set .ty=y
call MoveLocation(.l, .tx,.ty)
set .tz=z+GetLocationZ(.l)
endmethod
//-------- Missile launcher
public method launch takes real speed, real arc returns nothing
local real dx=.tx-.mx
local real dy=.ty-.my
local real d=SquareRoot(dx*dx+dy*dy)
local real a=Atan2(dy, dx)
local real dz=.tz-.mz
set .mvxy=speed*XE_ANIMATION_PERIOD
if speed<=0.0 then
debug call BJDebugMsg("xemissile launch error: speed must be a non-zero positive value.")
return
elseif d>0.0 then
set .time=d/speed
else
set .time=XE_ANIMATION_PERIOD
endif
set .mvz=( (d*arc)/(.time/4.0) + dz/.time )*XE_ANIMATION_PERIOD // Do some mathemagics to get a proper arc.
set .dead=.dead and not(.launched) // In case this is called from the onHit method to bounce the missile.
if not .dead and not .launched then
set .launched=true
set .V[.N]=this
set .N=.N+1
if(.N==1) then
call TimerStart(.T, XE_ANIMATION_PERIOD, true, xemissile.timerLoopFunction )
endif
endif
endmethod
//-------- Constructors and destructors
static method create takes real x, real y, real z, real a returns missile
local missile this=missile.allocate()
set .mx=x
set .my=y
call MoveLocation(.l, x,y)
set .mz=z+GetLocationZ(.l)
set .fx = xefx.create(x,y,a)
set .fx.z = z
return this
endmethod
private boolean silent=false
private method destroy takes nothing returns nothing
if(this.silent) then
call this.fx.hiddenDestroy()
else
call this.fx.destroy()
endif
call .deallocate()
endmethod
method terminate takes nothing returns nothing
set this.dead=true
set this.fx.zangle=0.0
set this.fxpath=""
endmethod
// declare hiddenDestroy so people don't call directly on the delegate xefx
method hiddenDestroy takes nothing returns nothing
set silent = true
call terminate()
endmethod
//-------- Main engine
private static timer T
private static integer N=0
private static xemissile array V
private static code timerLoopFunction //I use a code var so create can be above the timerloop function, more readable
private static method timerLoop takes nothing returns nothing
local integer i=0
local integer c=0
local thistype this
local real dx
local real dy
local real d
local real a
loop
exitwhen (i==.N )
set this=.V[i] //adopt-a-instance
if .dead then
set .launched=false
set this.fx.zangle=0.0
call .destroy()
else
if .tu!=null and GetUnitTypeId(.tu)!=0 then
set .update=true
set .tx=GetUnitX(.tu)
set .ty=GetUnitY(.tu)
call MoveLocation(.l, .tx,.ty)
set .tz=GetUnitFlyHeight(.tu)+GetLocationZ(.l)+.zoffset
endif
if .update then
set .update=false
set dx=.tx-.mx
set dy=.ty-.my
set d=SquareRoot(dx*dx+dy*dy)
set a=Atan2(dy,dx)
if d>0.0 then
set .time=d/.mvxy*XE_ANIMATION_PERIOD
else
set .time=XE_ANIMATION_PERIOD
endif
set .mvx=Cos(a)*.mvxy
set .mvy=Sin(a)*.mvxy
set .fx.xyangle=a
set .maz=2*((.tz-.mz)/.time/.time*XE_ANIMATION_PERIOD*XE_ANIMATION_PERIOD-(.mvz*XE_ANIMATION_PERIOD)/.time)
endif
set .mx=.mx+.mvx
set .my=.my+.mvy
set a=.maz/2.0
set .mvz=.mvz+a
set .mz=.mz+.mvz
set .mvz=.mvz+a
set .fx.x=.mx
set .fx.y=.my
call MoveLocation(.l, .mx,.my)
set .fx.z=.mz-GetLocationZ(.l)
set .fx.zangle=Atan2(.mvz, .mvxy)
set .time=.time-XE_ANIMATION_PERIOD
if .time<=0.0 then
set .dead=true
call this.onHit()
if .dead then
set .fxpath=""
endif
endif
set .V[c]=this
set c=c+1
if( this.loopControl.exists and not this.dead ) then
call this.loopControl()
endif
endif
set i=i+1
endloop
set .N=c
if(c==0) then
call PauseTimer(.T)
endif
endmethod
static method onInit takes nothing returns nothing
set .timerLoopFunction = (function missile.timerLoop)
set .T=CreateTimer()
endmethod
endstruct
//===========================================================================
struct xemissile extends missile
public static method create takes real x,real y,real z, real tx,real ty,real tz returns xemissile
local xemissile xm = xemissile.allocate(x,y,z, Atan2(ty-y,tx-x))
call xm.setTargetPoint(tx,ty,tz)
return xm
endmethod
endstruct
struct xehomingmissile extends xemissile
public static method create takes real x,real y,real z, unit target,real zoffset returns xehomingmissile
local xehomingmissile xm = xehomingmissile.allocate(x,y,z, GetUnitX(target), GetUnitY(target), 0.0)
set xm.zoffset=zoffset
set xm.targetUnit=target
return xm
endmethod
endstruct
endlibrary
xe
--
Q. Why xe?
A. As the caster system grew bigger vJass also appeared, there are also a lot
of things in the caster system that could have been done better but cannot
be fixed without dropping the caster system's function interface.
Q. No, really, WHY IS IT NAMED XE?
A. I have no idea.
Q. What's wrong with the caster system?
A. Instead of answering that I will list what's right with xe:
* It is modular. You can make a whole spell with just xebasic which is just
like a "constant package" that comes with the dummy model and unit. All the
other parts are disposable or replaceable.
Still, I made them and will probably keep making new modules as I advance,
right now xe can only do some basic functions, still cannot 100% replace
the caster system in functionality, certain parts like the parabolic
projectiles most notably, don't have a xe module yet, maybe later...
xebasic is so minimal I personally hope people could use it on their spells
and systems as a way to make it common to use these constants as constants of
that kind are often required to make things work.
* It is quite OOP, this is more related to the modules themselves, I wanted it
to exploit OOP for two reasons: 1) It prevents the 'ultra long function calls'
disease that has plagued the caster system since the beginning of time. 2) I
personally think it is easier this way instead of memorizing function names
and their argument lists.
xebasic
-------
xebasic is the nucleous of all xe, in order to use a xe module you would most
likely need xebasic. It is also meant to be the only part of xe that most users
would really need to tweak for their map.
This section is supposed to be a rapid guide on copying xebasic. The rest of
the xe modules should be rather easy to implement (just copy the 'trigger' that
contains it to the map).
1) Make a backup of your map.
2) Get vJass support. The most usual way would be using the newgen pack. There
are plenty of other ways. I for example do my vJass coding on Linux using just
jasshelper.exe, WINE and some editor tricks using a tool called Warcity.
Getting vJass to work is a wide area, if just installing and using the
"Jass newgen pack" doesn't work to you, please request/search help somehow. As
of now there really is no vJass support in OS/X, so you would need virtualization
and things of that style.
-- Note: You can have two maps open in the editor, and it is the only way to
make copy and paste work.
3) Copy the model, in this map's import manager you may find dummy.mdx, select
it and export it to some temp folder, then go to your map and import it, use
war3mapimported\dummy.mdx for path.
Please save the map immediatelly after importing the model to prevent it from
getting unimported due to a rare WE bug.
4) Copy the dummy unit: In the object editor under neutral passive, you may
find the dummy unit, select it, go to 'edit' then click copy. Now switch to
your map's object editor and use 'paste'.
5) Write down the rawcode: While you are in the object editor select your map's
recently pasted dummy unit, then go to the 'view' menu and click the option to
show values as raw data. Now take a look to the selected unit type. It will now
come with a code like "ewsp:e001", the last four characters of the code are
what matter, write them down.
6) Copy this map's xebasic trigger to your map.
7) Update your map's xebasic: change the value assigned to XE_DUMMY_UNITID to
'XXXX' where XXXX is the four character code you wrote down in step 5.
8) Save your map and pray, if it compiles correctly then it is done. Make sure
to test (after implementing) whatever needed you to install xebasic. If it
doesn't work correctly then it is likely you made a mistake when copying the
unit or the model or updating the rawcode.
9) Update the other values if you think it is necessary.
Using xebasic
-------------
Well, once you state your trigger/spell/system requires xebasic, just use
its constants, on a map that has implemented xebasic XE_DUMMY_UNITID will be
your key to creating dummy units, just remember to add it 'Aloc' ...
Contact
-------
I got a forum that's supposed to hold questions related to my systems at:
http://wc3campaigns.net/vexorian
I'd really appreciate that you used that forum for your questions, for starters
it is a lot more likely I would actually find the questions in that case.
Changelog
---------
0.9:
- Added xemissile.
- Added xedummy.
- xefx can now use xedummy to recycle dummy units.
- xepreload can now be used from struct initializers.
- Fixed a bug in xecast that would occur if recycledelay was shorter than
the duration of the spell cast by the dummy caster.
- Fixed a bug in xefx where hiddenReset did not properly assign the new fxpath.
- Optimized the xecollider collision detection.
- Fixed some errors in xefx and xecast documentation.
- new sample: Firestrike.
- Removed an xecast leak in the IllusionRune sample.
- Removed a handle id leak in SheepStaff sample.
0.8:
- No longer let xecollider hit corpses...
- When xecollider misses targetUnit (the unit dies, it will stop homing and
keep going on its current direction).
- angleSpeed no longer implicitly makes rotation automatic unless there is homing,
If you want rotation, set the boolean member rotation to true.
- xedamage: Added MAX_DAMAGE_FACTOR to prevent some deads, a debug message will
appear if the unit dies when being tested for a damage factor.
- xepreload: debug message when preloading an ability at a wrong time.
0.7:
- Requires jasshelper 0.A.2.4 or greater.
- xepreload will now show an useful error when the ability does not exist
(in debug mode).
- xepreload may now use TimerUtils to recycle its timer if you happen to have
TimerUtils in the map.
- xecast automatically resets mana and cooldown for the dummy before making it
cast stuff. If this behaviour concerns you, you may disable it through a
constant.
- Added targetUnit, setTargetPoint and forgetTarget to xecollider's
documentation.
- Added abilityLevel to xefx.
- Fixed a mistake in xefx's documentation that said "copy the xecast trigger"
- xedamage: Added a constant FACTOR_TEST_DAMAGE, which allows you to set the
amount of damage to do when testing for damage...
- xedamage: Added an isDummyDamage event response boolean to detect test damages.
- xedamage: Added a lot of things to documentation about the issues with armor.
- xedamage: fx is for sure not shown when there is no damage.
- xefx: added hiddenDestroy and hiddenReset
- new sample: Chains of fire.
0.6:
- The demo map is playable in patch 1.24.
- Only the samples and demomap system needed to be updated, xe's libraries
themselves have not changed.
0.5:
- xecollider.terminate now prevents events from firing.
- fixed a unit handle index kidnap in inRangeEnum (xecollider).
- fixed a small documentation bug about xecollider.terminate
- xecast's anti-AI protection now pauses the unit instead of removing the
ability (since that seemed to have bad side effects)
- xecast is now able to deal with units not visible to the player by setting
a constant to true.
- Due to technical split, xecast.castOnTarget now only takes unit and not
widget, old castOnTarget that takes widget has been renamed castOnWidgetTarget.
- xecollider now will not miss the detection of certain units that get inside
the range too fast anymore, however now creates a group per collider (damn) I
hope to find a better solution.
- Added a notice in xepreload's documentation about order events firing during
the preload.
- Added gem of double green fire
0.4:
- More documentation fixes.
- xecast no longer has double frees when using create/Basic/A and the
AOE/group methods.
- damageDestructablesInAOE now actually works and does not leak a xedamage
reference.
- damageTarget now returns true if it was succesful and false if it wasn't.
- xefx's recycle bin now extends array.
- added rune of illusions sample.
0.3:
- More documentation fixes.
- xefx requires xebasic in the library declaration (as it was supposed to)
- xefx now creates the effects at the correct place (used to consider pathing
during creation for some reason).
- xebasic sample uses 197.0 for max collision size since that's the default in
warcraft 3 (The default + 1)
- xebasic now includes an explanation for max collision size and its effects.
- added useSpecialEffect to xedamage
- included BoundSentinel
- added xecollider
- xedamage's required unittype field is not ignored anymore.
- Added the fireNovaStrike example.
0.2:
- Fixed a bug with xecast.castInPoint basically ignoring the arguments.
- Fixed a bug with xecast.createBasic ignoring the order id.
- Fixed documentation bugs.
- Added xedamage.
- Added sheep staff sample.
0.1 : Initial release
xepreload
---------
xepreload attacks the ability preloading issue. It is a good idea to preload
abilities you are going to add to units during the game to avoid the typical
"first-cast freeze". xepreload exploits jasshelper's inline and a timer to
minimize the time spent preloading each ability.
Install
-------
Copy the xepreload trigger to your map.
Usage
-----
_____________________________________________________________________________
function XE_PreloadAbility takes integer abilid returns nothing
----
Preloads the ability, pass it an ability id (rawcode). Notice that this
function may only work during map init. In order to use it in a library's
initializer, make sure the library requires xepreload.
* Please notice that the ability removal might trigger certain order events, try
ignoring xe dummy units in those events if necessary.
xedummy
-------
xedummy attacks the dummy unit recycling issue. Creating units is a costly
operation and due to their versatility, xe dummy units can end up being
created and destroyed very frequently. In such situations, recycling them
makes sense.
Install
-------
Copy the xedummy trigger to your map.
Usage
-----
_____________________________________________________________________________
function XE_NewDummyUnit takes player p, real x, real y, real face returns unit
----
Gives you a new xe dummy unit. If a previously preloaded or released unit
is available for the given facing angle, it will be reused, else a new xe
dummy unit will be created. The unit is automatically given the 'aloc'
ability to make it unselectable and the XE_HEIGHT_ENABLER ability so you can
modify its fly height.
There is no way to change the facing angle of a unit instantly, this is
why xedummy stores recycled units at various facing angles so that when a
new unit is requested, the system may already have a unit with a similar
facing angle available. This way, the non-instant change of facing when
reusing a recycled unit is made less noticeable.
The number of angles at which dummy units are stored is configurable,
however keep in mind that more angles mean higher overhead. With the current
implementation, the maximum theoretical overhead is N*N/4 units, so with the
default 12 directions the map will use at most 36 more units than it would
without this library.
_____________________________________________________________________________
function XE_ReleaseDummyUnit takes unit u returns nothing
----
Makes an xe dummy unit available for recycling. Please only call this on
xe dummy units that were obtained with the NewXEDummy function and make sure
to destroy any special effects attached to them and remove any abilities
they may have.
You can limit how many units the system will keep available for reuse.
If this limit is reached then released dummy units will be removed. This
way, if at some point your map needs a number of dummy units that greatly
exceeds your average use, you won't be stuck with that many dummy units for
the rest of the game. However, this limit should not be set too low or the
map will end up creating and removing dummy units more often than recycling
them.
_____________________________________________________________________________
xecast
------
This one solves typical problems that require dummy casters. Things like the
AOE sleep, targetted warstomp, etc. It is object oriented, this just means that
you'll actually not just call functions but deal with xecast objects, change
their attributes and then order them to cast. It deals with the dirty things
like recycling and dealing with timing, etc.
implementation
--------------
Just copy the xecast trigger to your map.
xecast object
-------------
__________________________________________________________________________________________________
static method create takes nothing returns nothing
- ------
This is the create method, it will make a new xecast object for you to use:
set somevariable = xecast.create()
_________________________________________________________________________________________________
static method createBasic takes integer abilityID, integer orderid, player owner returns xecast
- - - - - - - - - - - -
An abbreviated constructor, allows you to quickly set the basic attributes
abilityID: the rawcode of the ability to cast.
Example: 'AHbz'
orderid : the orderid (integer) of the ability to cast.
Example: OrderId("blizzard")
owner : the owning player for this cast object (The one that gets credit for damage)
Example: ( GetOwningPlayer(GetTriggerUnit() ))
_________________________________________________________________________________________________
method destroy takes nothing returns nothing
-
Call destroy() on instances you are not going to use anymore, to prevent struct leaks that would
break your map. A simple use for xecast is to just keep one instance per dummy spell to prevent
having to care about destroying them. Another possibility is to use the A constructors.
Example: call somevariable.destroy()
__________________________________________________________________________________________________
static method createA takes nothing returns nothing
static method createBasicA takes integer abilityID, integer orderid, player owner returns xecast
-
These do the same as create and createBasic , the only difference is that the
object is destroyed automatically after every call to a cast method (See bellow).
_____________________________________________________________________________________________________
method castOnTarget takes unit target returns nothing
-
Tells the xecast object to cast its spell on the target unit. Can cast on units that are invisible
to the owner of the xecast if FORCE_INVISIBLE_CAST is set to true.
_____________________________________________________________________________________________________
method castOnWidgetTarget takes widget target returns nothing
-
Tells the xecast object to cast its spell on the target. target may be unit, item or destructable.
_____________________________________________________________________________________________________
method castOnPoint takes real x, real y returns nothing
method castOnLoc takes location loc returns nothing
method castInPoint takes real x, real y returns nothing
method castInLoc takes location loc returns nothing
- -----------------------------------------------
Instead of casting on a target unit/item/destructable these ones cast on a target point. OnPoint is
used for point-targeteable spells, while InPoint is used for spells that have no target. The Loc
versions allow you to use locations. Locations are useless most of the times, but if you want to use
them you can use the Loc versions.
Example: call somevar.castOnPoint( spellx, spelly )
_____________________________________________________________________________________________________
method castOnAOE takes real x, real y, real radius returns nothing
method castOnAOELoc takes location loc,real radius returns nothing
method castOnGroup takes group g returns nothing
- ---------------------------------------------------
Methods to cast the spell on multiple units, AOE takes a circle's center and radius, while Group
takes a unit group, notice that the unit group will get cleaned after calling this function, which
means it will be an empty unit group, no, it does not destroy the group automatically, just empties it
* List of attributes *
________________________________________________________________________________
integer abilityid
----
This one holds the ability to cast's ability Id.
Example: set somevar.abilityid='AHbz'
________________________________________________________________________________
integer level
----
The level of the ability to cast.
Example: set somevar.level = GetUnitAbilityLevel(u, spellid)
________________________________________________________________________________
real recycledelay
----
The recycle delay is the time to wait before recycling the dummy caster, if
it is 0.0 the ability will be considered instant.
A proper recycle delay is important since when a dummy caster is recycled
its owner becomes player passive. Every damage done by the casted spell will
not credit the correct player.
Some other spells need some time in order to cast correctly. Not to mention
the channeling ones that require the caster to last during that situation.
Example: set somevar.recycledelay=10.0
________________________________________________________________________________
player owningplayer
----
The player that owns the spell (Who gets credited for it)
Example: set somevar.owningplayer = Player(2)
________________________________________________________________________________
integer orderid (write-only)
----
The ability to cast's order id. eg 858029 or OrderId("blizzard")
________________________________________________________________________________
string orderstring (write-only)
----
The ability to cast's order string (eg "blizzard")
________________________________________________________________________________
boolean customsource
----
false by default, determines if you want the dummy caster to be placed at
a specific point when casting, this allows you to exploit blizz spell's eye
candy. Once customsource is true, you need to set sourcex,sourcey and
sourcez.
________________________________________________________________________________
real sourcex, sourcey, sourcez
----
The coordinates where you want to place the dummy caster, z is height and
is 0.0 by default. These are ignored if customsource is set to false.
________________________________________________________________________________
method setSourcePoint takes real x, real y, real z returns nothing
method setSourceLoc takes location loc, real z returns nothing
----
In case setting all that stuff manually takes too much lines for your taste
you can use these methods to set those values, they will automatically set
customsource to true.
xefx
----
This module just allows you to have movable special effects, they are actually
dummy units, you can do plenty of things like changing their position, their
height, their rotation (in the xy and in the z axis as well), color, and things
like that. It is all about assigning attributes, the only two important methods
xefx objects have are create and destroy. There are other accessory methods.
implementation
--------------
Just copy the xefx trigger to your map.
xefx object
-------------
__________________________________________________________________________________________________
static method create takes real x, real y, real facing returns xefx
--
This is the create method, it will make a new xefx for you to use, there are
initial values you must specify, like the x,y coordinate and the facing angle.
facing is in radians.
Eg. set myfx = xefx.create()
__________________________________________________________________________________________________
method destroy takes nothing returns nothing
--
This just destroys your xefx object. (call myfx.destroy() )
* List of attributes *
________________________________________________________________________________
string fxpath
----
Determines the model of the special effect, yes, you may change it after
assigning it if necessary to change the model path.
Example: set myfx.path = "abilities\thisisamadeup\modelpath.mdl"
________________________________________________________________________________
method hiddenReset takes string newfxpath, real newfacing returns nothing
----
Resets the xefx with a new effect path and a new facing angle (radians).
Avoids playing the dead animation of the previous model, notice that it is
impossible to do this withouth playing the birth animation of the new model
and without playing the sound of the dead animation of the previous model.
Example: call myfx.hiddenReset("abilities\thisisamadeup\modelpath.mdl", 0.4)
________________________________________________________________________________
method hiddenDestroy takes nothing returns nothing
----
Destroys the xefx without playing the death animation of the model. Notice
that it is impossible to do this without playing the sound of the
dead animation.
Example: call myfx.hiddenDestroy()
________________________________________________________________________________
real x
real y
real z
----
Determine the position of your special effect, you can keep moving the
effect in a periodic loop, etc.
Example: set myfx.x=myfx.x + 65.0
set myfx.y=GetUnitY(u)
set myfx.z=JumpParabola(t)
________________________________________________________________________________
real xyangle
----
The angle in the xy plane, also called 'facing' angle. (Note: uses radians)
Example: set myfx.xyangle = AngleBetweenPoints(target, source)*bj_DEGTORAD
________________________________________________________________________________
real zangle
----
The angle in the z-axis (inclination?), (Note: uses radians)
Example: set myfx.zangle = bj_PI/2 //Now the model will look towards the sky
________________________________________________________________________________
integer red
integer green
integer blue
integer alpha
----
Well, the model's vertex coloring in RGB , a is the opacity value (use
values from 0 to 255 here)
Example: set myfx.red=255
set myfx.green=0
set myfx.blue=255
set myfx.alpha=128
______________________________________________________________________________________
method recolor takes integer r, integer g , integer b, integer a returns nothing
----
This one assigns all the color values in one pass.
________________________________________________________________________________
real scale (write-only)
----
Allows you to resize the xefx object, the default scale is 1.
Example: set myfx.scale=2.0 //double size (in fact 8x)
set myfx.scale=0.5 //half size (in fact 1/8x)
________________________________________________________________________________
player owner
----
For some reason you might want to change ownership of the effect, for
example, if you use abilityid (see bellow) and the ability does damage.
Example: set myfx.owner = GetOwningPlayer(GetTriggerUnit() )
________________________________________________________________________________
integer abilityid
----
Well, you may use a xefx object to grab a passive ability, perhaps you need
it for ye candy reasons or you want to use it as a damage dealer.
Example: set myfx.abilityid = 'Hphf'
________________________________________________________________________________
integer abilityLevel
----
And with this one, you change the level of that ability.
Example: set myfx.abilityLevel = GetUnitAbilityLevel( u, s)
________________________________________________________________________________
playercolor teamcolor
----
The team color to use for the model.
Example: set somevar.teamcolor=PLAYER_COLOR_RED
set somevar.teamcolor=GetPlayerColor(GetOwningPlayer(u))
________________________________________________________________________________
method flash takes string modelpath returns nothing
----
It shows the dead animation of the model specified by modelpath. This is
in case you need this sort of eye candy.
________________________________________________________________________________
method ARGBrecolor takes ARGB color returns nothing
----
If you got the ARGB library in your map, xefx then acquires the ARGBrecolor
method, that you can use to use an ARGB object to recolor the fx's model,
in a way similar to how recolor() works.
//TESH.scrollpos=0
//TESH.alwaysfold=0
xedamage
--------
When blizzard released UnitDamageTarget and UnitDamagePoint there were some
issue, both had a lot of parameters that were undocumented, but more importantly
DamagePoint was not a good enough solution, UnitDamagePoint causes issues with
apple players and it also misses ways to specify what sort of unit to target.
What many people missed was a way to specify these things in a similar way
to targets allowed in the object editor.
Determining and configuring valid targets and things like damage factors is
always a hassle, xedamage can automatize that process in a nice way.
xedamage is the successor of damageoptions it is also a little less messy.
bitflags are not used anymore, instead xedamage uses struct members to specify
most of it. So, when using xedamage, you may end up feeling like feeling a
table of fields. An example is worth a thousand of words:
local xedamage d=xedamage.create()
set d.damageAllies=true // also harm allies
set d.exception = UNIT_TYPE_FLYING // don't harm fliers
call d.factor ( UNIT_TYPE_STRUCTURE, 0.5) // half damage to buildings
set d.dtype = DAMAGE_TYPE_UNIVERSAL // Do universal damage.
//Execute AOE damage using those options:
call d.damageAOE(GetTriggerUnit(), point_x, point_y, 250.0, 450)
But there is more, xedamage also has a couple of members like isInUse() that
would add some event responses for the damaged unit event. That will allow you
to recognize when xedamage was in use to inflict the damage, the damagetype and
attacktype used, and even a custom tag that you could specify as a xedamage
field, this would allow you to have a bridge between xedamage and certain damage
detection systems that rely on such things.
About damage factors and dummy damages
----------------------------------------
Typically xedamage does some dummy damage to test the damage factor of a unit
because blizzard has not provided us with such a native... This damage is
invisible to the player, but not invisible to spells and damage detect systems
which could be a problem.
By default, the dummy damage is 0.01 and it is a common practice in these
spells and systems to ignore such low damage values. However, a bug from
blizzard makes it so we require a HUGE damage of 20.0 to be actually able to
detect all armor resistances. Something as low as 0.01 will not even detect
hero resistance. This blows. So if you want xedamage to consider resistance
correctly, you should use a test damage of 1/(armor reduction you wish to detect)
(change the FACTOR_TEST_DAMAGE constant in the xedamage trigger).
Of course, if you do this change, then you'll confuse spells/systems that
detect damage, that's the reason I have added a variable isDummyDamage to
xedamage (call it xedamage.isDummyDamage ) that you may read during a damage
event to ignore this dummy damage.
implementation
--------------
Just copy the xedamage trigger to your map.
xedamage object
----------------
xedamage fields include a bunch of boolean fields that you can set to
true/false, they hopefully got self-explaining names, I just list them and
their default values, remember I got a whole forum in wc3c, if you got doubts
don't forget to ask questions there:
boolean damageSelf = false
boolean damageAllies = false
boolean damageEnemies = true
boolean damageNeutral = true
boolean visibleOnly = false
boolean deadOnly = false
boolean alsoDead = false
boolean damageTrees = false
Something to notice is that damageTrees is probably only considered by AOE
damage and perhaps by some spells using xedamage to specify targets.
_______________________
boolean ranged = true
-----------------------
This is a special boolean field, it doesn't really determine valid targets
like the ones above, it merely determines if the damage should be considered
ranged, this merely determines how the AI reacts to the damage, a lot of people
don't care that much and just use true, that's the default.
___________________________________________________
damagetype dtype = DAMAGE_TYPE_UNIVERSAL
attacktype atype = ATTACK_TYPE_NORMAL
weapontype wtype = WEAPON_TYPE_WHOKNOWS
---------------------------------------------------
These fields determine the types to use in the damage native, the damage type
usually determines if the damage would be magical, universal (ultimate) or
physical, attacktype determines armor stuff, and weapon type determines sound.
There's some work on knowing what each combination does, for example:
http://www.wc3campaigns.net/showthread.php?t=100752
Some basic knowledge: For spells it is fine to use ATTACK_TYPE_NORMAL, and
that is default in xedamage, wtype usually doesn't need to be updated . dtype
is the important one, _UNIVERSAL makes the damage behave as a ultimate, there
is also _UNKNOWN which seems to ignore a lot of things, _FIRE, _LIGHTNING and
similar damagetypes are all magical, while DAMAGE_TYPE_NORMAL is physical.
Ultimate damage can harm both ethereal and spell immune units, magical damage
harms ethereal (with bonus) but cannot harm spell immune, physical damage can't
hurt ethereal units.
___________________________
integer tag = 0
---------------------------
This little field allows you to have a custom damage response CurrentDamageTag
(see bellow for event responses) basically, you can use whatever you want here
it all depends on what the thing that uses the event responses will do about it.
____________________________
unittype exception
unittype required
----------------------------
Learn a little about unittype, it is what blizzard calls unit classifications,
basically a unit can be a building, a flier, etc. exception specifies a
unittype that is required for a unit to receive damage. required, does the
opposite, for example:
set d.exception = UNIT_TYPE_FLYING
set d.required = UNIT_TYPE_SUMMONED
This xedamage instance can only hit ground summoned units.
* factor stuff:
Factor options in xedamage, specify some rules, if those rules are matched,
the damage will be multiplied by the specified factor, you can use negative
factor, half factor, etc. Notice that when using negative factors, these
things stack, so if you make a xedamage instance that does negative damage to
undead and negative damage to allies, it might do possitive damage to undead
allies.
If the total damage factor is 0.0 it is the same as adding an exception.
_____________________________
real allyfactor = 1.0
-----------------------------
If the xedamage can affect allies (damageAllies is true), then the damage
will be multiplied by allyfactor, for example, you can make a spell that does
half damage to allies. Or one that heals allies while hurting enemies.
_____________________________________________________________
method factor takes unittype ut, real fc returns nothing
-------------------------------------------------------------
This method allows you to add a specific factor for a unit type, by default
a xedamage instance allows up to three of these rules, you can increase this
cap by increasing MAX_SUB_OPTIONS in the top of the library.
For example:
call d.factor(UNIT_TYPE_STRUCTURE, 0.5)
call d.factor(UNIT_TYPE_SUMMONED, 2.0)
This instance of xedamage would do half damage to structures and double
damage to summoned units. Notice these things stack, so if for some reason
there was a "summoned building" in your map, it would do 100% damage.
_________________________________________________________________________
method abilityFactor takes integer abilityId, real fc returns nothing
-------------------------------------------------------------------------
Let's say you want a passive ability that makes you receive half damage
from fire spells, a way to do this is to make a whole damage detection system
and use xedamage's event responses to find out fire was used in the spell.
Then block the damage somehow... another way is to just change the spell so
when a unit has such passive ability, the damage is multiplied by 0.5 .
The 3 rules cap also works with abilityFactor and can as well be increased
by changing MAX_SUB_OPTIONS.
call d.abilityFactor( 'A000', 0.5)
____________________________________________________________________________
method useSpecialEffect takes string path, string attach returns nothing
----------------------------------------------------------------------------
This will make a special effect show up whenever succesful damage is done
using the xedamage object.
call d.useSpecialEffect("Abilities\\Weapons\\RedDragonBreath\\RedDragonMissile.mdl","origin")
xedamage methods
----------------
There would be little point in using all those fields without the methods that
make use of them.
____________________________________________________________________________________
method damageTarget takes unit source, unit target, real damage returns boolean
------------------------------------------------------------------------------------
A single unit targetting method, it will consider all the rules we just
reviewed when doing the damage, if the damage would get a factor of 0.0 it will
not perform any damage.
local unit u = GetTriggerUnit()
local unit t = GetSpellTargetUnit()
local xedamage d= xedamage.create()
set d.dtype = DAMAGE_TYPE_FIRE
set d.damageAllies = true
set d.allyfactor = -1.0
call d.damageTarget(u,t, 100)
call d.destroy()
This would be a simple spell that does 100.0 fire damage on enemy units or
heals for 100 hitpoints to allies.
This method returns true if non zero damage was done, and false otherwise.
____________________________________________________________________________________________
method damageTargetForceValue takes unit source, unit target, real damage returns nothing
---------------------------------------------------------------------------------------------
This is an analogue for damageTarget, but it will IGNORE every specified
field, and try to do the specified damage, no matter the circumstances, however
it will use the xedamage instances' dtype, atype and tag for the xedamage event
responses (see bellow).
This could be useful when you already know the factor
(you have previously used getTargetFactor)
__________________________________________________________________________
method allowedTarget takes unit source, unit target returns boolean
--------------------------------------------------------------------------
Returns true if xedamage would do a damage different than 0.0 in this case.
It is useful if you intend to use xedamage to configure a spell's allowed
targets.
if ( d.allowedTarget(u,t) ) then
//...
____________________________________________________________________________
method getTargetFactor takes unit source, unit target returns real
----------------------------------------------------------------------------
For applications similar to allowedTarget, this returns the whole damage
factor, so you can decide what to do based on it.
set fc = d.getTargetFactor(u, t)
________________________________________________________________________________________
method damageGroup takes unit source, group targetGroup, real damage returns integer
----------------------------------------------------------------------------------------
This method does what damageTarget does, but it executes it on a whole unit
group, probably faster than calling damageTarget on every unit in the group.
Notice this method will empty the provided group.
_________________________________________________________________________________________________
method damageAOE takes unit source, real x, real y, real radius, real damage returns integer
method damageAOELoc takes unit source, location loc, real radius, real damage returns integer
-------------------------------------------------------------------------------------------------
It will perform damage on units and destructables (if damageTrees is true)
that are inside the circle, notice collision sizes are considered. The returned
value is the number of targets that were affected by the function, the loc
version allows you to use a location instead of the more sane x,y coordinates.
______________________________________________________________________________________________________________
method damageDestructablesAOE takes unit source, real x, real y, real radius, real damage returns integer
method damageDestructablesAOELoc takes unit source, location loc, real radius, real damage returns integer
-----------------------------------------------------------------------------------------------------------
This one damages all the destructables in a circle, regardless of damageTrees
being true or not.
xedamage static method
-----------------------
________________________________________________________________________________________________
static method getDamageTypeFactor takes unit u, attacktype a, damagetype d returns real
------------------------------------------------------------------------------------------------
This method is used by one of the factor methods up there, thought it would be
useful to make it available as a public method, it just returns the factor that
a specific attacktype/damagetype couple would do on a certain unit u:
set fc = xedamage.getDamageTypeFactor( GetTriggerUnit(), ATTACK_TYPE_NORMAL, DAMAGE_TYPE_FIRE)
Would return 1.0 if the unit is a normal unit, 1.66 if it is ethereal and 0 if it is spell immune.
xedamage event responses
------------------------
______________________________________________________________________
boolean isDummyDamage
----------------------------------------------------------------------
This variable is true when xedamage has performed "dummy damage" see
above for more details.
______________________________________________________________________
static method isInUse takes nothing returns boolean
----------------------------------------------------------------------
This method will return true if xedamage was in use during a damaged event,
this would help you determine if the damage was inflicted by a xedamage call.
_______________________________________________________________________
readonly static damagetype CurrentDamageType=null
readonly static attacktype CurrentAttackType=null
readonly static integer CurrentDamageTag =0
-----------------------------------------------------------------------
When isInUse() returns true, you can use these event responses to determine
how was the damage inflicted, you can get the damage type, the attack type and
the tag (specified by the field tag in the xedamage object) of the call.
if (xedamage.isInUse() ) then
if(xedamage.CurrentDamageType == DAMAGE_TYPE_FIRE ) then
call BJDebugMsg(R2S(GetEventDamage())+" fire damage was inflicted to "+GetUnitName(GetTriggerUnit() ) )
endif
call BJDebugMsg("tag used: "+I2S(xedamage.CurrentDamageTag) )
endif
--
The FireNovaStrike sample attempts to be a quick example on
how to use xedamage.
xecollider
----------
A specialization xefx, aids at creating 2D missiles with collision and speed
and that sort of stuff, notice you'd usually have to make a new struct and
extend xecollider from it so you can declare your own methods for handling
the hit event.
implementation
--------------
First of all, you need xefx, after you implement xefx, you may just copy
the xecollider trigger to your map.
I'd also recommend you to implement the BoundSentinel library to prevent
crashes related to the xecolliders moving too down in the map, you can find the
BoundSentinel in the "Extras" trigger category.
Notice this needs at least jasshelper 0.9.E.0 to compile.
xecollider object
-----------------
__________________________________________________________________________________________________
static method create takes real x, real y, real dir returns xecollider
- - - ----------
This is the create method, it will make a new xecollider object for you to
use, If you are extending xecollider and wish to have a custom create method
on your struct, remember that you will need to call allocate(x,y,dir)
set somevariable = myxecollider.create( GetUnitX(u), GetUnitY(u), angl )
_________________________________________________________________________________________________
method terminate takes nothing returns nothing
- - --------------
Call terminate() when you wish to 'kill' the missile, it will call .destroy()
automatically, I recommend you not to call .destroy() manually. Use onDestroy
to detect when it was called. You can use .x and .y on onDestroy...
Example: call somevariable.terminate()
_____________________________________________________________________________________________________
delegate xefx
-
A xecollider object is practically also a xefx object, you may call all of
the members in xefx for your disposal, including x,y,z (to change the position)
and height of the missile) and fxpath (the model used by the missile) please,
read the xefx documentation as it includes a lot of members used by xecollider.
________________________________________________________________________________
real expirationTime
- ------------------------------------------------------------
The missile will die after expirationTime seconds, notice this is just a
variable so you can modify and read it as you will, when the expirationTime
ends, the missile is 'killed' so onDestroy will be called. If you do not assign
this manually, the expirationTime will be 100.0 by default
Example: set somevar.expirationTime = 3.0 // Die after three seconds.
________________________________________________________________________________
real direction
- -----------------------------------------------------------------
Direction determines two things, the facing angle of the missile and the
direction at which the missile will move (if you enable speed, etc) Since
just about everything else uses radians this does as well.
Example: set somevar.direction = 0.5 * bj_PI // face north...
________________________________________________________________________________
real collisionSize
- -------------------------------------------------------------
xecollider wouldn't have that name if it wasn't for collision, if a unit's
collision circle collides with the xecollider's collisionSize, then your
onUnitHit method will be called. Notice that you can change collisionSize
dynamically.
Example: set somevar.collisionSize = 50.0
________________________________________________________________________________
real speed = 0.0
real acceleration = 0.0
real maxSpeed = DEFAULT_MAX_SPEED
real minSpeed = 0.0
- ------------------------------------------------------
The automatic movement is just 2D over the xy axis, so is the collision, simple
spells don't usually mess a lot with 3D... Speed would be the distance a
xecollider can move in a second, the acceleration is an increment of speed
per second, notice acceleration can be negative.
maxSpeed and minSpeed are caps for the speed in case acceleration was used.
Initially a missile has zero speed and zero acceleration , the minimum speed
is 0, which means a negative acceleration can never make speed go negative
(which would probably make the missile look as it is going backwards) The
default max speed is 1500, but you can tweak that by changing the constant
at the top of the xecollider library.
________________________________________________________________________________
real angleSpeed = 0.0
- ------------------------------------------------
Although it lacks a more formal name, this is the increment to the direction
angle during a second, this like the other variables, is in radians. It will
allow you to have missiles with curved movement, angleSpeed is also used by
homing (see bellow)
________________________________________________________________________________
unit targetUnit = null
- ---------------------------------------------------------
By assigning this member to a living unit, the xecollider will home towards
the unit's position. Notice that for this to work it will require an angleSpeed
higher than 0.0.
________________________________________________________________________________
method setTargetPoint takes real x, real y returns nothing
method setTargetPointLoc takes real x, real y returns nothing
- -----------------
This one makes the missile home towards a point. Same as targetUnit , it will
need an angleSpeed higher than 0.
________________________________________________________________________________
method forgetTargetPoint takes nothing returns nothing
- ------------------------
This method makes the xecollider forget it was homing towards a unit or point
then it becomes a normal missile, you may like to change angleSpeed as well
though.
xecollider event methods
------------------------
These are methods you may declare on your custom struct in order to listen to
the xecollider events.
________________________________________________________________________________
method onUnitHit takes unit hitTarget returns nothing defaults nothing
- - --------- -
The onUnitHit method is called whenever the missile hits a unit (the collision
circles intersect) it is similar to the UnitInRange event. hitTarget is the
unit that just collided with the missile.
________________________________________________________________________________
method loopControl takes nothing returns nothing defaults nothing
- ------- --------
This is a method that, if declared will be called every XE_ANIMATION_PERIOD
seconds, may allow you to save a timer loop.
The FireNovaStrike sample attempts to be a well explained example on how to
use xecollider, get used to this whole 'extends' stuff, as you'd see in the
example it makes things easier since you will not need to attach things anymore.
//TESH.scrollpos=0
//TESH.alwaysfold=0
xemissile
----------
A specialization xefx, aids at creating targeted missiles with arc and
speed and that sort of stuff, notice you'd usually have to make a new
struct and extend xemissile from it so you can declare your own methods
for handling the hit event.
implementation
--------------
First of all, you need xefx, after you implement xefx, you may just copy
the xemissile trigger to your map.
I'd also recommend you to implement the BoundSentinel library to prevent
crashes related to the xemissiles moving too down in the map, you can find the
BoundSentinel in the "Extras" trigger category.
Notice this needs at least jasshelper 0.9.E.0 to compile.
This library has two objects you can extend, xemissile and xehomingmissile.
xehomingmissile extends xemissile and is only there to provide an alternate
constructor for your convenience. You could also create a normal xemissile
and then give it a homing target and it would work the same as if you created
a xehmoingmissile.
xemissile object
-----------------
__________________________________________________________________________________________________
static method create takes real x, real y, real z, real tx, real ty, real tz returns xemissile
- - - ----------
This is the create method, it will make a new xemissile object for you to
launch, If you are extending xemissile and wish to have a custom create method
on your struct, remember that you will need to call allocate(x,y,z, tx,ty,tz)
set somevariable = myxemissile.create( GetUnitX(u),GetUnitY(u),GetUnitFlyHeight(u)+LAUNCH_OFFSET, targetx,targety,0.0 )
xehomingmissile object
-----------------
__________________________________________________________________________________________________
static method create takes real x, real y, real z, unit target, real zoffset returns xehomingmissile
- - - ----------
Same as the xemissile create method, except that the target now is not a
point, but a unit, which will be hit at zoffset from its origin point.
set somevariable = myxehomingmissile.create( GetUnitX(u), GetUnitY(u), GetUnitFlyHeight(u)+LAUNCH_OFFSET, target, HIT_OFFSET )
both objects
-----------------
_________________________________________________________________________________________________
method launch takes real speed, real arc returns nothing
- - -----------------
This launches the missile, it is a seperate method from .create in order to
keep method argument lists reasonably short, the xemissile create method
already takes 6 arguments. You will probably never create an xemissile without
launching it immediately afterwards.
The speed value determines how fast the missile will move and can later be
changed mid-flight, the arc value determines at what angle the missile will be
launched and works the same way as object editor missile arc values.
Example: call somevariable.launch(1000.0, 0.25)
_________________________________________________________________________________________________
method terminate takes nothing returns nothing
- - --------------
Call terminate() when you wish to 'kill' the missile, it will call .destroy()
automatically, I recommend you not to call .destroy() manually. Use onDestroy
to detect when it was called. You can use .x and .y on onDestroy...
Example: call somevariable.terminate()
_________________________________________________________________________________________________
method setTargetPoint takes real tx, real ty, real tz returns nothing
- - ---------
This method sets the point towards which the xemissile will fly. This point
is already automatically set by the create method, if the xemissile has a
targetUnit set then this point will be constantly updated to the position of
that unit. You can also manually set the target point with this method to
redirect the missile, if you do the missile will forget any homing target
it may have had.
Example: call somevariable.setTargetPoint(GetSpellTargetX(),GetSpellTargetY(),0.0)
_____________________________________________________________________________________________________
delegate xefx
-
A xemissile object is practically also a xefx object, you may call all of
the members in xefx for your disposal, including x,y,z (to change the position)
and height of the missile) and fxpath (the model used by the missile) please,
read the xefx documentation as it includes a lot of members used by xemissile.
________________________________________________________________________________
real speed = 0.0
- ------------------------------------------------------
The automatic movement is just a vertical arc that homes in on the target,
just like WC3 attack and spell missiles.
Speed would be the distance a xemissile can move in a second and should be
a positive value or the missile will not cooperate. Speed is automatically
set by the launch method but you can also set it manually after launch.
unit targetUnit = null
real zoffset = 0.0
- ------------------------------------------------------
By setting these two values you can make an xemissile home in on a unit.
These values are automatically set by the xehomingmissile's create method,
but you can also set them manually. If you set the unit to null or if the
unit is removed, the missile will break its homing and land at the unit's
last known coordinates.
xemissile event methods
------------------------
These are methods you may declare on your custom struct in order to listen to
the xemissile events.
________________________________________________________________________________
method onHit takes nothing returns nothing defaults nothing
- - ------------- --------
The onHit method is called when the missile hits its target. The missile will
be destroyed afterwards unless you re-launch it.
________________________________________________________________________________
method loopControl takes nothing returns nothing defaults nothing
- ------- --------
This is a method that, if declared will be called every XE_ANIMATION_PERIOD
seconds, may allow you to save a timer loop.
/*
vJass Damage Engine 5.A.0.0
This update enables compatibility with AttackIndexer.
*/
/*
JASS API:
struct Damage extends array
readonly static unit source // udg_DamageEventSource in real-time
readonly static unit target // udg_DamageEventTarget in real-time
static real amount // udg_DamageEventAmount in real-time
readonly unit sourceUnit // udg_DamageEventSource by index
readonly unit targetUnit // udg_DamageEventTarget by index
real damage // udg_DamageEventAmount by index
readonly real prevAmt // udg_DamageEventPrevAmt by index
attacktype attackType // udg_DamageEventAttackT by index
damagetype damageType // udg_DamageEventDamageT by index
weapontype weaponType // udg_DamageEventWeaponT by index
integer userType // udg_DamageEventType by index
readonly boolean isAttack // udg_IsDamageAttack by index
readonly boolean isCode // udg_IsDamageCode by index
readonly boolean isMelee // udg_IsDamageMelee by index
readonly boolean isRanged // udg_IsDamageRanged by index
readonly boolean isSpell // udg_IsDamageSpell by index
real armorPierced // udg_DamageEventArmorPierced by index
integer armorType // udg_DamageEventArmorT by index
integer defenseType // udg_DamageEventDefenseT by index
readonly integer eFilter
Set to false to disable the damage event triggers or to true to reverse that:
static boolean operator enabled
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 apply takes
unit source,
unit target,
real amount,
boolean isAttack,
boolean isRanged,
attacktype at,
damagetype dt,
weapontype wt
returns Damage
A simplified version of the above function that autofills each boolean, attacktype and weapontype.
static method applySpell takes
unit src,
unit tgt,
real amt,
damagetype dt
returns Damage
A different variation of the above which autofills the "isAttack" boolean
and populates damagetype as DAMAGE_TYPE_NORMAL.
static method applyAttack takes
unit src,
unit tgt,
real amt,
boolean ranged,
attacktype at,
weapontype wt
returns Damage
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:
- integer DamageEngine_FILTER_ATTACK
- integer DamageEngine_FILTER_MELEE
- integer DamageEngine_FILTER_OTHER
- integer DamageEngine_FILTER_RANGED
- integer DamageEngine_FILTER_SPELL
- integer DamageEngine_FILTER_CODE
boolean configured //set to True after configuring any filters listed below.
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
method configure takes nothing returns nothing
The string in the aruments below requires the following API:
"" for standard damage event
"Modifier(or Mod if you prefer)/After/Lethal/AOE" for the others
static method registerTrigger takes
trigger whichTrig,
string var,
real value
returns nothing
static method unregister takes
trigger whichTrig,
string eventName,
real value,
boolean reset
returns boolean
static method getIndex takes
trigger fromTrigger,
string eventName,
real value
returns integer
If you already have the index of the trigger you want to unregister:
method unregisterByIndex takes
boolean reset
returns boolean
Converts a code argument to a trigger, while checking if the same code had already been registered before.
Use it via DamageTrigger[function MyCallbackFunction]
static method operator [] takes
code callback
returns trigger
The accepted strings here use the same criteria as DamageTrigger.getIndex/registerTrigger/unregister:
function TriggerRegisterDamageEngineEx takes
trigger whichTrig,
string eventName,
real value,
integer opId
returns nothing
function TriggerRegisterDamageEngine takes
trigger whichTrig,
string eventName,
real value
returns nothing
function RegisterDamageEngineEx takes
code callback,
string eventName,
real value,
integer opId
returns nothing
function RegisterDamageEngine takes
code callback,
string eventName,
real value
returns nothing
*/
//===========================================================================
library DamageEngine requires optional AttackIndexer
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 SourceDamageEvent, 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
/*
When manually-enabled recursion is enabled via DamageEngine_inception,
the engine will never go deeper than MAX_RECURSIVE_TOLERANCE:
*/
private constant integer MAX_RECURSIVE_TOLERANCE = 16
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 M$ ever changes this, it'll be a quick fix here.
private timer async = null
private boolean timerStarted = false
//Values to track the original pre-spirit Link/defensive damage values
private Damage lastInstance = 0
private boolean isNotNativeRecursiveDamage = true
private boolean waitingForDamageEventToRun = false
private boolean array attacksImmune
private boolean array damagesImmune
//Primary triggers used to handle all damage events.
private trigger damagingTrigger = null
private trigger damagedTrigger = null
private trigger recursiveTrigger = null //Catches, stores recursive events
/*
These variables coincide with Blizzard's "limitop" type definitions
so as to enable GUI users with some performance perks - however,
these optimizations need to be tested
*/
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
/*
When true, it allows your trigger to go recursively up to
MAX_RECURSIVE_TOLERANCE (if needed). It must be set before dealing damage.
*/
public boolean inception = false
private boolean callbacksInProgress = false
private integer recursiveCallbackDepth = 0
private group recursionSources = null
private group recursionTargets = null
private boolean recursiveCallbaksInProgress = false
private boolean nativeEventsCompleted = false
private boolean atLeastOneLethalDamageEventRegistered = false
// Struct members made private to this library.
private keyword run
private keyword trigFrozen
private keyword ownRecursiveDepth
private keyword manualRecursionRequested
endglobals
native UnitAlive takes unit u returns boolean
//GUI Vars:
/*
Retained from 3.8 and prior:
----------------------------
unit udg_DamageEventSource
unit udg_DamageEventTarget
unit udg_EnhancedDamageTarget
group udg_DamageEventAOEGroup
integer udg_DamageEventAOE
integer udg_DamageEventLevel
real udg_DamageModifierEvent
real udg_DamageEvent
real udg_AfterDamageEvent
real udg_DamageEventAmount
real udg_DamageEventPrevAmt
real udg_AOEDamageEvent
boolean udg_DamageEventOverride
boolean udg_NextDamageType
boolean udg_DamageEventType
boolean udg_IsDamageSpell
//Added in 5.0:
boolean udg_IsDamageMelee
boolean udg_IsDamageRanged
unit udg_AOEDamageSource
real udg_LethalDamageEvent
real udg_LethalDamageHP
real udg_DamageScalingWC3
integer udg_DamageEventAttackT
integer udg_DamageEventDamageT
integer udg_DamageEventWeaponT
//Added in 5.1:
boolean udg_IsDamageCode
//Added in 5.2:
integer udg_DamageEventArmorT
integer udg_DamageEventDefenseT
//Addded in 5.3:
real DamageEventArmorPierced
real udg_DamageScalingUser
//Added in 5.4.2 to allow GUI users to re-issue the exact same attack and damage type at the attacker.
attacktype array udg_CONVERTED_ATTACK_TYPE
damagetype array udg_CONVERTED_DAMAGE_TYPE
//Added after Reforged introduced the new native BlzGetDamageIsAttack
boolean udg_IsDamageAttack
//Added in 5.6 to give GUI users control over the "IsDamageAttack", "IsDamageRanged" and "DamageEventWeaponT" field
boolean udg_NextDamageIsAttack //The first boolean value in the UnitDamageTarget native
boolean udg_NextDamageIsMelee //Flag the damage classification as melee
boolean udg_NextDamageIsRanged //The second boolean value in the UnitDamageTarget native
integer udg_NextDamageWeaponT //Allows control over damage sound effect
//Added in 5.7 to enable efficient, built-in filtering (see the below "checkConfig" method - I recommend commenting-out anything you don't need in your map)
integer udg_DamageFilterAttackT
integer udg_DamageFilterDamageT //filter for a specific attack/damage type
unit udg_DamageFilterSource
unit udg_DamageFilterTarget //filter for a specific source/target
integer udg_DamageFilterSourceT
integer udg_DamageFilterTargetT //unit type of source/target
integer udg_DamageFilterType //which DamageEventType was used
integer udg_DamageFilterSourceB
integer udg_DamageFilterTargetB //if source/target has a buff
real udg_DamageFilterMinAmount //only allow a minimum damage threshold
//Added in 5.8:
boolean udg_RemoveDamageEvent //Allow GUI users to more fully unregister a damage event trigger. Can only be used from within a damage event (of any kind).
integer udg_DamageFilterSourceA
integer udg_DamageFilterTargetA //Check if a source or target have a specific ability (will overwrite any source or target buff check, I need to use this because GUI differentiates ability ID and buff ID)
integer udg_DamageFilterSourceI
integer udg_DamageFilterTargetI //Check if a source or target have a specific type of item
integer udg_DamageFilterSourceC
integer udg_DamageFilterTargetC //Classification of source/target (e.g. hero, treant, ward)
//Added in 5.9
real udg_SourceDamageEvent //Like AOEDamageEvent, fires each time the source unit has finished dealing damage, but doesn't care if the damage hit multiple units.
real udg_PreDamageEvent //Like DamageModifierEvent 3.99 or less, except can be any real value.
real udg_ArmorDamageEvent //Like DamageModifierEvent 4.00 or more, except can be any real value.
real udg_OnDamageEvent //Like DamageEvent equal to 1.00 or some non-zero/non-2 value, except can be any real value.
real udg_ZeroDamageEvent //Like DamageEvent equal to 0.00 or 2.00, except can be any real value.
*/
struct DamageTrigger extends array
static method checkItem takes unit u, integer id returns boolean
local integer i
if IsUnitType(u, UNIT_TYPE_HERO) then
set i = UnitInventorySize(u)
loop
exitwhen i <= 0
set i = i - 1
if GetItemTypeId(UnitItemInSlot(u, i)) == id then
return true
endif
endloop
endif
return false
endmethod
/*
Map makers should probably not use these filters,
unless someone tests performance to see
if such an ugly hack is even worth it.
*/
method checkConfig takes nothing returns boolean
//call BJDebugMsg("Checking configuration")
if this.sourceType != 0 and GetUnitTypeId(udg_DamageEventSource) != this.sourceType then
elseif this.targetType != 0 and GetUnitTypeId(udg_DamageEventTarget) != this.targetType then
elseif this.sourceBuff != 0 and GetUnitAbilityLevel(udg_DamageEventSource, this.sourceBuff) == 0 then
elseif this.targetBuff != 0 and GetUnitAbilityLevel(udg_DamageEventTarget, this.targetBuff) == 0 then
elseif this.failChance > 0.00 and GetRandomReal(0.00, 1.00) <= this.failChance then
elseif this.userType != 0 and udg_DamageEventType != this.userType then
elseif this.source != null and this.source != udg_DamageEventSource then
elseif this.target != null and this.target != udg_DamageEventTarget then
elseif this.attackType >= 0 and this.attackType != udg_DamageEventAttackT then
elseif this.damageType >= 0 and this.damageType != udg_DamageEventDamageT then
elseif this.sourceItem != 0 and not .checkItem(udg_DamageEventSource, this.sourceItem) then
elseif this.targetItem != 0 and not .checkItem(udg_DamageEventTarget, this.targetItem) then
elseif this.sourceClass >= 0 and not IsUnitType(udg_DamageEventSource, ConvertUnitType(this.sourceClass)) then
elseif this.targetClass >= 0 and not IsUnitType(udg_DamageEventTarget, ConvertUnitType(this.targetClass)) then
elseif udg_DamageEventAmount >= this.damageMin then
//call BJDebugMsg("Configuration passed")
return true
endif
//call BJDebugMsg("Checking failed")
return false
endmethod
//The below variables are to be treated as constant
readonly static thistype MOD = 1
readonly static thistype SHIELD = 4
readonly static thistype DAMAGE = 5
readonly static thistype ZERO = 6
readonly static thistype AFTER = 7
readonly static thistype LETHAL = 8
readonly static thistype AOE = 9
private static integer count = 9
static thistype lastRegistered = 0
private static thistype array trigIndexStack
static thistype eventIndex = 0
static boolean array filters
readonly string eventStr
readonly real weight
boolean usingGUI
private thistype next
private trigger rootTrig
//The below variables are to be treated as private
boolean trigFrozen //Whether the trigger is currently disabled due to recursion
integer ownRecursiveDepth //How deep the user recursion currently is.
boolean manualRecursionRequested //Added in 5.4.2 to simplify the inception variable for very complex DamageEvent triggers.
//configuration variables:
boolean configured
unit source
unit target
integer sourceType
integer targetType
integer sourceBuff
integer targetBuff
integer sourceItem
integer targetItem
integer sourceClass
integer targetClass
real damageMin
real failChance
integer attackType
integer damageType
integer userType
// getter:
method operator runChance takes nothing returns real
return 1.00 - this.failChance
endmethod
// setter:
method operator runChance= takes real chance returns nothing
set this.failChance = 1.00 - chance
endmethod
method configure takes nothing returns nothing
set this.attackType = udg_DamageFilterAttackT
set this.damageType = udg_DamageFilterDamageT
set this.source = udg_DamageFilterSource
set this.target = udg_DamageFilterTarget
set this.sourceType = udg_DamageFilterSourceT
set this.targetType = udg_DamageFilterTargetT
set this.sourceItem = udg_DamageFilterSourceI
set this.targetItem = udg_DamageFilterTargetI
set this.sourceClass = udg_DamageFilterSourceC
set this.targetClass = udg_DamageFilterTargetC
set this.userType = udg_DamageFilterType
set this.damageMin = udg_DamageFilterMinAmount
set this.failChance = 1.00 - (udg_DamageFilterRunChance - udg_DamageFilterFailChance)
if udg_DamageFilterSourceA > 0 then
set this.sourceBuff = udg_DamageFilterSourceA
set udg_DamageFilterSourceA = 0
else
set this.sourceBuff = udg_DamageFilterSourceB
endif
if udg_DamageFilterTargetA > 0 then
set this.targetBuff = udg_DamageFilterTargetA
set udg_DamageFilterTargetA = 0
else
set this.targetBuff = udg_DamageFilterTargetB
endif
set udg_DamageFilterSource = null
set udg_DamageFilterTarget = null
//These handles can have a valid value of 0, so we need to distinguish them.
set udg_DamageFilterAttackT = -1
set udg_DamageFilterDamageT = -1
set udg_DamageFilterSourceC = -1
set udg_DamageFilterTargetC = -1
set udg_DamageFilterSourceT = 0
set udg_DamageFilterTargetT = 0
set udg_DamageFilterType = 0
set udg_DamageFilterSourceB = 0
set udg_DamageFilterTargetB = 0
set udg_DamageFilterSourceI = 0
set udg_DamageFilterTargetI = 0
set udg_DamageFilterMinAmount = 0.00
set udg_DamageFilterFailChance = 0.00
set udg_DamageFilterRunChance = 1.00
set this.configured = true
endmethod
static method setGUIFromStruct takes boolean full returns nothing
set udg_DamageEventAmount = Damage.index.damage
set udg_DamageEventAttackT = GetHandleId(Damage.index.attackType)
set udg_DamageEventDamageT = GetHandleId(Damage.index.damageType)
set udg_DamageEventWeaponT = GetHandleId(Damage.index.weaponType)
set udg_DamageEventType = Damage.index.userType
static if USE_ARMOR_MOD then
set udg_DamageEventArmorPierced = Damage.index.armorPierced
set udg_DamageEventArmorT = Damage.index.armorType
set udg_DamageEventDefenseT = Damage.index.defenseType
endif
if full then
set udg_DamageEventSource = Damage.index.sourceUnit
set udg_DamageEventTarget = Damage.index.targetUnit
set udg_DamageEventPrevAmt = Damage.index.prevAmt
set udg_IsDamageAttack = Damage.index.isAttack
set udg_IsDamageCode = Damage.index.isCode
set udg_IsDamageSpell = Damage.index.isSpell
//! runtextmacro optional ATTACK_INDEXER_GUI_VARS()
static if USE_MELEE_RANGE then
set udg_IsDamageMelee = Damage.index.isMelee
set udg_IsDamageRanged = Damage.index.isRanged
endif
endif
endmethod
static method setStructFromGUI takes nothing returns nothing
set Damage.index.damage = udg_DamageEventAmount
set Damage.index.attackType = ConvertAttackType(udg_DamageEventAttackT)
set Damage.index.damageType = ConvertDamageType(udg_DamageEventDamageT)
set Damage.index.weaponType = ConvertWeaponType(udg_DamageEventWeaponT)
set Damage.index.userType = udg_DamageEventType
static if USE_ARMOR_MOD then
set Damage.index.armorPierced = udg_DamageEventArmorPierced
set Damage.index.armorType = udg_DamageEventArmorT
set Damage.index.defenseType = udg_DamageEventDefenseT
endif
endmethod
static method getVerboseStr takes string eventName returns string
if eventName == "Modifier" or eventName == "Mod" then
return "udg_DamageModifierEvent"
endif
return "udg_" + eventName + "DamageEvent"
endmethod
private static method getStrIndex takes string var, real lbs returns thistype
local integer root = R2I(lbs)
if (var == "udg_DamageModifierEvent" and root < 4) or var == "udg_PreDamageEvent" then
set root = MOD
elseif var == "udg_DamageModifierEvent" or var == "udg_ArmorDamageEvent" then
set root = SHIELD
elseif (var == "udg_DamageEvent" and root == 2 or root == 0) or var == "udg_ZeroDamageEvent" then
set root = ZERO
elseif var == "udg_DamageEvent" or var == "udg_OnDamageEvent" then
set root = DAMAGE
elseif var == "udg_AfterDamageEvent" then
set root = AFTER
elseif var == "udg_LethalDamageEvent" then
set root = LETHAL
elseif var == "udg_AOEDamageEvent" or var == "udg_SourceDamageEvent" then
set root = AOE
else
set root = 0
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_GDD()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_PDD()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_05()
endif
return root
endmethod
private method toggleAllFilters takes boolean flag returns nothing
set filters[this + FILTER_ATTACK] = flag
set filters[this + FILTER_MELEE] = flag
set filters[this + FILTER_OTHER] = flag
set filters[this + FILTER_RANGED] = flag
set filters[this + FILTER_SPELL] = flag
set filters[this + FILTER_CODE] = flag
endmethod
method operator filter= takes integer opId returns nothing
set this = this * FILTER_MAX
if opId == FILTER_OTHER then
call this.toggleAllFilters(true)
else
if opId == 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 + opId] = 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
//allows GUI to register multiple different types of Damage filters to the same trigger
set filters[lastRegistered*FILTER_MAX + filt] = true
return 0
endif
set atLeastOneLethalDamageEventRegistered = /*
*/ atLeastOneLethalDamageEventRegistered or index == LETHAL
if trigIndexStack[0] == 0 then
set count = count + 1 //List runs from index 10 and up
set id = count
else
set id = trigIndexStack[0]
set trigIndexStack[0] = trigIndexStack[id]
endif
set lastRegistered = id
set id.filter = filt
set id.rootTrig = whichTrig
set id.usingGUI = GUI
set id.weight = lbs
set id.eventStr = var
//Next 2 lines added to fix a bug when using manual vJass configuration,
//discovered and solved by lolreported
set id.attackType = -1
set id.damageType = -1
//they will probably bug out with class types as well, so I should add them, just in case:
set id.sourceClass = -1
set id.targetClass = -1
loop
set i = index.next
exitwhen i == 0 or lbs < i.weight
set index = i
endloop
set index.next = id
set id.next = i
//call BJDebugMsg("Registered " + I2S(id) + " to " + I2S(index) + " and before " + I2S(i))
return lastRegistered
endmethod
static method registerTrigger takes trigger t, string var, real lbs returns thistype
return registerVerbose(t, DamageTrigger.getVerboseStr(var), lbs, false, FILTER_OTHER)
endmethod
private static thistype prev = 0
static method getIndex takes /*
*/ trigger t, /*
*/ string eventName, /*
*/ real lbs /*
*/ returns thistype
local thistype index = getStrIndex(getVerboseStr(eventName), lbs)
loop
set prev = index
set index = index.next
exitwhen index == 0 or index.rootTrig == t
endloop
return index
endmethod
method unregisterByIndex takes boolean reset returns boolean
if this == 0 then
return false
endif
set prev.next = this.next
set trigIndexStack[this] = trigIndexStack[0]
set trigIndexStack[0] = this
if reset then
call this.configure()
set this.configured = false
call thistype(this*FILTER_MAX).toggleAllFilters(false)
endif
return true
endmethod
static method unregister takes /*
*/ trigger t, /*
*/ string eventName, /*
*/ real lbs, /*
*/ boolean reset /*
*/ returns boolean
return getIndex(t, eventName, lbs).unregisterByIndex(reset)
endmethod
method run takes nothing returns nothing
local integer cat = this
local Damage d = Damage.index
static if USE_GUI then
local boolean structUnset = false
local boolean guiUnset = false
local boolean mod = cat <= DAMAGE
endif
if callbacksInProgress then
return
endif
set callbacksInProgress = true
call DisableTrigger(damagingTrigger)
call DisableTrigger(damagedTrigger)
call EnableTrigger(recursiveTrigger)
//call BJDebugMsg("Start of event running")
loop
set this = this.next
exitwhen this == 0
exitwhen cat == MOD and (udg_DamageEventOverride or udg_DamageEventType == TYPE_PURE)
exitwhen cat == SHIELD and udg_DamageEventAmount <= 0.00
static if USE_LETHAL then
exitwhen cat == LETHAL and udg_LethalDamageHP > DEATH_VAL
endif
set eventIndex = this
if (not this.trigFrozen) and /*
*/ filters[this*FILTER_MAX + d.eFilter] and /*
*/ IsTriggerEnabled(this.rootTrig) and /*
*/ ((not this.configured) or (this.checkConfig())) and /*
*/ (cat != AOE or udg_DamageEventAOE > 1 or this.eventStr == "udg_SourceDamageEvent") /*
*/ then
static if USE_GUI then
if mod then
if this.usingGUI then
if guiUnset then
set guiUnset = false
call setGUIFromStruct(false)
endif
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_PDD()
elseif structUnset then
set structUnset = false
call setStructFromGUI()
endif
endif
endif
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_05()
//JASS users who do not use actions can modify the below block to just evaluate.
//It should not make any perceptable difference in terms of performance.
if TriggerEvaluate(this.rootTrig) then
call TriggerExecute(this.rootTrig)
endif
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_05()
static if USE_GUI then
if mod then
if this.usingGUI then
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_PDD()
if cat != MOD then
set d.damage = udg_DamageEventAmount
else
set structUnset = true
endif
elseif cat != MOD then
set udg_DamageEventAmount = d.damage
else
set guiUnset = true
endif
endif
if udg_RemoveDamageEvent then
set udg_RemoveDamageEvent = false
call this.unregisterByIndex(true)
endif
endif
endif
endloop
static if USE_GUI then
if structUnset then
call setStructFromGUI()
endif
if guiUnset then
call setGUIFromStruct(false)
endif
else
call setGUIFromStruct(false)
endif
//call BJDebugMsg("End of event running")
call DisableTrigger(recursiveTrigger)
call EnableTrigger(damagingTrigger)
call EnableTrigger(damagedTrigger)
set callbacksInProgress = false
endmethod
/*
Used by RegisterDamageEngineEx to create triggers behind-the-scenes,
allowing the user to simply pass the function they want to execute.
*/
static trigger array autoTriggers
static boolexpr array autoFuncs
static integer autoN = 0
static method operator [] takes code callback returns trigger
local integer i = 0
local boolexpr b = Filter(callback)
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
readonly unit targetUnit
real damage
readonly real prevAmt
attacktype attackType
damagetype damageType
weapontype weaponType
integer userType
readonly boolean isAttack
readonly boolean isCode
readonly boolean isSpell
static if USE_MELEE_RANGE then
readonly boolean isMelee //stores udg_IsDamageMelee
endif
readonly boolean isRanged //stores udg_IsDamageRanged
readonly integer eFilter //stores the previous eventFilter variable
static if USE_ARMOR_MOD then
real armorPierced //stores udg_DamageEventArmorPierced
integer armorType //stores udg_DamageEventArmorT
integer defenseType //stores udg_DamageEventDefenseT
endif
readonly static Damage index = 0
private static Damage damageStack = 0
private static Damage prepped = 0
private static integer count = 0 //The number of currently-running queued or sequential damage instances
private Damage stackRef
private DamageTrigger recursiveTrig
private integer prevArmorT
private integer prevDefenseT
static method operator source takes nothing returns unit
return udg_DamageEventSource
endmethod
static method operator target takes nothing returns unit
return udg_DamageEventTarget
endmethod
static method operator amount takes nothing returns real
return Damage.index.damage
endmethod
static method operator amount= takes real r returns nothing
set Damage.index.damage = r
endmethod
static if USE_ARMOR_MOD then
private method setArmor takes boolean reset returns nothing
local real pierce
local integer at
local integer dt
if reset then
set pierce = udg_DamageEventArmorPierced
set at = Damage.index.prevArmorT
set dt = Damage.index.prevDefenseT
set udg_DamageEventArmorPierced = 0.00
set this.armorPierced = 0.00
else
set pierce = -udg_DamageEventArmorPierced
set at = udg_DamageEventArmorT
set dt = udg_DamageEventDefenseT
endif
if not (pierce == 0.00) then //Changed from != to not == due to bug reported by BLOKKADE
call BlzSetUnitArmor(udg_DamageEventTarget, BlzGetUnitArmor(udg_DamageEventTarget) + pierce)
endif
if Damage.index.prevArmorT != udg_DamageEventArmorT then
call BlzSetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_ARMOR_TYPE, at)
endif
if Damage.index.prevDefenseT != udg_DamageEventDefenseT then
call BlzSetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_DEFENSE_TYPE, dt)
endif
endmethod
endif
static if USE_EXTRA then
private static method onAOEEnd takes nothing returns nothing
call DamageTrigger.AOE.run()
set udg_DamageEventAOE = 1
set udg_DamageEventLevel = 1
set udg_EnhancedDamageTarget = null
set udg_AOEDamageSource = null
call GroupClear(udg_DamageEventAOEGroup)
endmethod
endif
private static method afterDamage takes nothing returns nothing
if udg_DamageEventDamageT != 0 and not (udg_DamageEventPrevAmt == 0.00) then
call DamageTrigger.AFTER.run()
set udg_DamageEventDamageT = 0
set udg_DamageEventPrevAmt = 0.00
endif
endmethod
private method runDamagingEvents 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(recursionSources, udg_DamageEventSource)
call GroupAddUnit(recursionTargets, 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()
// Using not == instead of !=; the idea is to eliminate floating point bugs when two numbers are very close to 0,
// because JASS uses a less-strict comparison for checking if a number is equal than when it is unequal.
if not (udg_DamageEventAmount == 0.00) then
set udg_DamageEventOverride = udg_DamageEventDamageT == 0
call DamageTrigger.MOD.run()
static if not USE_GUI then
call DamageTrigger.setGUIFromStruct(false)
endif
if natural then
call BlzSetEventAttackType(this.attackType)
call BlzSetEventDamageType(this.damageType)
call BlzSetEventWeaponType(this.weaponType)
call BlzSetEventDamage(udg_DamageEventAmount)
endif
static if USE_ARMOR_MOD then
call this.setArmor(false)
endif
return false
endif
return true //return value is based on whether the event is a 0 damage event (true) or not (false).
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.ownRecursiveDepth = 0
endloop
call EnableTrigger(damagingTrigger)
call EnableTrigger(damagedTrigger)
set recursiveCallbaksInProgress = false
set damageStack = 0
set prepped = 0
set callbacksInProgress = false
set recursiveCallbackDepth = 0
call GroupClear(recursionSources)
call GroupClear(recursionTargets)
//call BJDebugMsg("Cleared up the groups")
endmethod
static method runAfterDamageEvents takes nothing returns nothing
local Damage i = 0
local integer exit
if nativeEventsCompleted then
set nativeEventsCompleted = false
call afterDamage()
endif
if isNotNativeRecursiveDamage and not recursiveCallbaksInProgress then
if damageStack != 0 then
set recursiveCallbaksInProgress = true
loop
/*
Use two loops. The outer loop handles all normal event
execution, while the inner loop intelligently handles
recursive execution (when it's used).
*/
set recursiveCallbackDepth = recursiveCallbackDepth + 1
set exit = damageStack
loop
set prepped = i.stackRef
if UnitAlive(prepped.targetUnit) then
// We don't need to trigger `damagingTrigger` itself, so just call its handler directly.
call prepped.runDamagingEvents(false)
if prepped.damage > 0.00 then
call DisableTrigger(damagingTrigger) // Disallow `damagingTrigger` because we only want `damageTrigger` to run.
call EnableTrigger(damagedTrigger) // Re-enable `damagedTrigger` in case the user forgot to do so.
set waitingForDamageEventToRun = true
call UnitDamageTarget( /*
*/ prepped.sourceUnit, /*
*/ prepped.targetUnit, /*
*/ prepped.damage, /*
*/ prepped.isAttack, /*
*/ prepped.isRanged, /*
*/ prepped.attackType, /*
*/ prepped.damageType, /*
*/ prepped.weaponType /*
*/ )
else
if udg_DamageEventDamageT != 0 then
//No native events run at all in this case
call DamageTrigger.DAMAGE.run()
endif
if prepped.damage < 0.00 then
/*
No need for BlzSetEventDamage/UnitDamageTarget here,
because we can safely adjust the unit's life instead.
*/
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 isNotNativeRecursiveDamage = true
set recursiveCallbaksInProgress = false
set waitingForDamageEventToRun = false
if udg_DamageEventDamageT != 0 then
call DamageTrigger.DAMAGE.run()
set nativeEventsCompleted = true
endif
call runAfterDamageEvents()
endmethod
static method operator enabled= takes boolean b returns nothing
if b then
if callbacksInProgress then
call EnableTrigger(recursiveTrigger)
else
call EnableTrigger(damagingTrigger)
call EnableTrigger(damagedTrigger)
endif
else
if callbacksInProgress then
call DisableTrigger(recursiveTrigger)
else
call DisableTrigger(damagingTrigger)
call DisableTrigger(damagedTrigger)
endif
endif
endmethod
static method operator enabled takes nothing returns boolean
return IsTriggerEnabled(damagingTrigger)
endmethod
private static boolean threadCompleted = false
private static method asyncCallbackSafeCallback takes nothing returns nothing
if waitingForDamageEventToRun then
/*
This means that WarCraft 3 didn't run the DAMAGED event despite running the DAMAGING event.
*/
call failsafeClear()
else
set isNotNativeRecursiveDamage = true
set recursiveCallbaksInProgress = false
call runAfterDamageEvents()
endif
static if USE_EXTRA then
call onAOEEnd()
endif
set threadCompleted = true
endmethod
private static method asyncCallback takes nothing returns nothing
set callbacksInProgress = false
set Damage.enabled = true
/*
Open a new thread in case of a thread crash during callback.
*/
call ForForce(bj_FORCE_PLAYER[0], function thistype.asyncCallbackSafeCallback)
if not threadCompleted then
//call BJDebugMsg("DamageEngine issue: thread crashed!")
call unfreeze()
else
set threadCompleted = false
endif
set Damage.count = 0
set Damage.index = 0
set timerStarted = false
//call BJDebugMsg("Timer wrapped up")
endmethod
private method addRecursive takes nothing returns nothing
local DamageTrigger currentIndex
if not (this.damage == 0.00) then
set currentIndex = DamageTrigger.eventIndex
set this.recursiveTrig = currentIndex
if not this.isCode then
/*
If the recursive damage trigger is executed, this can only
mean that the user has manually dealt damage from a trigger.
Hence flag the damage as being 'code' if they didn't already
manually do this.
*/
set this.isCode = true
set this.userType = TYPE_CODE
endif
set inception = inception or /*
*/ currentIndex.manualRecursionRequested
if recursiveCallbaksInProgress and /*
*/ IsUnitInGroup(this.sourceUnit, recursionSources) and /*
*/ IsUnitInGroup(this.targetUnit, recursionTargets) /*
*/ then
if not inception then
set currentIndex.trigFrozen = true
elseif not currentIndex.trigFrozen then
set currentIndex.manualRecursionRequested = true
if currentIndex.ownRecursiveDepth < recursiveCallbackDepth then
set currentIndex.ownRecursiveDepth = /*
*/ currentIndex.ownRecursiveDepth + 1
if currentIndex.ownRecursiveDepth >= MAX_RECURSIVE_TOLERANCE then
set currentIndex.trigFrozen = true
endif
endif
endif
endif
// push the reference to the top of the damage stack.
set damageStack.stackRef = this
set damageStack = damageStack + 1
//call BJDebugMsg("damageStack: " + I2S(damageStack) + " ownRecursiveDepth: " + I2S(currentIndex.ownRecursiveDepth) + " recursiveCallbackDepth: " + I2S(recursiveCallbackDepth))
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 isAttack, /*
*/ 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.damageType = dt
set d.attackType = at
set d.weaponType = wt
set d.isAttack = udg_NextDamageIsAttack or isAttack
set d.isSpell = d.attackType == null and not d.isAttack
return d
endmethod
private static method createFromEvent takes nothing returns Damage
local Damage d = thistype.create( /*
*/ GetEventDamageSource(), /*
*/ GetTriggerUnit(), /*
*/ GetEventDamage(), /*
*/ BlzGetEventIsAttack(), /*
*/ BlzGetEventAttackType(), /*
*/ BlzGetEventDamageType(), /*
*/ BlzGetEventWeaponType() /*
*/ )
set d.isCode = udg_NextDamageType != 0 or /*
*/ udg_NextDamageIsAttack or /*
*/ udg_NextDamageIsRanged or /*
*/ udg_NextDamageIsMelee or /*
*/ d.damageType == DAMAGE_TYPE_MIND or /*
*/ udg_NextDamageWeaponT != 0 or /*
*/ (d.damageType == DAMAGE_TYPE_UNKNOWN and not (d.damage == 0.00))
if d.isCode then
if udg_NextDamageType != 0 then
set d.userType = udg_NextDamageType
else
set d.userType = TYPE_CODE
endif
static if USE_MELEE_RANGE then
set d.isMelee = udg_NextDamageIsMelee
set d.isRanged = udg_NextDamageIsRanged
endif
set d.eFilter = FILTER_CODE
if udg_NextDamageWeaponT != 0 then
set d.weaponType = ConvertWeaponType(udg_NextDamageWeaponT)
set udg_NextDamageWeaponT = 0
endif
else
set d.userType = 0
if d.damageType == DAMAGE_TYPE_NORMAL and d.isAttack then
// Added in version 5.A in order to allow an optional external
// Attack Indexer system to reset the event weapon type to normal.
//! runtextmacro optional ATTACK_INDEXER_ADJUSTMENTS()
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
// Melee units always play a sound when damaging in WC3,
// so this is an easy check.
set d.isMelee = d.weaponType != null
// In the case where a unit is both ranged and melee,
// the ranged attack plays no sound.
set d.isRanged = not d.isMelee
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
// Spells are neither melee nor ranged.
set d.isMelee = false
set d.isRanged = false
endif
endif
endif
call clearNexts()
return d
endmethod
private static method onRecursiveDamageCallback takes nothing returns boolean
local Damage d = Damage.createFromEvent()
call d.addRecursive()
call BlzSetEventDamage(0.00)
return false
endmethod
private static method onDamagingCallback takes nothing returns boolean
local Damage d = Damage.createFromEvent()
//call BJDebugMsg("Pre-damage event running for " + GetUnitName(GetTriggerUnit()))
if timerStarted then
if waitingForDamageEventToRun 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 waitingForDamageEventToRun = false
set lastInstance = Damage.index
set isNotNativeRecursiveDamage = false
else
call failsafeClear() //Not an overlapping event - just wrap it up
endif
else
call runAfterDamageEvents() //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
set udg_EnhancedDamageTarget = d.targetUnit
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(async, 0.00, false, function Damage.asyncCallback)
set timerStarted = 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.runDamagingEvents(true) then
call DamageTrigger.ZERO.run()
set isNotNativeRecursiveDamage = true
call runAfterDamageEvents()
endif
set waitingForDamageEventToRun = 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 onDamagedCallback 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 callbacksInProgress or d.prevAmt == 0.00 then
return false
elseif waitingForDamageEventToRun then
set waitingForDamageEventToRun = false
else
/*
This should only happen for native recursive WarCraft 3 damage
such as Spirit Link, Thorns Aura, or Spiked Carapace / Barricades.
*/
call afterDamage()
set Damage.index = lastInstance
set lastInstance = 0
set d = Damage.index
/*
Since the native recursive damage has now wrapped up, we can resume
handling events as normal at this point. This means that the original
target that the DAMAGING event was triggered for is now finally getting
its DAMAGED event.
*/
set isNotNativeRecursiveDamage = true
call DamageTrigger.setGUIFromStruct(true)
endif
static if USE_ARMOR_MOD then
call d.setArmor(true)
endif
static if USE_SCALING then
if not (udg_DamageEventAmount == 0.00) and not (r == 0.00) then
set udg_DamageScalingWC3 = r / udg_DamageEventAmount
elseif udg_DamageEventAmount > 0.00 then
set udg_DamageScalingWC3 = 0.00
else
set udg_DamageScalingWC3 = 1.00
if udg_DamageEventPrevAmt == 0.00 then
set udg_DamageScalingUser = 0.00
else
set udg_DamageScalingUser = /*
*/ udg_DamageEventAmount / udg_DamageEventPrevAmt
endif
endif
endif
set udg_DamageEventAmount = r
set d.damage = r
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_GDD()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_PDD()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_05()
if udg_DamageEventAmount > 0.00 then
call DamageTrigger.SHIELD.run()
static if not USE_GUI then
set udg_DamageEventAmount = d.damage
endif
static if USE_LETHAL then
if atLeastOneLethalDamageEventRegistered or udg_DamageEventType < 0 then
set udg_LethalDamageHP = /*
*/ GetWidgetLife(udg_DamageEventTarget) - udg_DamageEventAmount
if udg_LethalDamageHP <= DEATH_VAL then
if atLeastOneLethalDamageEventRegistered 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 nativeEventsCompleted = true
if udg_DamageEventAmount == 0.00 then
call runAfterDamageEvents()
endif
// This return statement was needed years ago to avoid potential crashes on Mac.
// I am not sure if that's still a thing.
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 callbacksInProgress 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 runAfterDamageEvents()
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
/*
This part is the most critical to get things kicked off. All the code we've seen up until now
is related to event handling, trigger assignment, edge cases, etc. But it's the following that
is really quite esesntial for any damage engine - not just this one.
*/
private static method onInit takes nothing returns nothing
set async = CreateTimer()
set recursionSources = CreateGroup()
set recursionTargets = CreateGroup()
set damagingTrigger = CreateTrigger()
set damagedTrigger = CreateTrigger()
set recursiveTrigger = CreateTrigger() //Moved from globals block as per request of user Ricola3D
call TriggerRegisterAnyUnitEventBJ(damagingTrigger, EVENT_PLAYER_UNIT_DAMAGING)
call TriggerAddCondition(damagingTrigger, Filter(function Damage.onDamagingCallback))
call TriggerRegisterAnyUnitEventBJ(damagedTrigger, EVENT_PLAYER_UNIT_DAMAGED)
call TriggerAddCondition(damagedTrigger, Filter(function Damage.onDamagedCallback))
//For recursion
call TriggerRegisterAnyUnitEventBJ(recursiveTrigger, EVENT_PLAYER_UNIT_DAMAGING)
call TriggerAddCondition(recursiveTrigger, Filter(function Damage.onRecursiveDamageCallback))
call DisableTrigger(recursiveTrigger) //starts disabled. Will be enabled during recursive event handling.
/*
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
// Called from the GUI configuration trigger once the assignments are in place.
public function DebugStr takes nothing returns nothing
local integer i = 0
loop
set udg_CONVERTED_ATTACK_TYPE[i] = ConvertAttackType(i)
exitwhen i == 6
set i = i + 1
endloop
set i = 0
loop
set udg_CONVERTED_DAMAGE_TYPE[i] = ConvertDamageType(i)
exitwhen i == 26
set i = i + 1
endloop
set udg_AttackTypeDebugStr[0] = "SPELLS" //ATTACK_TYPE_NORMAL in JASS
set udg_AttackTypeDebugStr[1] = "NORMAL" //ATTACK_TYPE_MELEE in JASS
set udg_AttackTypeDebugStr[2] = "PIERCE"
set udg_AttackTypeDebugStr[3] = "SIEGE"
set udg_AttackTypeDebugStr[4] = "MAGIC"
set udg_AttackTypeDebugStr[5] = "CHAOS"
set udg_AttackTypeDebugStr[6] = "HERO"
set udg_DamageTypeDebugStr[0] = "UNKNOWN"
set udg_DamageTypeDebugStr[4] = "NORMAL"
set udg_DamageTypeDebugStr[5] = "ENHANCED"
set udg_DamageTypeDebugStr[8] = "FIRE"
set udg_DamageTypeDebugStr[9] = "COLD"
set udg_DamageTypeDebugStr[10] = "LIGHTNING"
set udg_DamageTypeDebugStr[11] = "POISON"
set udg_DamageTypeDebugStr[12] = "DISEASE"
set udg_DamageTypeDebugStr[13] = "DIVINE"
set udg_DamageTypeDebugStr[14] = "MAGIC"
set udg_DamageTypeDebugStr[15] = "SONIC"
set udg_DamageTypeDebugStr[16] = "ACID"
set udg_DamageTypeDebugStr[17] = "FORCE"
set udg_DamageTypeDebugStr[18] = "DEATH"
set udg_DamageTypeDebugStr[19] = "MIND"
set udg_DamageTypeDebugStr[20] = "PLANT"
set udg_DamageTypeDebugStr[21] = "DEFENSIVE"
set udg_DamageTypeDebugStr[22] = "DEMOLITION"
set udg_DamageTypeDebugStr[23] = "SLOW_POISON"
set udg_DamageTypeDebugStr[24] = "SPIRIT_LINK"
set udg_DamageTypeDebugStr[25] = "SHADOW_STRIKE"
set udg_DamageTypeDebugStr[26] = "UNIVERSAL"
set udg_WeaponTypeDebugStr[0] = "NONE" //WEAPON_TYPE_WHOKNOWS in JASS
set udg_WeaponTypeDebugStr[1] = "METAL_LIGHT_CHOP"
set udg_WeaponTypeDebugStr[2] = "METAL_MEDIUM_CHOP"
set udg_WeaponTypeDebugStr[3] = "METAL_HEAVY_CHOP"
set udg_WeaponTypeDebugStr[4] = "METAL_LIGHT_SLICE"
set udg_WeaponTypeDebugStr[5] = "METAL_MEDIUM_SLICE"
set udg_WeaponTypeDebugStr[6] = "METAL_HEAVY_SLICE"
set udg_WeaponTypeDebugStr[7] = "METAL_MEDIUM_BASH"
set udg_WeaponTypeDebugStr[8] = "METAL_HEAVY_BASH"
set udg_WeaponTypeDebugStr[9] = "METAL_MEDIUM_STAB"
set udg_WeaponTypeDebugStr[10] = "METAL_HEAVY_STAB"
set udg_WeaponTypeDebugStr[11] = "WOOD_LIGHT_SLICE"
set udg_WeaponTypeDebugStr[12] = "WOOD_MEDIUM_SLICE"
set udg_WeaponTypeDebugStr[13] = "WOOD_HEAVY_SLICE"
set udg_WeaponTypeDebugStr[14] = "WOOD_LIGHT_BASH"
set udg_WeaponTypeDebugStr[15] = "WOOD_MEDIUM_BASH"
set udg_WeaponTypeDebugStr[16] = "WOOD_HEAVY_BASH"
set udg_WeaponTypeDebugStr[17] = "WOOD_LIGHT_STAB"
set udg_WeaponTypeDebugStr[18] = "WOOD_MEDIUM_STAB"
set udg_WeaponTypeDebugStr[19] = "CLAW_LIGHT_SLICE"
set udg_WeaponTypeDebugStr[20] = "CLAW_MEDIUM_SLICE"
set udg_WeaponTypeDebugStr[21] = "CLAW_HEAVY_SLICE"
set udg_WeaponTypeDebugStr[22] = "AXE_MEDIUM_CHOP"
set udg_WeaponTypeDebugStr[23] = "ROCK_HEAVY_BASH"
set udg_DefenseTypeDebugStr[0] = "LIGHT"
set udg_DefenseTypeDebugStr[1] = "MEDIUM"
set udg_DefenseTypeDebugStr[2] = "HEAVY"
set udg_DefenseTypeDebugStr[3] = "FORTIFIED"
set udg_DefenseTypeDebugStr[4] = "NORMAL" //Typically deals flat damage to all armor types
set udg_DefenseTypeDebugStr[5] = "HERO"
set udg_DefenseTypeDebugStr[6] = "DIVINE"
set udg_DefenseTypeDebugStr[7] = "UNARMORED"
set udg_ArmorTypeDebugStr[0] = "NONE" //ARMOR_TYPE_WHOKNOWS in JASS, added in 1.31
set udg_ArmorTypeDebugStr[1] = "FLESH"
set udg_ArmorTypeDebugStr[2] = "METAL"
set udg_ArmorTypeDebugStr[3] = "WOOD"
set udg_ArmorTypeDebugStr[4] = "ETHEREAL"
set udg_ArmorTypeDebugStr[5] = "STONE"
// Added 25 July 2017 to allow detection of things like Bash or Pulverize or AOE spread
set udg_DamageEventAOE = 1
set udg_DamageEventLevel = 1
/*
In-game World Editor doesn't allow Attack Type and Damage Type comparisons.
Therefore, I need to code them as integers into GUI
*/
set udg_ATTACK_TYPE_SPELLS = 0
set udg_ATTACK_TYPE_NORMAL = 1
set udg_ATTACK_TYPE_PIERCE = 2
set udg_ATTACK_TYPE_SIEGE = 3
set udg_ATTACK_TYPE_MAGIC = 4
set udg_ATTACK_TYPE_CHAOS = 5
set udg_ATTACK_TYPE_HERO = 6
// -
set udg_DAMAGE_TYPE_UNKNOWN = 0
set udg_DAMAGE_TYPE_NORMAL = 4
set udg_DAMAGE_TYPE_ENHANCED = 5
set udg_DAMAGE_TYPE_FIRE = 8
set udg_DAMAGE_TYPE_COLD = 9
set udg_DAMAGE_TYPE_LIGHTNING = 10
set udg_DAMAGE_TYPE_POISON = 11
set udg_DAMAGE_TYPE_DISEASE = 12
set udg_DAMAGE_TYPE_DIVINE = 13
set udg_DAMAGE_TYPE_MAGIC = 14
set udg_DAMAGE_TYPE_SONIC = 15
set udg_DAMAGE_TYPE_ACID = 16
set udg_DAMAGE_TYPE_FORCE = 17
set udg_DAMAGE_TYPE_DEATH = 18
set udg_DAMAGE_TYPE_MIND = 19
set udg_DAMAGE_TYPE_PLANT = 20
set udg_DAMAGE_TYPE_DEFENSIVE = 21
set udg_DAMAGE_TYPE_DEMOLITION = 22
set udg_DAMAGE_TYPE_SLOW_POISON = 23
set udg_DAMAGE_TYPE_SPIRIT_LINK = 24
set udg_DAMAGE_TYPE_SHADOW_STRIKE = 25
set udg_DAMAGE_TYPE_UNIVERSAL = 26
/*
The below variables don't affect damage amount, but do affect the sound played
They also give important information about the type of attack used.
They can differentiate between ranged and melee for units who are both
*/
set udg_WEAPON_TYPE_NONE = 0
// Metal Light/Medium/Heavy
set udg_WEAPON_TYPE_ML_CHOP = 1
set udg_WEAPON_TYPE_MM_CHOP = 2
set udg_WEAPON_TYPE_MH_CHOP = 3
set udg_WEAPON_TYPE_ML_SLICE = 4
set udg_WEAPON_TYPE_MM_SLICE = 5
set udg_WEAPON_TYPE_MH_SLICE = 6
set udg_WEAPON_TYPE_MM_BASH = 7
set udg_WEAPON_TYPE_MH_BASH = 8
set udg_WEAPON_TYPE_MM_STAB = 9
set udg_WEAPON_TYPE_MH_STAB = 10
// Wood Light/Medium/Heavy
set udg_WEAPON_TYPE_WL_SLICE = 11
set udg_WEAPON_TYPE_WM_SLICE = 12
set udg_WEAPON_TYPE_WH_SLICE = 13
set udg_WEAPON_TYPE_WL_BASH = 14
set udg_WEAPON_TYPE_WM_BASH = 15
set udg_WEAPON_TYPE_WH_BASH = 16
set udg_WEAPON_TYPE_WL_STAB = 17
set udg_WEAPON_TYPE_WM_STAB = 18
// Claw Light/Medium/Heavy
set udg_WEAPON_TYPE_CL_SLICE = 19
set udg_WEAPON_TYPE_CM_SLICE = 20
set udg_WEAPON_TYPE_CH_SLICE = 21
// Axe Medium
set udg_WEAPON_TYPE_AM_CHOP = 22
// Rock Heavy
set udg_WEAPON_TYPE_RH_BASH = 23
/*
Since GUI still doesn't provide Defense Type and Armor Types,
I needed to include the below:
*/
set udg_ARMOR_TYPE_NONE = 0
set udg_ARMOR_TYPE_FLESH = 1
set udg_ARMOR_TYPE_METAL = 2
set udg_ARMOR_TYPE_WOOD = 3
set udg_ARMOR_TYPE_ETHEREAL = 4
set udg_ARMOR_TYPE_STONE = 5
set udg_DEFENSE_TYPE_LIGHT = 0
set udg_DEFENSE_TYPE_MEDIUM = 1
set udg_DEFENSE_TYPE_HEAVY = 2
set udg_DEFENSE_TYPE_FORTIFIED = 3
set udg_DEFENSE_TYPE_NORMAL = 4
set udg_DEFENSE_TYPE_HERO = 5
set udg_DEFENSE_TYPE_DIVINE = 6
set udg_DEFENSE_TYPE_UNARMORED = 7
/*
The remaining stuff is an ugly 'optimization' that I did a long
time ago, thinking that it would improve performance for GUI users
by not having so many different triggerconditions evaluating per
damage event. I am not sure if it even worked; in Lua it might
perform worse, but in vJass it remains to be tested.
*/
set udg_UNIT_CLASS_HERO = 0
set udg_UNIT_CLASS_DEAD = 1
set udg_UNIT_CLASS_STRUCTURE = 2
set udg_UNIT_CLASS_FLYING = 3
set udg_UNIT_CLASS_GROUND = 4
set udg_UNIT_CLASS_ATTACKS_FLYING = 5
set udg_UNIT_CLASS_ATTACKS_GROUND = 6
set udg_UNIT_CLASS_MELEE = 7
set udg_UNIT_CLASS_RANGED = 8
set udg_UNIT_CLASS_GIANT = 9
set udg_UNIT_CLASS_SUMMONED = 10
set udg_UNIT_CLASS_STUNNED = 11
set udg_UNIT_CLASS_PLAGUED = 12
set udg_UNIT_CLASS_SNARED = 13
set udg_UNIT_CLASS_UNDEAD = 14
set udg_UNIT_CLASS_MECHANICAL = 15
set udg_UNIT_CLASS_PEON = 16
set udg_UNIT_CLASS_SAPPER = 17
set udg_UNIT_CLASS_TOWNHALL = 18
set udg_UNIT_CLASS_ANCIENT = 19
set udg_UNIT_CLASS_TAUREN = 20
set udg_UNIT_CLASS_POISONED = 21
set udg_UNIT_CLASS_POLYMORPHED = 22
set udg_UNIT_CLASS_SLEEPING = 23
set udg_UNIT_CLASS_RESISTANT = 24
set udg_UNIT_CLASS_ETHEREAL = 25
set udg_UNIT_CLASS_MAGIC_IMMUNE = 26
set udg_DamageFilterAttackT = -1
set udg_DamageFilterDamageT = -1
set udg_DamageFilterSourceC = -1
set udg_DamageFilterTargetC = -1
set udg_DamageFilterRunChance = 1.00
endfunction
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 opId /*
*/ returns DamageTrigger
return DamageTrigger.registerVerbose( /*
*/ whichTrig, /*
*/ DamageTrigger.getVerboseStr(eventName), /*
*/ value, /*
*/ false, /*
*/ opId /*
*/ )
endfunction
function TriggerRegisterDamageEngine takes /*
*/ trigger whichTrig, /*
*/ string eventName, /*
*/ real value /*
*/ returns DamageTrigger
return DamageTrigger.registerTrigger(whichTrig, eventName, value)
endfunction
function RegisterDamageEngineEx takes /*
*/ code callback, /*
*/ string eventName, /*
*/ real value, /*
*/ integer opId /*
*/ returns DamageTrigger
return TriggerRegisterDamageEngineEx(DamageTrigger[callback], eventName, value, opId)
endfunction
//Similar to TriggerRegisterDamageEvent, but takes code instead of trigger as the first argument.
function RegisterDamageEngine takes /*
*/ code callback, /*
*/ string eventName, /*
*/ real value /*
*/ returns DamageTrigger
return RegisterDamageEngineEx(callback, eventName, value, FILTER_OTHER)
endfunction
/*
The below macros are for GUI to tap into more powerful vJass event filtering:
*/
//! textmacro DAMAGE_TRIGGER_CONFIG
if not DamageTrigger.eventIndex.configured then
//! endtextmacro
//! textmacro DAMAGE_TRIGGER_CONFIG_END
call DamageTrigger.eventIndex.configure()
endif
if not DamageTrigger.eventIndex.checkConfig() then
return
endif
//! endtextmacro
endlibrary
// Arcing Text Tag v1.0.2.0 by Maker with added API by Bribe and features proposed by Ugabunda and Kusanagi Kuro
//
// Added API in 1.0.1.0:
// public static ArcingTextTag lastCreated
// - Get the last created ArcingTextTag
// public real scaling
// - Set the size ratio of the texttag - 1.00 is the default
// public real timeScaling
// - Set the duration ratio of the texttag - 1.00 is the default
library FloatingTextArc
globals
private constant real SIZE_MIN = 0.018 // Minimum size of text
private constant real SIZE_BONUS = 0.012 // Text size increase
private constant real TIME_LIFE = 1.0 // How long the text lasts
private constant real TIME_FADE = 0.8 // When does the text start to fade
private constant real Z_OFFSET = 50 // Height above unit
private constant real Z_OFFSET_BON = 50 // How much extra height the text gains
private constant real VELOCITY = 2 // How fast the text move in x/y plane
private constant real ANGLE = bj_PI/2 // Movement angle of the text. Does not apply if
// ANGLE_RND is true
private constant boolean ANGLE_RND = true // Is the angle random or fixed
private timer TMR = CreateTimer()
endglobals
struct ArcingTextTag extends array
private texttag tt
private real as // angle, sin component
private real ac // angle, cos component
private real t // time
private real x // origin x
private real y // origin y
private string s // text
private force f // force
private static integer array next
private static integer array prev
private static integer array rn
private static integer ic = 0 // Instance count
private real scale
private real timeScale
public static thistype lastCreated = 0
private static method update takes nothing returns nothing
local thistype this=next[0]
local real p
loop
set p = Sin(bj_PI*(.t / timeScale))
set .t = .t - 0.03125
set .x = .x + .ac
set .y = .y + .as
call SetTextTagPos(.tt, .x, .y, Z_OFFSET + Z_OFFSET_BON*p)
call SetTextTagText(.tt, .s, (SIZE_MIN + SIZE_BONUS*p)*.scale)
if .t <= 0 then
set .tt = null
set next[prev[this]] = next[this]
set prev[next[this]] = prev[this]
set rn[this] = rn[0]
set rn[0] = this
if next[0]==0 then
call PauseTimer(TMR)
endif
endif
set this = next[this]
exitwhen this == 0
endloop
endmethod
public static method createEx takes string s, unit u, real duration, real size, player p returns thistype
local thistype this = rn[0]
static if ANGLE_RND then
local real a = GetRandomReal(0, 2*bj_PI)
else
local real a = ANGLE
endif
if this == 0 then
set ic = ic + 1
set this = ic
else
set rn[0] = rn[this]
endif
set .scale = size
set .timeScale = RMaxBJ(duration, 0.001)
set next[this] = 0
set prev[this] = prev[0]
set next[prev[0]] = this
set prev[0] = this
set .s = s
set .x = GetUnitX(u)
set .y = GetUnitY(u)
set .t = TIME_LIFE
set .as = Sin(a)*VELOCITY
set .ac = Cos(a)*VELOCITY
if IsUnitVisible(u, p) then
set .tt = CreateTextTag()
call SetTextTagPermanent(.tt, false)
call SetTextTagLifespan(.tt, TIME_LIFE*duration)
call SetTextTagFadepoint(.tt, TIME_FADE*duration)
call SetTextTagText(.tt, s, SIZE_MIN*size)
call SetTextTagPos(.tt, .x, .y, Z_OFFSET)
call ShowTextTagForceBJ( false, .tt, GetPlayersAll() )
set .f = GetForceOfPlayer(p)
call ShowTextTagForceBJ( true, .tt, .f )
call DestroyForce(.f)
else
set .tt = null
endif
if prev[this] == 0 then
call TimerStart(TMR, 0.03125, true, function thistype.update)
endif
set .lastCreated = this
return this
endmethod
public static method create takes string s, unit u returns thistype
return thistype.createEx(s, u, TIME_LIFE, 1.00, GetLocalPlayer())
endmethod
endstruct
endlibrary
function Trig_Dmg_Text_Actions takes nothing returns nothing
local player s
local player t
local real amount
local string color
if (udg_DamageEventAmount == 0) then
return
endif
set amount = udg_DamageEventAmount
set udg_DmgDuration = 1.00
set udg_DmgSize = 1.00
set color = "|cffffffff"
if ( udg_DAMAGE_TYPE_POISON == udg_DamageEventDamageT or udg_DAMAGE_TYPE_SLOW_POISON == udg_DamageEventDamageT) then
set color = "|cff40fd14"
endif
set s = GetOwningPlayer(udg_DamageEventSource)
set t = GetOwningPlayer(udg_DamageEventTarget)
if (GetPlayerId(s) < 10) then
call ROUND_STATS.instance.setDmg(amount, GetPlayerId(s))
endif
set udg_DmgStr = ( color + ( I2S(MathRound(amount)) + "|r" ) )
call ArcingTextTag.createEx(udg_DmgStr, udg_DamageEventTarget, udg_DmgDuration, udg_DmgSize, s)
if (s != t) then
set udg_DmgDuration = 1.00
set udg_DmgSize = 0.75
set udg_DmgStr = ( color + ( I2S(MathRound(amount)) + "|r" ) )
call ArcingTextTag.createEx(udg_DmgStr, udg_DamageEventTarget, udg_DmgDuration, udg_DmgSize, t)
endif
set s = null
set t = null
endfunction
//===========================================================================
function InitTrig_Dmg_Text takes nothing returns nothing
set gg_trg_Dmg_Text = CreateTrigger( )
call TriggerRegisterVariableEvent( gg_trg_Dmg_Text, "udg_OnDamageEvent", EQUAL, 1.00 )
call TriggerAddAction( gg_trg_Dmg_Text, function Trig_Dmg_Text_Actions )
endfunction
function Trig_Heal_Text_Actions takes nothing returns nothing
local player s
local player t
local real amount
set amount = udg_HealEventAmount
set udg_DmgStr = "|cff22ff33"
set udg_DmgDuration = 1.00
set udg_DmgSize = 1.00
set s = GetOwningPlayer(udg_HealEventSource)
set t = GetOwningPlayer(udg_HealEventTarget)
set udg_DmgStr = ( "|cff22ff33" + ( I2S(MathRound(amount)) + "|r" ) )
call ArcingTextTag.createEx(udg_DmgStr, udg_HealEventTarget, udg_DmgDuration, udg_DmgSize, s)
if (s != t) then
set udg_DmgDuration = 1.00
set udg_DmgSize = 0.75
set udg_DmgStr = ( "|cff22ff33" + ( I2S(MathRound(amount)) + "|r" ) )
call ArcingTextTag.createEx(udg_DmgStr, udg_HealEventTarget, udg_DmgDuration, udg_DmgSize, t)
endif
set s = null
set t = null
endfunction
//===========================================================================
function InitTrig_Heal_Text takes nothing returns nothing
set gg_trg_Heal_Text = CreateTrigger( )
call TriggerRegisterVariableEvent( gg_trg_Heal_Text, "udg_OnHealEvent", EQUAL, 1.00 )
call TriggerAddAction( gg_trg_Heal_Text, function Trig_Heal_Text_Actions )
endfunction
function Trig_Mana_Text_Actions takes nothing returns nothing
local player s
local player t
local real amount
set amount = udg_ManaEventAmount
set udg_DmgStr = "|cff2244ce"
set udg_DmgDuration = 1.00
set udg_DmgSize = 1.00
set s = GetOwningPlayer(udg_ManaEventSource)
set t = GetOwningPlayer(udg_ManaEventTarget)
set udg_DmgStr = ( "|cff2244ce" + ( I2S(MathRound(amount)) + "|r" ) )
call ArcingTextTag.createEx(udg_DmgStr, udg_ManaEventTarget, udg_DmgDuration, udg_DmgSize, s)
if (s != t) then
set udg_DmgDuration = 1.00
set udg_DmgSize = 0.75
set udg_DmgStr = ( "|ccff2244ce" + ( I2S(MathRound(amount)) + "|r" ) )
call ArcingTextTag.createEx(udg_DmgStr, udg_ManaEventTarget, udg_DmgDuration, udg_DmgSize, t)
endif
set s = null
set t = null
endfunction
//===========================================================================
function InitTrig_Mana_Text takes nothing returns nothing
set gg_trg_Mana_Text = CreateTrigger( )
call TriggerRegisterVariableEvent( gg_trg_Mana_Text, "udg_OnManaEvent", EQUAL, 1.00 )
call TriggerAddAction( gg_trg_Mana_Text, function Trig_Mana_Text_Actions )
endfunction
struct WaveVariant
string name
string description
string icon
trigger array bossTriggers[10]
trigger array preTriggers[10]
integer bossTriggerSize = 0
integer preTriggerSize = 0
integer bossType //unittype
integer bossTypeHard = 0
integer compositionSize
integer array creepsNumber[10]
integer spawnSize
integer array creepType[10] //unittype
integer waveRewardGold
integer waveRewardExp
Arena arena
integer int = 0
integer str = 0
integer agi = 0
static method create takes nothing returns thistype
local thistype this = thistype.allocate()
return this
endmethod
endstruct
struct Wave
WaveVariant array variants[4]
integer size = 0
static method create takes nothing returns thistype
local thistype this = thistype.allocate()
return this
endmethod
method push takes WaveVariant v returns nothing
set variants[size] = v
set size = size + 1
endmethod
endstruct
function WAVE1V1_CRABS_CREATE takes nothing returns WaveVariant
local WaveVariant w = WaveVariant.create()
set w.name = "Crabs"
set w.description = "Crabs, imported from the beaches of kalimdor crabs make for a perfect first wave"
set w.icon = "ReplaceableTextures\\CommandButtons\\BTNSpinyCrab.blp"
set w.bossTriggers[0] = gg_trg_W1V1_AI
set w.bossTriggers[1] = gg_trg_W1V1_AI_SummonH
set w.bossTriggerSize = 2
set w.bossType = 'H007'
set w.compositionSize = 3
set w.creepsNumber[0] = 2
set w.creepsNumber[1] = 1
set w.creepsNumber[2] = 1
set w.spawnSize = 3
set w.creepType[0] = 'w111'
set w.creepType[1] = 'w112'
set w.creepType[2] = 'w113'
set w.waveRewardGold = 200
set w.waveRewardExp = 600
set w.arena = Arena.MainArena
return w
endfunction
function WAVE1V2_MURLOCKS_CREATE takes nothing returns WaveVariant
local WaveVariant w = WaveVariant.create()
set w.name = "Murlocks"
set w.description = "Murlocks, spiky and derpy amphibians, readily availabiles. They are a cheap way to test new gladiators."
set w.icon = "ReplaceableTextures\\CommandButtons\\BTNMurloc.blp"
set w.bossTriggers[0] = gg_trg_W1V2_AI
set w.bossTriggerSize = 1
set w.bossType = 'H00P'
set w.compositionSize = 1
set w.creepsNumber[0] = 5
set w.spawnSize = 2
set w.creepType[0] = 'w121'
set w.waveRewardGold = 150
set w.waveRewardExp = 625
set w.arena = Arena.CageArena
return w
endfunction
function WAVE1V3_RAZORMANES_CREATE takes nothing returns WaveVariant
local WaveVariant w = WaveVariant.create()
set w.name = "Pig creatures"
set w.description = "...at least they are prettier than the humans"
set w.icon = "ReplaceableTextures\\CommandButtons\\BTNRazorback.blp"
set w.bossTriggers[0] = gg_trg_W1V3_AI
set w.bossTriggers[1] = gg_trg_W1V3Razor_AIH
set w.bossTriggers[2] = gg_trg_W1V3_AI_EarthquakeH
set w.bossTriggerSize = 3
set w.bossType = 'H017'
set w.compositionSize = 2
set w.creepsNumber[0] = 1
set w.creepsNumber[1] = 2
set w.spawnSize = 2
set w.creepType[0] = 'w131'
set w.creepType[1] = 'w132'
set w.waveRewardGold = 250
set w.waveRewardExp = 600
set w.arena = Arena.MainArena
return w
endfunction
function WAVE2V1_GNOLLS_CREATE takes nothing returns WaveVariant
local WaveVariant w = WaveVariant.create()
set w.name = "Gnolls"
set w.description = "Some cool creatures found on the forests of lorderon, they make high pitched noises and wield weapons, nothing more to know"
set w.icon = "ReplaceableTextures\\CommandButtons\\BTNGnollWarden.blp"
set w.bossTriggers[0] = gg_trg_W2V1_AI_Fury
set w.bossTriggers[1] = gg_trg_W2V1_AI_Carrion
set w.bossTriggers[2] = gg_trg_W2V1_Scaling
set w.preTriggers[0] = gg_trg_W2V1_GnollAssasinH
set w.bossTriggerSize = 3
set w.preTriggerSize = 1
set w.bossType = 'H009'
set w.compositionSize = 3
set w.creepsNumber[0] = 1
set w.creepsNumber[1] = 2
set w.creepsNumber[2] = 2
set w.spawnSize = 3
set w.creepType[0] = 'w211'
set w.creepType[1] = 'w212'
set w.creepType[2] = 'w213'
set w.waveRewardGold = 250
set w.waveRewardExp = 600
set w.arena = Arena.MainArena
return w
endfunction
function WAVE2V2_SETTLERS_CREATE takes nothing returns WaveVariant
local WaveVariant w = WaveVariant.create()
set w.name = "Settlers"
set w.description = "While peaceful settler may be scarse around northrent there are plenty available in Lordaeron, cherry on top they're easy to carry and transport"
set w.icon = "ReplaceableTextures\\CommandButtons\\BTNMilitia.blp"
set w.bossTriggers[0] = gg_trg_W2V2_AI_Leap
set w.bossTriggers[1] = gg_trg_W2V2_AI_StrainBody
set w.bossTriggers[2] = gg_trg_W2V2_ScalingH
set w.bossTriggers[3] = gg_trg_W2V2_Militia_AIH
set w.bossTriggers[4] = gg_trg_W2V2_MilitiaChargeDmg
set w.bossTriggerSize = 5
set w.bossType = 'H00U'
set w.compositionSize = 3
set w.creepsNumber[0] = 2
set w.creepsNumber[1] = 1
set w.creepsNumber[2] = 2
set w.spawnSize = 2
set w.creepType[0] = 'w221'
set w.creepType[1] = 'w222'
set w.creepType[2] = 'w223'
set w.waveRewardGold = 200
set w.waveRewardExp = 650
set w.arena = Arena.CageArena
return w
endfunction
function WAVE2V3_SLAVES_CREATE takes nothing returns WaveVariant
local WaveVariant w = WaveVariant.create()
set w.name = "Slaves"
set w.description = "Once slaves amond their kind now they serve as slaves in the arena"
set w.icon = "ReplaceableTextures\\CommandButtons\\BTNPeon.blp"
set w.bossTriggers[0] = gg_trg_W2V3_AI_UTW
set w.bossTriggers[1] = gg_trg_W2V3_AI_LivingSpikes
set w.bossTriggers[2] = gg_trg_W2V3_AI_PeonChampion
set w.preTriggers[0] = gg_trg_W2V3_PeonChampionH
set w.bossTriggerSize = 3
set w.preTriggerSize = 1
set w.bossType = 'H019'
set w.compositionSize = 3
set w.creepsNumber[0] = 2
set w.creepsNumber[1] = 2
set w.creepsNumber[2] = 3
set w.spawnSize = 2
set w.creepType[0] = 'w231'
set w.creepType[1] = 'w232'
set w.creepType[2] = 'w233'
set w.waveRewardGold = 225
set w.waveRewardExp = 600
set w.arena = Arena.MainArena
return w
endfunction
function WAVE3V1_BANDITS_CREATE takes nothing returns WaveVariant
local WaveVariant w = WaveVariant.create()
set w.name = "Bandits"
set w.description = "Thieves, tried to stole the prize now have to compete in the arena as fodder"
set w.icon = "ReplaceableTextures\\CommandButtons\\BTNBandit.blp"
set w.bossTriggers[0] = gg_trg_W3V1_AI_BagOfGold
set w.bossTriggers[1] = gg_trg_W3V1_AI_Ambush
set w.preTriggers[0] = gg_trg_W3V1_CreepsPoisonH
set w.bossTriggerSize = 2
set w.preTriggerSize = 1
set w.bossType = 'H00A'
set w.compositionSize = 2
set w.creepsNumber[0] = 2
set w.creepsNumber[1] = 3
set w.spawnSize = 3
set w.creepType[0] = 'w311'
set w.creepType[1] = 'w312'
set w.waveRewardGold = 300
set w.waveRewardExp = 600
set w.arena = Arena.MainArena
return w
endfunction
function WAVE3V2_DINITIATES_CREATE takes nothing returns WaveVariant
local WaveVariant w = WaveVariant.create()
set w.name = "Dalaran Initiates"
set w.description = "Young mages snatched from the humans. Well it's time for them to put work what they have learned so far"
set w.icon = "ReplaceableTextures\\CommandButtons\\BTNSummonWaterElemental.blp"
set w.bossTriggers[0] = gg_trg_W3V2_Scaling
set w.bossTriggers[1] = gg_trg_W3V2_AI_MirrorImage1
set w.bossTriggers[2] = gg_trg_W3V2_AI_MirrorImage2
set w.bossTriggers[3] = gg_trg_W3V2_AI_MirrorImage3
set w.bossTriggers[4] = gg_trg_W3V2_AI_MirrorImage4
set w.bossTriggers[5] = gg_trg_W3V2_AI_MirrorImage5
set w.bossTriggers[6] = gg_trg_W3V2_AI_Initiate
set w.bossTriggers[7] = gg_trg_W3V2_CreepsShieldH
set w.bossTriggerSize = 8
set w.bossType = 'H002'
set w.bossTypeHard = 'H01B'
set w.compositionSize = 2
set w.creepsNumber[0] = 3
set w.creepsNumber[1] = 3
set w.spawnSize = 2
set w.creepType[0] = 'w321'
set w.creepType[1] = 'w322'
set w.waveRewardGold = 300
set w.waveRewardExp = 600
set w.arena = Arena.CageArena
return w
endfunction
function WAVE3V3_WARPARTY_CREATE takes nothing returns WaveVariant
local WaveVariant w = WaveVariant.create()
set w.name = "War Party"
set w.description = "In the arena, out of the arena. Doesn't matter these orcs don't care, get ready for war!"
set w.icon = "ReplaceableTextures\\CommandButtons\\BTNGrunt.blp"
set w.bossTriggers[0] = gg_trg_W3V3_AI
set w.bossTriggerSize = 1
set w.bossType = 'H01A'
set w.bossTypeHard = 'H01C'
set w.compositionSize = 3
set w.creepsNumber[0] = 1
set w.creepsNumber[1] = 1
set w.creepsNumber[2] = 3
set w.spawnSize = 3
set w.creepType[0] = 'w331'
set w.creepType[1] = 'w332'
set w.creepType[2] = 'w333'
set w.waveRewardGold = 300
set w.waveRewardExp = 600
set w.arena = Arena.MainArena
return w
endfunction
function WAVE4V1_LIZARDS_CREATE takes nothing returns WaveVariant
local WaveVariant w = WaveVariant.create()
set w.name = "Lizards"
set w.description = "Cool exotic overgrown lizards, the arena won't compromise when it comes to providing challenges"
set w.icon = "ReplaceableTextures\\CommandButtons\\BTNThunderLizard.blp"
set w.bossTriggers[0] = gg_trg_W4V1_AI
set w.bossTriggers[1] = gg_trg_W4V1_AI_LizardH
set w.bossTriggerSize = 2
set w.preTriggers[0] = gg_trg_W4V1_CreepsForkedH
set w.preTriggerSize = 1
set w.bossType = 'H00B'
set w.compositionSize = 2
set w.creepsNumber[0] = 3
set w.creepsNumber[1] = 3
set w.spawnSize = 3
set w.creepType[0] = 'w411'
set w.creepType[1] = 'w412'
set w.waveRewardGold = 350
set w.waveRewardExp = 600
set w.arena = Arena.MainArena
return w
endfunction
function WAVE4V2_RECONPARTY_CREATE takes nothing returns WaveVariant
local WaveVariant w = WaveVariant.create()
set w.name = "Recon Party"
set w.description = "A run of the mill human recon party, repurposed to serve in the arena, otherwise unreamarkeble"
set w.icon = "ReplaceableTextures\\CommandButtons\\BTNFootman.blp"
set w.bossTriggers[0] = gg_trg_W4V2_AI
set w.bossTriggerSize = 1
set w.preTriggers[0] = gg_trg_W4V2_ArcherH
set w.preTriggerSize = 1
set w.bossType = 'H00T'
set w.compositionSize = 3
set w.creepsNumber[0] = 1
set w.creepsNumber[1] = 1
set w.creepsNumber[2] = 5
set w.spawnSize = 1
set w.creepType[0] = 'w421'
set w.creepType[1] = 'w422'
set w.creepType[2] = 'w423'
set w.waveRewardGold = 400
set w.waveRewardExp = 650
set w.arena = Arena.CageArena
return w
endfunction
function WAVE4V3_ORCWARLOCKS_CREATE takes nothing returns WaveVariant
local WaveVariant w = WaveVariant.create()
set w.name = "Warlock Conclave"
set w.description = "Greenskins, attuned to the magic. An exemplary wave 4"
set w.icon = "ReplaceableTextures\\CommandButtons\\BTNChaosWarlockGreen.blp"
set w.bossTriggers[0] = gg_trg_W4V3_AI_Fireball
set w.bossTriggers[1] = gg_trg_W4V3_AI_Frenzy
set w.bossTriggers[2] = gg_trg_W4V3_AI_Warlock
set w.bossTriggers[3] = gg_trg_W4V3_AI_WarlockArcher
set w.bossTriggerSize = 4
set w.bossType = 'H01D'
set w.compositionSize = 3
set w.creepsNumber[0] = 4
set w.creepsNumber[1] = 2
set w.creepsNumber[2] = 2
set w.spawnSize = 3
set w.creepType[0] = 'w431'
set w.creepType[1] = 'w432'
set w.creepType[2] = 'w433'
set w.waveRewardGold = 400
set w.waveRewardExp = 650
set w.arena = Arena.MainArena
return w
endfunction
function WAVE5V1_TROLLS_CREATE takes nothing returns WaveVariant
local WaveVariant w = WaveVariant.create()
set w.name = "Trolls"
set w.description = "Ranged warriors, sometimes they casually backflip in place, impressive"
set w.icon = "ReplaceableTextures\\CommandButtons\\BTNIceTrollBeserker.blp"
set w.bossTriggers[0] = gg_trg_W5V1_AI_Frenzy
set w.bossTriggers[1] = gg_trg_W5V1_AI_Tornado
set w.bossTriggerSize = 2
set w.preTriggers[0] = gg_trg_W5TrollsH
set w.preTriggerSize = 1
set w.bossType = 'H00G'
set w.compositionSize = 5
set w.creepsNumber[0] = 3
set w.creepsNumber[1] = 2
set w.creepsNumber[2] = 1
set w.creepsNumber[3] = 2
set w.creepsNumber[4] = 2
set w.spawnSize = 2
set w.creepType[0] = 'w511'
set w.creepType[1] = 'w512'
set w.creepType[2] = 'w513'
set w.creepType[3] = 'w514'
set w.creepType[4] = 'w515'
set w.waveRewardGold = 400
set w.waveRewardExp = 600
set w.arena = Arena.MainArena
return w
endfunction
function WAVE5V2_TODL_CREATE takes nothing returns WaveVariant
local WaveVariant w = WaveVariant.create()
set w.name = "Troops of the Line"
set w.description = "Highly motivated and cohesive, these warriors will fight to as a team in order to escape the arena"
set w.icon = "war3mapImported\\BTNFemaleCaptain.blp"
set w.bossTriggers[0] = gg_trg_W5V2_AI_Rally
set w.bossTriggers[1] = gg_trg_W5V2_AI_Multislash
set w.bossTriggers[2] = gg_trg_W5CaptainRallyProtectLoop
set w.bossTriggerSize = 3
set w.preTriggers[0] = gg_trg_W5FootiesH
set w.preTriggerSize = 1
set w.bossType = 'H00W'
set w.compositionSize = 4
set w.creepsNumber[0] = 3
set w.creepsNumber[1] = 2
set w.creepsNumber[2] = 2
set w.creepsNumber[3] = 1
set w.spawnSize = 2
set w.creepType[0] = 'w421'
set w.creepType[1] = 'w422'
set w.creepType[2] = 'w523'
set w.creepType[3] = 'w524'
set w.waveRewardGold = 450
set w.waveRewardExp = 650
set w.arena = Arena.MainArena
return w
endfunction
function WAVE5V3_CENTAURS_CREATE takes nothing returns WaveVariant
local WaveVariant w = WaveVariant.create()
set w.name = "Centaurs"
set w.description = "Horse people armed with bow and arrows"
set w.icon = "ReplaceableTextures\\CommandButtons\\BTNCentaurKhan.blp"
set w.bossTriggers[0] = gg_trg_W5V3_AI_Rumble
set w.bossTriggers[1] = gg_trg_W5V3_AI_Frenzy
set w.bossTriggerSize = 2
set w.preTriggers[0] = gg_trg_W5V3_CentaurH
set w.preTriggers[1] = gg_trg_W5V3_AI_Run_Away
set w.preTriggers[2] = gg_trg_W5KhanH
set w.preTriggerSize = 3
set w.bossType = 'H01F'
set w.compositionSize = 2
set w.creepsNumber[0] = 4
set w.creepsNumber[1] = 4
set w.spawnSize = 2
set w.creepType[0] = 'w531'
set w.creepType[1] = 'w532'
set w.waveRewardGold = 450
set w.waveRewardExp = 650
set w.arena = Arena.MainArena
return w
endfunction
function WAVE6V1_TURTLES_CREATE takes nothing returns WaveVariant
local WaveVariant w = WaveVariant.create()
set w.name = "Turtles"
set w.description = "Do you know how long it takes a for turle to grow to this size? Well here are some to slaughter"
set w.icon = "ReplaceableTextures\\CommandButtons\\BTNSeaTurtleGreen.blp"
set w.bossTriggers[0] = gg_trg_W6V1_AI
set w.bossTriggerSize = 1
set w.bossType = 'H00K'
set w.compositionSize = 2
set w.creepsNumber[0] = 4
set w.creepsNumber[1] = 4
set w.spawnSize = 3
set w.creepType[0] = 'w611'
set w.creepType[1] = 'w612'
set w.waveRewardGold = 450
set w.waveRewardExp = 600
set w.arena = Arena.MainArena
return w
endfunction
function WAVE6V2_SPECIAL_FORCES_CREATE takes nothing returns WaveVariant
local WaveVariant w = WaveVariant.create()
set w.name = "Special Forces"
set w.description = "A good catch the royal spy master and his entourage. They are yours to fight."
set w.icon = "ReplaceableTextures\\CommandButtons\\BTNBanditMage.blp"
set w.bossTriggers[0] = gg_trg_W6V2_AI
set w.bossTriggers[0] = gg_trg_W6SpyMasterCreatePet
set w.bossTriggerSize = 2
set w.bossType = 'H00Z'
set w.compositionSize = 2
set w.creepsNumber[0] = 4
set w.creepsNumber[1] = 4
set w.spawnSize = 3
set w.creepType[0] = 'w621'
set w.creepType[1] = 'w622'
set w.waveRewardGold = 450
set w.waveRewardExp = 600
set w.arena = Arena.MainArena
return w
endfunction
function WAVE6V3_CHAOS_ORCS_CREATE takes nothing returns WaveVariant
local WaveVariant w = WaveVariant.create()
set w.name = "Chaos Orcs"
set w.description = "Drank from a tainted well, now they are all red. The takeaway is watch where you drink from"
set w.icon = "ReplaceableTextures\\CommandButtons\\BTNChaosBlademaster.blp"
set w.bossTriggers[0] = gg_trg_W6V3_AI
set w.bossTriggers[1] = gg_trg_W6V3_CritsSplash
set w.bossTriggers[2] = gg_trg_W6V3_AI_Crits
set w.bossTriggers[3] = gg_trg_W6V3_AI_Warlock
set w.bossTriggerSize = 4
set w.bossType = 'H01L'
set w.compositionSize = 3
set w.creepsNumber[0] = 4
set w.creepsNumber[1] = 2
set w.creepsNumber[2] = 2
set w.spawnSize = 1
set w.creepType[0] = 'w631'
set w.creepType[1] = 'w632'
set w.creepType[2] = 'w632'
set w.waveRewardGold = 450
set w.waveRewardExp = 600
set w.arena = Arena.CageArena
return w
endfunction
function WAVE7V1_FURBOLGS_CREATE takes nothing returns WaveVariant
local WaveVariant w = WaveVariant.create()
set w.name = "Furbolgs"
set w.description = "Bear people, an excellent wave 7"
set w.icon = "ReplaceableTextures\\CommandButtons\\BTNPolarFurbolg.blp"
set w.bossTriggers[0] = gg_trg_W7V1_AI
set w.bossTriggerSize = 1
set w.bossType = 'H00L'
set w.compositionSize = 4
set w.creepsNumber[0] = 7
set w.creepsNumber[1] = 2
set w.creepsNumber[2] = 2
set w.creepsNumber[3] = 1
set w.spawnSize = 3
set w.creepType[0] = 'w711'
set w.creepType[1] = 'w712'
set w.creepType[2] = 'w713'
set w.creepType[3] = 'w714'
set w.waveRewardGold = 550
set w.waveRewardExp = 600
set w.arena = Arena.MainArena
return w
endfunction
function WAVE7V2_KNIGHTS_CREATE takes nothing returns WaveVariant
local WaveVariant w = WaveVariant.create()
set w.name = "Knights"
set w.description = "Veterans, well equipped and trained each man is an army. Enjoy"
set w.icon = "ReplaceableTextures\\CommandButtons\\BTNKnight.blp"
set w.bossTriggers[0] = gg_trg_W7V2_AI
set w.bossTriggerSize = 1
set w.bossType = 'H012'
set w.compositionSize = 2
set w.creepsNumber[0] = 3
set w.creepsNumber[1] = 2
set w.spawnSize = 1
set w.creepType[0] = 'w721'
set w.creepType[1] = 'w722'
set w.waveRewardGold = 550
set w.waveRewardExp = 650
set w.arena = Arena.CageArena
return w
endfunction
function WAVE8V1_WENDIGOS_CREATE takes nothing returns WaveVariant
local WaveVariant w = WaveVariant.create()
set w.name = "Wendigos"
set w.description = "Snow people, captured in backyard of the arena and uleashed against the gladiators"
set w.icon = "ReplaceableTextures\\CommandButtons\\BTNWendigo.blp"
set w.bossTriggers[0] = gg_trg_W8V1_AI
set w.bossTriggerSize = 1
set w.bossType = 'H00M'
set w.compositionSize = 3
set w.creepsNumber[0] = 4
set w.creepsNumber[1] = 5
set w.creepsNumber[2] = 1
set w.spawnSize = 3
set w.creepType[0] = 'w811'
set w.creepType[1] = 'w812'
set w.creepType[2] = 'w813'
set w.waveRewardGold = 600
set w.waveRewardExp = 600
set w.arena = Arena.MainArena
return w
endfunction
function WAVE8V2_SUMMONER_PRODIGY_CREATE takes nothing returns WaveVariant
local WaveVariant w = WaveVariant.create()
set w.name = "Summoner Prodigy"
set w.description = "Often star guest in a competing arena she is now trying to branch out.|nMight or might not be inspired by |cff7b1fa2Legendary Trials|r from a certain |cff7b1fa2Eaglendia|r"
set w.icon = "ReplaceableTextures\\CommandButtons\\BTNJaina.blp"
set w.bossTriggers[0] = gg_trg_W8V2_AI_Wall
set w.bossTriggers[1] = gg_trg_W8V2RG_AI
set w.bossTriggers[2] = gg_trg_W8V2RG_AI_2
set w.bossTriggers[3] = gg_trg_W8V2GWE_AI
set w.bossTriggerSize = 4
set w.bossType = 'H015'
set w.compositionSize = 2
set w.creepsNumber[0] = 1
set w.creepsNumber[1] = 1
set w.spawnSize = 1
set w.creepType[0] = 'w821'
set w.creepType[1] = 'w822'
set w.waveRewardGold = 650
set w.waveRewardExp = 650
set w.int = 110
set w.arena = Arena.CageArena
return w
endfunction
function WAVE9V1_BLUE_DRASGONS_CREATE takes nothing returns WaveVariant
local WaveVariant w = WaveVariant.create()
set w.name = "Blue Dragons"
set w.description = "Reptiles from another era, they spit fire, which is cold? Don't even get me started with this one"
set w.icon = "ReplaceableTextures\\CommandButtons\\BTNAzureDragon.blp"
//set w.bossTriggers[0] = gg_trg_W9V2_AI
set w.bossTriggerSize = 0
//set w.bossType = 0
set w.compositionSize = 1
set w.creepsNumber[0] = 3
set w.spawnSize = 1
set w.creepType[0] = 'w911'
set w.waveRewardGold = 600
set w.waveRewardExp = 600
set w.arena = Arena.MainArena
return w
endfunction
function WAVE9V2_ARCHMAGE_CREATE takes nothing returns WaveVariant
local WaveVariant w = WaveVariant.create()
set w.name = "Archmage"
set w.description = "An Influential Archmage, we don't have many of those, dont waste it"
set w.icon = "ReplaceableTextures\\CommandButtons\\BTNHeroArchMage.blp"
set w.bossTriggers[0] = gg_trg_W9V2_AI
set w.bossTriggerSize = 1
set w.bossType = 'H00X'
set w.compositionSize = 2
set w.creepsNumber[0] = 4
set w.creepsNumber[1] = 4
set w.spawnSize = 2
set w.creepType[0] = 'w921'
set w.creepType[1] = 'w922'
set w.waveRewardGold = 700
set w.waveRewardExp = 700
set w.str = 125
set w.agi = 85
set w.int = 85
set w.arena = Arena.CageArena
return w
endfunction
function WAVE10V1_SENIOR_PALADIN_CREATE takes nothing returns WaveVariant
local WaveVariant w = WaveVariant.create()
set w.name = "Senior Paladin"
set w.description = "A champion of the holy, multiple times savior of the humanity, with a life full of accomplisment he has now decided to Partecipate in clandestine Undead Gladiator games"
set w.icon = "ReplaceableTextures\\CommandButtons\\BTNHeroPaladin.blp"
set w.bossTriggers[0] = gg_trg_W10V1_AI_Mass_Holy
set w.bossTriggers[1] = gg_trg_W10V1_AI_Summon
set w.bossTriggers[2] = gg_trg_W10V1_AI_Shield1
set w.bossTriggers[3] = gg_trg_W10V1_AI_Shield2
set w.bossTriggers[4] = gg_trg_W10V1_AI_Bloodlust1
set w.bossTriggers[5] = gg_trg_W10V1_AI_Sweep2
set w.bossTriggerSize = 6
set w.bossType = 'H00N'
set w.compositionSize = 0
set w.spawnSize = 1
set w.waveRewardGold = 600
set w.waveRewardExp = 0
set w.arena = Arena.CageArena
return w
endfunction
struct PlayableArea
private rect array regions[128]
private integer regionCount = 0
static method create takes nothing returns thistype
local thistype this = thistype.allocate()
return this
endmethod
public method push takes rect r returns nothing
set regions[regionCount] = r
set regionCount = regionCount + 1
endmethod
public method containsLocation takes location l returns boolean
local integer i = 0
loop
exitwhen i == regionCount
if (RectContainsLoc(regions[i], l)) then
return true
endif
set i = i + 1
endloop
return false
endmethod
endstruct
function switchCurrentPlayableArea takes integer newArea returns nothing
local PlayableArea current = udg_CURRENT_PLAYABLE_AREA
set udg_CURRENT_PLAYABLE_AREA = newArea
if (current != null) then
call current.destroy()
endif
endfunction
function PICK_AREA_CREATE takes nothing returns PlayableArea
local PlayableArea p = PlayableArea.create()
call p.push(gg_rct_PAREA_PICK1)
return p
endfunction
function HUB_AREA_CREATE takes nothing returns PlayableArea
local PlayableArea p = PlayableArea.create()
call p.push(gg_rct_PAREA_HUB1)
return p
endfunction
function ARENA_AREA_CREATE takes nothing returns PlayableArea
local PlayableArea p = PlayableArea.create()
call p.push(gg_rct_PAREA_ARENA1)
call p.push(gg_rct_PAREA_ARENA2)
call p.push(gg_rct_PAREA_ARENA3)
call p.push(gg_rct_PAREA_ARENA4)
call p.push(gg_rct_PAREA_ARENA5)
call p.push(gg_rct_PAREA_ARENA6)
call p.push(gg_rct_PAREA_ARENA7)
call p.push(gg_rct_PAREA_ARENA8)
call p.push(gg_rct_PAREA_ARENA9)
call p.push(gg_rct_PAREA_ARENA10)
call p.push(gg_rct_PAREA_ARENA11)
call p.push(gg_rct_PAREA_ARENA12)
call p.push(gg_rct_PAREA_ARENA13)
call p.push(gg_rct_PAREA_ARENA14)
call p.push(gg_rct_PAREA_ARENA15)
call p.push(gg_rct_PAREA_ARENA16)
call p.push(gg_rct_PAREA_ARENA17)
call p.push(gg_rct_PAREA_ARENA18)
call p.push(gg_rct_PAREA_ARENA19)
call p.push(gg_rct_PAREA_ARENA20)
call p.push(gg_rct_PAREA_ARENA21)
call p.push(gg_rct_PAREA_ARENA22)
call p.push(gg_rct_PAREA_ARENA23)
call p.push(gg_rct_PAREA_ARENA24)
call p.push(gg_rct_PAREA_ARENA25)
call p.push(gg_rct_PAREA_ARENA26)
call p.push(gg_rct_PAREA_ARENA27)
call p.push(gg_rct_PAREA_ARENA28)
call p.push(gg_rct_PAREA_ARENA29)
call p.push(gg_rct_PAREA_ARENA30)
return p
endfunction
function CAGE_AREA_CREATE takes nothing returns PlayableArea
local PlayableArea p = PlayableArea.create()
call p.push(gg_rct_PAREA_CAGE1)
call p.push(gg_rct_PAREA_CAGE2)
call p.push(gg_rct_PAREA_CAGE3)
call p.push(gg_rct_PAREA_CAGE4)
call p.push(gg_rct_PAREA_CAGE5)
call p.push(gg_rct_PAREA_CAGE6)
call p.push(gg_rct_PAREA_CAGE7)
call p.push(gg_rct_PAREA_CAGE8)
call p.push(gg_rct_PAREA_CAGE9)
call p.push(gg_rct_PAREA_CAGE10)
call p.push(gg_rct_PAREA_CAGE11)
return p
endfunction
struct Difficulty
// sttic initialization is fake?
public static integer level = 0
public static Difficulty current
public static Difficulty easy
public static Difficulty normal
public static Difficulty hard
public string name
public string description
public string prompt
public string icon
//multi
public real creepDmg
public real creepHealth
public real bossAttribute
public integer diffLevel
static method create takes nothing returns thistype
local thistype this = thistype.allocate()
return this
endmethod
static method init takes nothing returns nothing
set easy = create()
set easy.name = "|cff98FB98SOLO(easy)|r"
set easy.prompt = "-solo"
set easy.description = "While the map is playable with any composition and amount of players, some heroes will find the solo experience too hard. This difficulty make the game |cff98FB98easier|r and it's suggested for solo runs but can also be selected with any amount of players."
set easy.creepDmg = 0.75
set easy.creepHealth = 0.75
set easy.bossAttribute = 0.9
set easy.diffLevel = 1
set easy.icon = ""
set normal = create()
set normal.name = "|cff4682B4NORMAL|r"
set normal.prompt = "-normal"
set normal.description = "How the game is meant to be played."
set normal.creepDmg = 1
set normal.creepHealth = 1
set normal.bossAttribute = 1
set normal.diffLevel = 2
set normal.icon = ""
set hard = create()
set hard.name = "|cff36454FHARD|r"
set hard.prompt = "-hard"
set hard.description = "An extra challenge. Hard adds new mechnics to bosses and creep but do change their stats directly"
set hard.creepDmg = 1
set hard.creepHealth = 1
set hard.bossAttribute = 1
set hard.diffLevel = 3
set hard.icon = ""
set level = 0
endmethod
endstruct
function adjustUnavailabilityMask takes integer index, boolean show, player p returns nothing
if p == GetLocalPlayer() then
call ShowImage(udg_UnavailablePickMask[index], show)
endif
endfunction
function initUnavailabilityMask takes nothing returns nothing
set udg_UnavailablePickMask[0] = CreateImage("war3mapImported\\redX.blp", 64, 64, 64, GetRectCenterX(gg_rct_PICKCL), GetRectCenterY(gg_rct_PICKCL), 10, 32, 32, 10, 1)
call SetImageRenderAlways(udg_UnavailablePickMask[0], true)
set udg_UnavailablePickMask[1] = CreateImage("war3mapImported\\redX.blp", 64, 64, 64, GetRectCenterX(gg_rct_PICKDL), GetRectCenterY(gg_rct_PICKDL), 10, 32, 32, 10, 1)
call SetImageRenderAlways(udg_UnavailablePickMask[1], true)
set udg_UnavailablePickMask[2] = CreateImage("war3mapImported\\redX.blp", 64, 64, 64, GetRectCenterX(gg_rct_PICKPL), GetRectCenterY(gg_rct_PICKPL), 10, 32, 32, 10, 1)
call SetImageRenderAlways(udg_UnavailablePickMask[2], true)
set udg_UnavailablePickMask[3] = CreateImage("war3mapImported\\redX.blp", 64, 64, 64, GetRectCenterX(gg_rct_PICKMC), GetRectCenterY(gg_rct_PICKMC), 10, 32, 32, 10, 1)
call SetImageRenderAlways(udg_UnavailablePickMask[3], true)
endfunction
function buildPrompt takes integer heroPicker, player p returns string
local HeroPicker hp = heroPicker
local string pickHints = ""
set pickHints = pickHints + "|cff66ee77Mysterious Cauldron|r - "
if (hp.mysteriousCauldron != null) then
set pickHints = pickHints + hp.mysteriousCauldron.description
else
set pickHints = pickHints + "|cffff0505UNAVAILABLE|r"
endif
set pickHints = pickHints + "\n"
call adjustUnavailabilityMask(3, hp.mysteriousCauldron == null, p)
set pickHints = pickHints + "|cff66ee77No Weapon|r (bottom circle) - "
if (hp.pileOfWeapons != null) then
set pickHints = pickHints + hp.pileOfWeapons.description
else
set pickHints = pickHints + "|cffff0505UNAVAILABLE|r"
endif
set pickHints = pickHints + "\n"
call adjustUnavailabilityMask(2, hp.pileOfWeapons == null, p)
set pickHints = pickHints + "|cff66ee77Lightning rod|r - "
if (hp.lightningRod != null) then
set pickHints = pickHints + hp.lightningRod.description
else
set pickHints = pickHints + "|cffff0505UNAVAILABLE|r"
endif
set pickHints = pickHints + "\n"
call adjustUnavailabilityMask(1, hp.lightningRod == null, p)
set pickHints = pickHints + "|cff66ee77Pile of Weapon|r - "
if (hp.noWeapon != null) then
set pickHints = pickHints + hp.noWeapon.description
else
set pickHints = pickHints + "|cffff0505UNAVAILABLE|r"
endif
set pickHints = pickHints + "\n"
call adjustUnavailabilityMask(0, hp.noWeapon == null, p)
return pickHints
endfunction
function Trig_ELEVATOR_UP takes nothing returns nothing
if ( GetDestructableTypeId(GetEnumDestructable()) == 'DTrf' ) then
call ChangeElevatorHeight( GetEnumDestructable(), 2 )
call ChangeElevatorWalls( false, bj_ELEVATOR_WALL_TYPE_ALL, GetEnumDestructable() )
endif
endfunction
function Trig_ELEVATOR_DOWN takes nothing returns nothing
if ( GetDestructableTypeId(GetEnumDestructable()) == 'DTrf' ) then
call DestructableRestoreLife( GetEnumDestructable(), GetDestructableMaxLife(GetEnumDestructable()), true )
call ChangeElevatorHeight( GetEnumDestructable(), 1 )
endif
endfunction
function Trig_ELEVATOR_OPEN takes nothing returns nothing
if ( GetDestructableTypeId(GetEnumDestructable()) == 'DTrf' ) then
call ChangeElevatorWalls( true, bj_ELEVATOR_WALL_TYPE_ALL, GetEnumDestructable() )
endif
endfunction
function Trig_ELEVATOR_Actions takes nothing returns nothing
call EnumDestructablesInRectAll( gg_rct_ELEVATORS, function Trig_ELEVATOR_UP )
call DisableTrigger( gg_trg_HERO_DIE )
call PolledWait( 4.00 )
call EnumDestructablesInRectAll( gg_rct_ELEVATORS, function Trig_ELEVATOR_DOWN )
call PolledWait( 1.00 )
call EnumDestructablesInRectAll( gg_rct_ELEVATORS, function Trig_ELEVATOR_OPEN )
endfunction
//===========================================================================
function InitTrig_ELEVATOR takes nothing returns nothing
set gg_trg_ELEVATOR = CreateTrigger( )
call TriggerAddAction( gg_trg_ELEVATOR, function Trig_ELEVATOR_Actions )
endfunction
function INIT_PICKERS_promptResponse takes nothing returns nothing
local unit u
local unit h
local unit pickerUnit
local HeroPickers hps
local HeroPicker hp
local player p
local integer i = 0
local string pickHints
set p = GetTriggerPlayer()
set hps = udg_HeroPickers
set hp = 0
set pickerUnit = udg_Pickers[GetPlayerId(p)]
loop
exitwhen hp != 0 or i == hps.size
if (hps.heroPickers[i].swapToPrompt == GetEventPlayerChatString()) then
set hp = hps.heroPickers[i]
endif
set i = i + 1
endloop
set h = udg_MainHeroes[GetPlayerId(p)]
if (h == null) then
set u = udg_Pickers[GetPlayerId(p)]
call ReplaceUnitBJ( u, hp.pickerType, bj_UNIT_STATE_METHOD_RELATIVE )
call SelectUnitForPlayerSingle( GetLastReplacedUnitBJ(), p )
set udg_Pickers[GetPlayerId(p)] = GetLastReplacedUnitBJ()
set pickHints = "You have switched to |cff6677ee" + hp.swapToPrompt + "|r\n\nYour available choices are:\n"
set pickHints = pickHints + buildPrompt(hp, GetTriggerPlayer())
call DisplayTextToPlayer(p, 0, 0, pickHints)
endif
set pickerUnit = null
set pickHints = null
set h = null
set u = null
set p = null
endfunction
function Trig_INIT_PICKERS_CreatePrompts takes integer heroPickers returns nothing
local HeroPickers hps
local integer i = 0
local integer j = 0
local trigger t
set hps = heroPickers
loop
exitwhen i == hps.size
set t = CreateTrigger()
set j = 0
loop
exitwhen j == 10
call TriggerRegisterPlayerChatEvent( t, Player(j), hps.heroPickers[i].swapToPrompt, true)
set j = j + 1
endloop
set i = i + 1
call TriggerAddAction(t, function INIT_PICKERS_promptResponse)
endloop
endfunction
function Trig_INIT_PICKERS_Actions takes nothing returns nothing
local HeroPickers hps
local HeroPicker hp
set hps = HeroPickers.create()
set hp = HeroPicker.create('ugho', "ghoul")
set hp.noWeapon = HeroPickerInteraction.create('U001', "A powerful single target fighter with mobility and sustain")
set hp.lightningRod = HeroPickerInteraction.create('U002', "A superior aoe fighter with sustain")
set hp.pileOfWeapons = HeroPickerInteraction.create('U003', "A powerful nuker with mana restoration capabilities")
call hps.push(hp)
set hp = HeroPicker.create('uktn', "necromancer")
set hp.noWeapon = HeroPickerInteraction.create('U005', "A versatile caster/summoner")
set hp.lightningRod = HeroPickerInteraction.create('U000', "A support caster/summoner")
set hp.pileOfWeapons = HeroPickerInteraction.create('U007', "A tanky fighter/summoner")
set hp.mysteriousCauldron = HeroPickerInteraction.create('U00I', "An aoe nuker and support")
call hps.push(hp)
set hp = HeroPicker.create('u00E', "assassin")
set hp.noWeapon = HeroPickerInteraction.create('U00C', "An illusive single target assassin with mobolity mana sustain")
set hp.lightningRod = HeroPickerInteraction.create('U00D', "A strong single target and AOE nuker with superior mobility but lacking in sustain")
set hp.pileOfWeapons = HeroPickerInteraction.create('U00B', "A powerful aoe fighter with sustain and mobility")
call hps.push(hp)
set udg_HeroPickers = hps
call initUnavailabilityMask()
call Trig_INIT_PICKERS_CreatePrompts(hps)
endfunction
//===========================================================================
function InitTrig_INIT_PICKERS takes nothing returns nothing
set gg_trg_INIT_PICKERS = CreateTrigger( )
call TriggerAddAction( gg_trg_INIT_PICKERS, function Trig_INIT_PICKERS_Actions )
endfunction
function Trig_INIT_PICK_BOUND_Actions takes nothing returns nothing
call SetCameraBoundsToRectForPlayerBJ( Player(0), gg_rct_BOUNDPICK )
call SetCameraBoundsToRectForPlayerBJ( Player(1), gg_rct_BOUNDPICK )
call SetCameraBoundsToRectForPlayerBJ( Player(2), gg_rct_BOUNDPICK )
call SetCameraBoundsToRectForPlayerBJ( Player(3), gg_rct_BOUNDPICK )
call SetCameraBoundsToRectForPlayerBJ( Player(4), gg_rct_BOUNDPICK )
call SetCameraBoundsToRectForPlayerBJ( Player(5), gg_rct_BOUNDPICK )
call SetCameraBoundsToRectForPlayerBJ( Player(6), gg_rct_BOUNDPICK )
call SetCameraBoundsToRectForPlayerBJ( Player(7), gg_rct_BOUNDPICK )
call SetCameraBoundsToRectForPlayerBJ( Player(8), gg_rct_BOUNDPICK )
call SetCameraBoundsToRectForPlayerBJ( Player(9), gg_rct_BOUNDPICK )
call BlzChangeMinimapTerrainTex("war3mapImported\\pickingGray.blp")
endfunction
//===========================================================================
function InitTrig_INIT_PICK_BOUND takes nothing returns nothing
set gg_trg_INIT_PICK_BOUND = CreateTrigger( )
call TriggerRegisterTimerEventSingle( gg_trg_INIT_PICK_BOUND, 0.00 )
call TriggerAddAction( gg_trg_INIT_PICK_BOUND, function Trig_INIT_PICK_BOUND_Actions )
endfunction
function Trig_INIT_WAVES_Actions takes nothing returns nothing
local Wave w
set udg_WaveIndex = 0
call Arena.init()
set w = Wave.create()
call w.push(WAVE1V1_CRABS_CREATE())
call w.push(WAVE1V2_MURLOCKS_CREATE())
call w.push(WAVE1V3_RAZORMANES_CREATE())
set udg_Waves[0] = w
set w = Wave.create()
call w.push(WAVE2V1_GNOLLS_CREATE ())
call w.push(WAVE2V2_SETTLERS_CREATE ())
call w.push(WAVE2V3_SLAVES_CREATE ())
set udg_Waves[1] = w
set w = Wave.create()
call w.push(WAVE3V1_BANDITS_CREATE ())
call w.push(WAVE3V2_DINITIATES_CREATE ())
call w.push(WAVE3V3_WARPARTY_CREATE ())
set udg_Waves[2] = w
set w = Wave.create()
call w.push(WAVE4V1_LIZARDS_CREATE ())
call w.push(WAVE4V2_RECONPARTY_CREATE ())
call w.push(WAVE4V3_ORCWARLOCKS_CREATE ())
set udg_Waves[3] = w
set w = Wave.create()
call w.push(WAVE5V1_TROLLS_CREATE ())
call w.push(WAVE5V2_TODL_CREATE ())
call w.push(WAVE5V3_CENTAURS_CREATE ())
set udg_Waves[4] = w
set w = Wave.create()
call w.push(WAVE6V1_TURTLES_CREATE())
call w.push(WAVE6V2_SPECIAL_FORCES_CREATE())
call w.push(WAVE6V3_CHAOS_ORCS_CREATE())
set udg_Waves[5] = w
set w = Wave.create()
call w.push(WAVE7V1_FURBOLGS_CREATE())
call w.push(WAVE7V2_KNIGHTS_CREATE())
set udg_Waves[6] = w
set w = Wave.create()
call w.push(WAVE8V1_WENDIGOS_CREATE ())
call w.push(WAVE8V2_SUMMONER_PRODIGY_CREATE ())
set udg_Waves[7] = w
set w = Wave.create()
//call w.push(WAVE9V1_BLUE_DRASGONS_CREATE ())
call w.push(WAVE9V2_ARCHMAGE_CREATE ())
set udg_Waves[8] = w
set w = Wave.create()
call w.push(WAVE10V1_SENIOR_PALADIN_CREATE ())
set udg_Waves[9] = w
//set udg_WaveIndex = 4 //
set udg_LastWaveIndex = 9
endfunction
//===========================================================================
function InitTrig_INIT_WAVES takes nothing returns nothing
set gg_trg_INIT_WAVES = CreateTrigger( )
call TriggerAddAction( gg_trg_INIT_WAVES, function Trig_INIT_WAVES_Actions )
endfunction
function Trig_INIT_COLORS_Actions takes nothing returns nothing
set udg_ColorPrefixes[0] = "|cffFF0000"
set udg_ColorPrefixes[1] = "|cff0000FF"
set udg_ColorPrefixes[2] = "|cff00FFFF"
set udg_ColorPrefixes[3] = "|cff800080"
set udg_ColorPrefixes[4] = "|cffFFFF00"
set udg_ColorPrefixes[5] = "|cffFF8000"
set udg_ColorPrefixes[6] = "|cff00FF00"
set udg_ColorPrefixes[7] = "|cffFF80C0"
set udg_ColorPrefixes[8] = "|cffC0C0C0"
set udg_ColorPrefixes[9] = "|cff80FFFF"
set udg_ColorPrefixes[10] = "|c00106246"
set udg_ColorPrefixes[11] = "|c004E2A04"
set udg_ColorPrefixes[12] = "|cff9c0000"
set udg_ColorPrefixes[13] = "|cff0000c3"
set udg_ColorPrefixes[14] = "|cff00ebff"
set udg_ColorPrefixes[15] = "|cffbd00ff"
set udg_ColorPrefixes[16] = "|cffecce87"
set udg_ColorPrefixes[17] = "|cfff7a58b"
set udg_ColorPrefixes[18] = "|cffbfff81"
set udg_ColorPrefixes[19] = "|cffdbb8eb"
set udg_ColorPrefixes[20] = "|cff4f5055"
set udg_ColorPrefixes[21] = "|cffecf0ff"
set udg_ColorPrefixes[22] = "|cff00781e"
set udg_ColorPrefixes[23] = "|cffa56f34"
set udg_ColorPrefixes[23] = "|cff2e2d2e"
endfunction
//===========================================================================
function InitTrig_INIT_COLORS takes nothing returns nothing
set gg_trg_INIT_COLORS = CreateTrigger( )
call TriggerAddAction( gg_trg_INIT_COLORS, function Trig_INIT_COLORS_Actions )
endfunction
function Trig_INIT_CREDITS_Actions takes nothing returns nothing
call Credits.push("|cff0073e6Thank you!|r")
call Credits.push("for: Damage Engine 5.A.0.0\nto: |cffffcc00Bride@hiveworkshop|r")
call Credits.push("for: T32\nto: |cffffcc00Jesus4Lyf@thehelper|r")
call Credits.push("for: Xe 0.9\nto: |cffffcc00Vexorian@hiveworkshop|r")
call Credits.push("for: Weapons pack\nto: |cffffcc00Sunchips@hiveworkshop|r")
call Credits.push("for: Target indicator\nto: |cffffcc00ThompZon@hiveworkshop|r")
call Credits.push("for: Spiked shield\nto: |cffffcc00InfernalTater@hiveworkshop|r")
call Credits.push("for: Assassin (Night Elf) and Derivatives\nto: |cffffcc00Ujimasa Hojo@hiveworkshop|r")
call Credits.push("for: Fighting women\nto: |cffffcc00Ujimasa CybrgDragon@hiveworkshop|r")
call Credits.push("for: Villager man\nto: |cffffcc00Aquis@hiveworkshop|r")
call Credits.push("for: Female Footman\nto: |cffffcc00Kuhneghetz@hiveworkshop|r")
call Credits.push("for: Human Archer\nto: |cffffcc00HappyTauren@hiveworkshop|r")
call Credits.push("for: Human Crossbow\nto: |cffffcc00Wandering Soul@hiveworkshop|r")
call Credits.push("for: CrossbowFootman and Derivatives\nto: |cffffcc00Jiok@hiveworkshop|r")
call Credits.push("for: Female Captain\nto: |cffffcc00Cavman@hiveworkshop and Kuhneghetz@hiveworkshop|r")
call Credits.push("for: Spell Markers\nto: |cffffcc00Vinz@hiveworkshop|r")
call Credits.push("for: Knight Female\nto: |cffffcc00Cavman@hiveworkshop|r")
call Credits.push("for: Bandit Lady\nto: |cffffcc00Cavman@hiveworkshop|r")
call Credits.push("for: BlueShockwaveMissile\nto: |cffffcc00Razer!X@hiveworkshop|r")
call Credits.push("for: Item Cleanup\nto: |cffffcc00Tirlititi@hiveworkshop|r")
call Credits.push("for: Female Warlock\nto: |cffffcc00Stefan.K@hiveworkshop|r")
call Credits.push("for: Orc Berserker\nto: |cffffcc00supertoinkz@hiveworkshop|r")
call Credits.push("for: Warlock Archer\nto: |cffffcc00eubz@hiveworkshop|r")
call Credits.push("for: Draka\nto: |cffffcc00Stefan.K@hiveworkshop|r")
call Credits.push("for: Axemaster pack\nto: |cffffcc00Ilya Alaric@hiveworkshop|r")
call Credits.push("for: Grunt Captain\nto: |cffffcc00Stefan.K@hiveworkshop|r")
call Credits.push("for: Orc Slave/Militia/Boulder Thrower\nto: |cffffcc00Stefan.K@hiveworkshop|r")
call Credits.push("for: War Drummer (Mammoth Mount) and Derivatives\nto: |cffffcc00Ujimasa Hojo@hiveworkshop|r")
call Credits.push("for: Orcish Spearthrower & Fel Orc Spearthrower\nto: |cffffcc00General Frank@hiveworkshop|r")
call Credits.push("for: Raider Models (Re-Classic Pack)\nto: |cffffcc00johnwar@hiveworkshop|r")
call Credits.push("for: WaterElemental(fire)\nto: |cffffcc00alfredx_sotn@hiveworkshop|r")
call Credits.push("for: Fire Missiles\nto: |cffffcc00Vinz@hiveworkshop|r")
call Credits.push("for: HeroGlow\nto: |cffffcc00assasin_lord@hiveworkshop|r")
call CreateQuestBJ( bj_QUESTTYPE_OPT_DISCOVERED, "Credits", "Credits are available at the circle of power in the bottom right corner of the hub", "ReplaceableTextures\\CommandButtons\\BTNAcorn.blp" )
endfunction
//===========================================================================
function InitTrig_INIT_CREDITS takes nothing returns nothing
set gg_trg_INIT_CREDITS = CreateTrigger( )
call TriggerRegisterTimerEventSingle( gg_trg_INIT_CREDITS, 10.00 )
call TriggerAddAction( gg_trg_INIT_CREDITS, function Trig_INIT_CREDITS_Actions )
endfunction
function Trig_INIT_GLOBALS_Actions takes nothing returns nothing
set udg_NotifyRegistry = InitHashtable( )
set udg_LightningSMap = InitHashtable( )
set udg_WaveBehaviorMap = InitHashtable( )
set udg_UniqueEffectsMap = InitHashtable( )
set udg_ClassShopMap = InitHashtable( )
set udg_DummyToHeroMap = InitHashtable()
set udg_UtilMap = InitHashtable()
set udg_TEX = CreateTrigger()
set udg_UnitRewardMap = InitHashtable()
set udg_ReviveStats = InitHashtable()
endfunction
//===========================================================================
function InitTrig_INIT_GLOBALS takes nothing returns nothing
set gg_trg_INIT_GLOBALS = CreateTrigger( )
call TriggerAddAction( gg_trg_INIT_GLOBALS, function Trig_INIT_GLOBALS_Actions )
endfunction
function Trig_INIT_MISC_Actions takes nothing returns nothing
local integer i = 0
set ROUND_STATS.instance = ROUND_STATS.create()
//
loop
exitwhen i == 30
set udg_AMOVE_GROUPS[i] = CreateGroup()
set i = i + 1
endloop
//0 - 20 general purpose
//20 - 30 special
call SkeletonNames.push("Skelethral")
call SkeletonNames.push("Banebone")
call SkeletonNames.push("Malevolimb")
call SkeletonNames.push("Cryptcrawler")
call SkeletonNames.push("Marrowmancer")
call SkeletonNames.push("Vilevessel")
call SkeletonNames.push("Bonebrute")
call SkeletonNames.push("Cadaverous Thrall")
call Difficulty.init()
call SetPlayerColorBJ(Player(23), ConvertPlayerColor(20), true)
endfunction
//===========================================================================
function InitTrig_INIT_MISC takes nothing returns nothing
set gg_trg_INIT_MISC = CreateTrigger( )
call TriggerRegisterTimerEventSingle( gg_trg_INIT_MISC, 3.00 )
call TriggerAddAction( gg_trg_INIT_MISC, function Trig_INIT_MISC_Actions )
endfunction
function Trig_INIT_COMMANDS_QUEST_Actions takes nothing returns nothing
local string s = "Picking phase:\n\n"
local quest q = CreateQuest()
set s = s + " • |cffef0510-repick|r: replace the PICKED HERO with a random HERO PICKER\n"
set s = s + " • |cffef0510assassin|r: replace the current HERO PICKER with the |cffef0510assassin|r HERO PICKER\n"
set s = s + " • |cffef0510ghoul|r: replace the current HERO PICKER with the |cffef0510ghoul|r HERO PICKER\n"
set s = s + " • |cffef0510necromancer|r: replace the current HERO PICKER with the |cffef0510necromancer|r HERO PICKER\n"
call QuestSetTitle(q, "Commands Picking Phase")
call QuestSetDescription(q, s)
call QuestSetIconPath(q, "ReplaceableTextures\\CommandButtons\\BTNManual3.blp")
call QuestSetRequired(q, true)
call QuestSetDiscovered(q, true)
call QuestSetCompleted(q, false)
set udg_QuestPick = q
set s = "Hub:\n\n"
set s = s + " • |cffef0510stop|r: stops the hub timer, player 1 only\n"
set s = s + " • |cffef0510resume|r: resumes the hub timer, player 1 only\n"
set q = CreateQuest()
call QuestSetTitle(q, "Commands Hub")
call QuestSetDescription(q, s)
call QuestSetIconPath(q, "ReplaceableTextures\\CommandButtons\\BTNManual3.blp")
call QuestSetRequired(q, true)
call QuestSetDiscovered(q, true)
call QuestSetCompleted(q, false)
set s = "Difficulties:\n\n"
set s = s + " • |cffef0510-solo|r: an easy difficulty recomanded for solo runs\n"
set s = s + " • |cffef0510-normal|r: as the game was intented to play\n"
set q = CreateQuest()
call QuestSetTitle(q, "Commands Difficulties")
call QuestSetDescription(q, s)
call QuestSetIconPath(q, "ReplaceableTextures\\CommandButtons\\BTNBookOfTheDead.blp")
call QuestSetRequired(q, false)
call QuestSetDiscovered(q, true)
call QuestSetCompleted(q, false)
set udg_QuestDiff = q
set q = null
endfunction
//===========================================================================
function InitTrig_INIT_COMMANDS_QUEST takes nothing returns nothing
set gg_trg_INIT_COMMANDS_QUEST = CreateTrigger( )
call TriggerAddAction( gg_trg_INIT_COMMANDS_QUEST, function Trig_INIT_COMMANDS_QUEST_Actions )
endfunction
function Trig_REMOVE_PRELOAD_f takes nothing returns nothing
call KillUnit(GetEnumUnit())
call RemoveUnit(GetEnumUnit())
endfunction
function Trig_REMOVE_PRELOAD_Actions takes nothing returns nothing
call ForGroup(udg_PreloadGroup, function Trig_REMOVE_PRELOAD_f)
endfunction
//===========================================================================
function InitTrig_REMOVE_PRELOAD takes nothing returns nothing
set gg_trg_REMOVE_PRELOAD = CreateTrigger( )
call TriggerRegisterTimerEventSingle( gg_trg_REMOVE_PRELOAD, 10.00 )
call TriggerAddAction( gg_trg_REMOVE_PRELOAD, function Trig_REMOVE_PRELOAD_Actions )
endfunction
function Trig_CREATE_STARTING_UNITS_LoopConditon takes nothing returns boolean
return GetPlayerSlotState(GetFilterPlayer()) == PLAYER_SLOT_STATE_PLAYING and GetPlayerController(GetFilterPlayer()) == MAP_CONTROL_USER
endfunction
function Trig_CREATE_STARTING_UNITS_LoopAction takes nothing returns nothing
local integer random
local unit u
local HeroPickers hps
local HeroPicker hp
local string heroHint
set hps = udg_HeroPickers
call ForceAddPlayer(udg_HumanPlayers, GetEnumPlayer())
set random = GetRandomInt(0, hps.size - 1)
set hp = hps.heroPickers[random]
set u = CreateUnitAtLoc(GetEnumPlayer(), hp.pickerType, GetPlayerStartLocationLoc(GetEnumPlayer()), bj_UNIT_FACING )
set heroHint = "Before the game begins you have to select an hero with your picker, you can do so by walking into a circle of power.\n\n" + "Your available choices are:\n"
set heroHint = heroHint + buildPrompt(hp, GetEnumPlayer())
call DisplayTimedTextToPlayer(GetOwningPlayer(u), 0, 0, 5, heroHint)
set udg_Pickers[GetPlayerId(GetEnumPlayer())] = u
set udg_CURRENT_PLAYABLE_AREA = PICK_AREA_CREATE()
set udg_PlayerCount = ( udg_PlayerCount + 1 )
set u = null
set heroHint = null
endfunction
function NoExpFromKilling takes nothing returns nothing
call SetPlayerHandicapXP(GetEnumPlayer(), 0.00 )
endfunction
function Trig_CREATE_STARTING_UNITS_Actions takes nothing returns nothing
call ForForce( GetPlayersMatching(Condition(function Trig_CREATE_STARTING_UNITS_LoopConditon)), function Trig_CREATE_STARTING_UNITS_LoopAction)
call ForForce( udg_HumanPlayers, function NoExpFromKilling)
set udg_VoteWeight = 4 / udg_PlayerCount + 1
endfunction
//===========================================================================
function InitTrig_CREATE_STARTING_UNITS takes nothing returns nothing
set gg_trg_CREATE_STARTING_UNITS = CreateTrigger( )
call TriggerRegisterTimerEventSingle( gg_trg_CREATE_STARTING_UNITS, 1.00 )
call TriggerAddAction( gg_trg_CREATE_STARTING_UNITS, function Trig_CREATE_STARTING_UNITS_Actions )
endfunction
function Trig_DC1_Func001A takes nothing returns nothing
call RemoveUnit(GetEnumUnit())
endfunction
function Trig_DC1_Actions takes nothing returns nothing
local player p = GetTriggerPlayer()
local integer id = GetPlayerId(p)
call DisplayTextToForce(GetPlayersAll(), "Player " + udg_ColorPrefixes[GetPlayerId(p)] + GetPlayerName(GetTriggerPlayer()) + "|r has left the game")
set udg_MainHeroes[id] = null
set udg_HeroPicked[id] = false
set bj_wantDestroyGroup = true
call ForGroupBJ(GetUnitsOfPlayerAll(p), function Trig_DC1_Func001A )
call ForceRemovePlayer(udg_HumanPlayers, p)
set p = null
call TriggerExecute(gg_trg_DC)
endfunction
//===========================================================================
function InitTrig_DC1 takes nothing returns nothing
set gg_trg_DC1 = CreateTrigger( )
call TriggerRegisterPlayerEventLeave( gg_trg_DC1, Player(0) )
call TriggerRegisterPlayerEventLeave( gg_trg_DC1, Player(1) )
call TriggerRegisterPlayerEventLeave( gg_trg_DC1, Player(2) )
call TriggerRegisterPlayerEventLeave( gg_trg_DC1, Player(3) )
call TriggerRegisterPlayerEventLeave( gg_trg_DC1, Player(4) )
call TriggerRegisterPlayerEventLeave( gg_trg_DC1, Player(5) )
call TriggerRegisterPlayerEventLeave( gg_trg_DC1, Player(6) )
call TriggerRegisterPlayerEventLeave( gg_trg_DC1, Player(7) )
call TriggerRegisterPlayerEventLeave( gg_trg_DC1, Player(8) )
call TriggerRegisterPlayerEventLeave( gg_trg_DC1, Player(9) )
call TriggerAddAction( gg_trg_DC1, function Trig_DC1_Actions )
endfunction
function Trig_DC_Actions takes nothing returns nothing
set udg_PlayerCount = CountPlayersInForceBJ(udg_HumanPlayers)
call DisplayTextToForce( GetPlayersAll(), ( "Player count: " + I2S(udg_PlayerCount) ) )
set udg_VoteWeight = 4 / udg_PlayerCount + 1
if ( IsMultiboardDisplayed(udg_PickBoard) ) then
call ConditionalTriggerExecute( gg_trg_UPDATE_PICK_BOARD )
endif
endfunction
//===========================================================================
function InitTrig_DC takes nothing returns nothing
set gg_trg_DC = CreateTrigger( )
call TriggerAddAction( gg_trg_DC, function Trig_DC_Actions )
endfunction
struct HeroPickerInteraction
integer utype
string description
static method create takes integer utype, string description returns thistype
local thistype this = thistype.allocate()
set this.utype = utype
set this.description = description
return this
endmethod
endstruct
struct HeroPicker
integer pickerType
string swapToPrompt
HeroPickerInteraction mysteriousCauldron
HeroPickerInteraction pileOfWeapons
HeroPickerInteraction lightningRod
HeroPickerInteraction noWeapon
static method create takes integer utype, string prompt returns thistype
local thistype this = thistype.allocate()
set this.pickerType = utype
set this.swapToPrompt = prompt
return this
endmethod
endstruct
struct HeroPickers
integer size
HeroPicker array heroPickers[10]
static method create takes nothing returns thistype
local thistype this = thistype.allocate()
return this
endmethod
method push takes HeroPicker h returns nothing
set heroPickers[size] = h
set size = size + 1
endmethod
endstruct
function CountSelectedHeroes takes nothing returns integer
local integer count = 0
local integer i = 0
loop
exitwhen i == 10
if udg_HeroPicked[i] then
set count = count + 1
endif
set i = i + 1
endloop
return count
endfunction
function Trig_JAILOR_PROMPT_Actions takes nothing returns nothing
call TransmissionFromUnitWithNameBJ( GetPlayersAll(), gg_unit_u009_0026, "TRIGSTR_969", null, "TRIGSTR_970", bj_TIMETYPE_SET, 2.00, true )
call TransmissionFromUnitWithNameBJ( GetPlayersAll(), gg_unit_u009_0026, "TRIGSTR_969", null, "TRIGSTR_972", bj_TIMETYPE_SET, 2.00, true )
endfunction
//===========================================================================
function InitTrig_JAILOR_PROMPT takes nothing returns nothing
set gg_trg_JAILOR_PROMPT = CreateTrigger( )
call TriggerRegisterTimerEventSingle( gg_trg_JAILOR_PROMPT, 10.00 )
call TriggerAddAction( gg_trg_JAILOR_PROMPT, function Trig_JAILOR_PROMPT_Actions )
endfunction
function Trig_UPDATE_PICK_BOARD_Actions takes nothing returns nothing
local integer count = CountPlayersInForceBJ(udg_HumanPlayers)
local multiboarditem mbitem
local integer row = 0
local integer i = 0
call MultiboardSetRowCount(udg_PickBoard, count)
loop
exitwhen i == 10
if (IsPlayerInForce(Player(i), udg_HumanPlayers)) then
set mbitem = MultiboardGetItem(udg_PickBoard, row, 0)
call MultiboardSetItemStyle(mbitem, true, false)
call MultiboardSetItemValue(mbitem, udg_ColorPrefixes[(i)] + ( GetPlayerName(Player(i)) + "|r" ))
call MultiboardSetItemWidth(mbitem, 0.12)
call MultiboardReleaseItem(mbitem)
set mbitem = MultiboardGetItem(udg_PickBoard, row, 1)
call MultiboardSetItemStyle(mbitem, true, false)
if (udg_HeroPicked[i]) then
call MultiboardSetItemValue(mbitem, "TRIGSTR_047")
else
call MultiboardSetItemValue(mbitem, "TRIGSTR_048")
endif
call MultiboardSetItemWidth(mbitem, 0.08)
call MultiboardReleaseItem(mbitem)
set row = row + 1
endif
set i = i + 1
endloop
set mbitem = null
call MultiboardDisplay(udg_PickBoard, true)
endfunction
//===========================================================================
function InitTrig_UPDATE_PICK_BOARD takes nothing returns nothing
set gg_trg_UPDATE_PICK_BOARD = CreateTrigger( )
call TriggerAddAction( gg_trg_UPDATE_PICK_BOARD, function Trig_UPDATE_PICK_BOARD_Actions )
endfunction
function Trig_ALLPICKED_WAIT_Conditions takes nothing returns boolean
return udg_PlayerCount == CountSelectedHeroes()
endfunction
function Trig_ALLPICKED_WAIT_Actions takes nothing returns nothing
call ClearTextMessagesBJ(udg_HumanPlayers)
call DisplayTextToForce( GetPlayersAll(), "TRIGSTR_021" )
call StartTimerBJ( udg_RepickTimer, false, 5.00 )
call PauseTimerBJ( false, udg_RepickTimer )
endfunction
//===========================================================================
function InitTrig_ALLPICKED_WAIT takes nothing returns nothing
set gg_trg_ALLPICKED_WAIT = CreateTrigger( )
call TriggerAddCondition( gg_trg_ALLPICKED_WAIT, Condition( function Trig_ALLPICKED_WAIT_Conditions ) )
call TriggerAddAction( gg_trg_ALLPICKED_WAIT, function Trig_ALLPICKED_WAIT_Actions )
endfunction
function Trig_ALLPICKED_GOTO_HUB_Conditions takes nothing returns boolean
return udg_PlayerCount == CountSelectedHeroes()
endfunction
function Trig_ALLPICKED_GOTO_HUB_Actions takes nothing returns nothing
call DisableTrigger( gg_trg_REPICK )
call ClearTextMessagesBJ(udg_HumanPlayers)
call QuestSetCompleted(udg_QuestPick, true)
call DisplayTextToForce( GetPlayersAll(), ( "Player count: " + I2S(udg_PlayerCount) ) )
call PolledWait( 1.00 )
call ConditionalTriggerExecute( gg_trg_START_HUB )
call EnableTrigger( gg_trg_HERO_DIE )
endfunction
//===========================================================================
function InitTrig_ALLPICKED_GOTO_HUB takes nothing returns nothing
set gg_trg_ALLPICKED_GOTO_HUB = CreateTrigger( )
call TriggerRegisterTimerExpireEventBJ( gg_trg_ALLPICKED_GOTO_HUB, udg_RepickTimer )
call TriggerAddCondition( gg_trg_ALLPICKED_GOTO_HUB, Condition( function Trig_ALLPICKED_GOTO_HUB_Conditions ) )
call TriggerAddAction( gg_trg_ALLPICKED_GOTO_HUB, function Trig_ALLPICKED_GOTO_HUB_Actions )
endfunction
function HeroPick takes unit picker, integer toCode, string seffect returns nothing
local location l
local effect e
call ReplaceUnitBJ(picker, toCode, bj_UNIT_STATE_METHOD_MAXIMUM)
set l = GetUnitLoc(GetLastReplacedUnitBJ())
set e = AddSpecialEffectLoc(seffect, l)
call DestroyEffect(e)
call SelectUnitForPlayerSingle(GetLastReplacedUnitBJ(), GetOwningPlayer(picker))
set udg_MainHeroes[GetPlayerId(GetOwningPlayer(picker))] = GetLastReplacedUnitBJ()
set udg_HeroPicked[GetPlayerId(GetOwningPlayer(picker))] = true
call ConditionalTriggerExecute(gg_trg_UPDATE_PICK_BOARD)
if udg_PlayerCount == CountSelectedHeroes() then
call Trig_ALLPICKED_WAIT_Actions()
endif
call DestroyEffect(e)
call RemoveLocation(l)
set e = null
set l = null
endfunction
function Trig_NO_WEAPONS_GH_Conditions takes nothing returns boolean
return GetUnitTypeId(GetTriggerUnit()) == 'ugho'
endfunction
function Trig_NO_WEAPONS_GH_Actions takes nothing returns nothing
call HeroPick(GetTriggerUnit(), 'U001', "Abilities\\Spells\\Other\\Charm\\CharmTarget.mdl")
/*
local image im = CreateImage("war3mapImported\\redX.blp", 64, 64, 64, GetUnitX(GetTriggerUnit()), GetUnitY(GetTriggerUnit()), 10, 32, 32, 10, 1)
call SetImageRenderAlways(im, true)
call ShowImage(im, false)
*/
endfunction
//===========================================================================
function InitTrig_NO_WEAPONS_GH takes nothing returns nothing
set gg_trg_NO_WEAPONS_GH = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_NO_WEAPONS_GH, gg_rct_PICKCL )
call TriggerAddCondition( gg_trg_NO_WEAPONS_GH, Condition( function Trig_NO_WEAPONS_GH_Conditions ) )
call TriggerAddAction( gg_trg_NO_WEAPONS_GH, function Trig_NO_WEAPONS_GH_Actions )
endfunction
function Trig_NO_WEAPONS_NC_Conditions takes nothing returns boolean
return GetUnitTypeId(GetTriggerUnit()) == 'uktn'
endfunction
function Trig_NO_WEAPONS_NC_Actions takes nothing returns nothing
call HeroPick(GetTriggerUnit(), 'U005', "Abilities\\Spells\\Other\\Charm\\CharmTarget.mdl")
endfunction
//===========================================================================
function InitTrig_NO_WEAPONS_NC takes nothing returns nothing
set gg_trg_NO_WEAPONS_NC = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_NO_WEAPONS_NC, gg_rct_PICKCL )
call TriggerAddCondition( gg_trg_NO_WEAPONS_NC, Condition( function Trig_NO_WEAPONS_NC_Conditions ) )
call TriggerAddAction( gg_trg_NO_WEAPONS_NC, function Trig_NO_WEAPONS_NC_Actions )
endfunction
function Trig_NO_WEAPONS_AS_Conditions takes nothing returns boolean
return GetUnitTypeId(GetTriggerUnit()) == 'u00E'
endfunction
function Trig_NO_WEAPONS_AS_Actions takes nothing returns nothing
call HeroPick(GetTriggerUnit(), 'U00C', "Abilities\\Spells\\Other\\Charm\\CharmTarget.mdl")
endfunction
//===========================================================================
function InitTrig_NO_WEAPONS_AS takes nothing returns nothing
set gg_trg_NO_WEAPONS_AS = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_NO_WEAPONS_AS, gg_rct_PICKCL )
call TriggerAddCondition( gg_trg_NO_WEAPONS_AS, Condition( function Trig_NO_WEAPONS_AS_Conditions ) )
call TriggerAddAction( gg_trg_NO_WEAPONS_AS, function Trig_NO_WEAPONS_AS_Actions )
endfunction
function Trig_LIGHTINING_ROD_GH_Conditions takes nothing returns boolean
return GetUnitTypeId(GetTriggerUnit()) == 'ugho'
endfunction
function Trig_LIGHTINING_ROD_GH_Actions takes nothing returns nothing
local unit u
local location l
local effect ef
local integer id
set u = GetTriggerUnit()
set l = GetUnitLoc(u)
set id = GetPlayerId(GetOwningPlayer(u))
// temp filling array before sleep
set udg_MainHeroes[id] = u
call AddSpecialEffectLocBJ( l, "Doodads\\Cinematic\\Lightningbolt\\Lightningbolt.mdl" )
set ef = GetLastCreatedEffectBJ()
call AddSpecialEffectLocBJ( l, "Abilities\\Spells\\Orc\\WarStomp\\WarStompCaster.mdl" )
call DestroyEffect( GetLastCreatedEffectBJ() )
call KillUnit( u )
call TriggerSleepAction( 1.25 )
call DestroyEffect( ef )
call ReplaceUnitBJ( u, 'U002', bj_UNIT_STATE_METHOD_MAXIMUM )
set u = GetLastReplacedUnitBJ()
call SelectUnitForPlayerSingle( u, GetOwningPlayer(u) )
call AddSpecialEffectLocBJ( l, "Abilities\\Spells\\Human\\Resurrect\\ResurrectTarget.mdl" )
call DestroyEffect( GetLastCreatedEffectBJ() )
set udg_MainHeroes[id] = GetLastReplacedUnitBJ()
set udg_HeroPicked[id] = true
call ConditionalTriggerExecute( gg_trg_UPDATE_PICK_BOARD )
if ( udg_PlayerCount == CountSelectedHeroes() ) then
call Trig_ALLPICKED_WAIT_Actions()
endif
call RemoveLocation(l)
set ef = null
set u = null
set l = null
endfunction
//===========================================================================
function InitTrig_LIGHTINING_ROD_GH takes nothing returns nothing
set gg_trg_LIGHTINING_ROD_GH = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_LIGHTINING_ROD_GH, gg_rct_PICKDL )
call TriggerAddCondition( gg_trg_LIGHTINING_ROD_GH, Condition( function Trig_LIGHTINING_ROD_GH_Conditions ) )
call TriggerAddAction( gg_trg_LIGHTINING_ROD_GH, function Trig_LIGHTINING_ROD_GH_Actions )
endfunction
function Trig_LIGHTINING_ROD_NC_Conditions takes nothing returns boolean
return GetUnitTypeId(GetTriggerUnit()) == 'uktn'
endfunction
function Trig_LIGHTINING_ROD_NC_Actions takes nothing returns nothing
call HeroPick(GetTriggerUnit(), 'U000', "Abilities\\Spells\\Other\\Charm\\CharmTarget.mdl")
endfunction
//===========================================================================
function InitTrig_LIGHTINING_ROD_NC takes nothing returns nothing
set gg_trg_LIGHTINING_ROD_NC = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_LIGHTINING_ROD_NC, gg_rct_PICKDL )
call TriggerAddCondition( gg_trg_LIGHTINING_ROD_NC, Condition( function Trig_LIGHTINING_ROD_NC_Conditions ) )
call TriggerAddAction( gg_trg_LIGHTINING_ROD_NC, function Trig_LIGHTINING_ROD_NC_Actions )
endfunction
function Trig_LIGHTINING_ROD_AS_Conditions takes nothing returns boolean
return GetUnitTypeId(GetTriggerUnit()) == 'u00E'
endfunction
function Trig_LIGHTINING_ROD_AS_Actions takes nothing returns nothing
call HeroPick(GetTriggerUnit(), 'U00D', "Abilities\\Spells\\Other\\Charm\\CharmTarget.mdl")
endfunction
//===========================================================================
function InitTrig_LIGHTINING_ROD_AS takes nothing returns nothing
set gg_trg_LIGHTINING_ROD_AS = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_LIGHTINING_ROD_AS, gg_rct_PICKDL )
call TriggerAddCondition( gg_trg_LIGHTINING_ROD_AS, Condition( function Trig_LIGHTINING_ROD_AS_Conditions ) )
call TriggerAddAction( gg_trg_LIGHTINING_ROD_AS, function Trig_LIGHTINING_ROD_AS_Actions )
endfunction
function Trig_PILE_OF_WEAPONS_NC_Conditions takes nothing returns boolean
return GetUnitTypeId(GetTriggerUnit()) == 'uktn'
endfunction
function Trig_PILE_OF_WEAPONS_NC_Actions takes nothing returns nothing
call HeroPick(GetTriggerUnit(), 'U007', "Abilities\\Spells\\Human\\Polymorph\\PolyMorphDoneGround.mdl")
endfunction
//===========================================================================
function InitTrig_PILE_OF_WEAPONS_NC takes nothing returns nothing
set gg_trg_PILE_OF_WEAPONS_NC = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_PILE_OF_WEAPONS_NC, gg_rct_PICKPL )
call TriggerAddCondition( gg_trg_PILE_OF_WEAPONS_NC, Condition( function Trig_PILE_OF_WEAPONS_NC_Conditions ) )
call TriggerAddAction( gg_trg_PILE_OF_WEAPONS_NC, function Trig_PILE_OF_WEAPONS_NC_Actions )
endfunction
function Trig_PILE_OF_WEAPONS_GH_Conditions takes nothing returns boolean
return GetUnitTypeId(GetTriggerUnit()) == 'ugho'
endfunction
function Trig_PILE_OF_WEAPONS_GH_Actions takes nothing returns nothing
call HeroPick(GetTriggerUnit(), 'U003', "Abilities\\Spells\\Human\\Polymorph\\PolyMorphDoneGround.mdl")
endfunction
//===========================================================================
function InitTrig_PILE_OF_WEAPONS_GH takes nothing returns nothing
set gg_trg_PILE_OF_WEAPONS_GH = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_PILE_OF_WEAPONS_GH, gg_rct_PICKPL )
call TriggerAddCondition( gg_trg_PILE_OF_WEAPONS_GH, Condition( function Trig_PILE_OF_WEAPONS_GH_Conditions ) )
call TriggerAddAction( gg_trg_PILE_OF_WEAPONS_GH, function Trig_PILE_OF_WEAPONS_GH_Actions )
endfunction
function Trig_PILE_OF_WEAPONS_AS_Conditions takes nothing returns boolean
return GetUnitTypeId(GetTriggerUnit()) == 'u00E'
endfunction
function Trig_PILE_OF_WEAPONS_AS_Actions takes nothing returns nothing
call HeroPick(GetTriggerUnit(), 'U00B', "Abilities\\Spells\\Human\\Polymorph\\PolyMorphDoneGround.mdl")
endfunction
//===========================================================================
function InitTrig_PILE_OF_WEAPONS_AS takes nothing returns nothing
set gg_trg_PILE_OF_WEAPONS_AS = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_PILE_OF_WEAPONS_AS, gg_rct_PICKPL )
call TriggerAddCondition( gg_trg_PILE_OF_WEAPONS_AS, Condition( function Trig_PILE_OF_WEAPONS_AS_Conditions ) )
call TriggerAddAction( gg_trg_PILE_OF_WEAPONS_AS, function Trig_PILE_OF_WEAPONS_AS_Actions )
endfunction
function Trig_MYSTERYOUSC_NC_Conditions takes nothing returns boolean
return GetUnitTypeId(GetTriggerUnit()) == 'uktn'
endfunction
function Trig_MYSTERYOUSC_NC_Actions takes nothing returns nothing
local unit u
local location l
local integer id
set u = GetTriggerUnit()
set l = GetUnitLoc(u)
set id = GetPlayerId(GetOwningPlayer(u))
// temp filling array before sleep
set udg_MainHeroes[id] = u
call KillUnit( u )
call TriggerSleepAction( 2.0 )
call ReplaceUnitBJ(u, 'U00I', bj_UNIT_STATE_METHOD_MAXIMUM)
set u = GetLastReplacedUnitBJ()
call SelectUnitForPlayerSingle( u, GetOwningPlayer(u) )
call AddSpecialEffectLocBJ(l, "Abilities\\Spells\\Items\\TomeOfRetraining\\TomeOfRetrainingCaster.mdl")
call DestroyEffect( GetLastCreatedEffectBJ() )
set udg_MainHeroes[id] = GetLastReplacedUnitBJ()
set udg_HeroPicked[id] = true
call ConditionalTriggerExecute( gg_trg_UPDATE_PICK_BOARD )
if ( udg_PlayerCount == CountSelectedHeroes() ) then
call Trig_ALLPICKED_WAIT_Actions()
endif
call RemoveLocation(l)
set u = null
set l = null
endfunction
//===========================================================================
function InitTrig_MYSTERYOUSC_NC takes nothing returns nothing
set gg_trg_MYSTERYOUSC_NC = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_MYSTERYOUSC_NC, gg_rct_PICKMC )
call TriggerAddCondition( gg_trg_MYSTERYOUSC_NC, Condition( function Trig_MYSTERYOUSC_NC_Conditions ) )
call TriggerAddAction( gg_trg_MYSTERYOUSC_NC, function Trig_MYSTERYOUSC_NC_Actions )
endfunction
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~ Timer32 ~~ By Jesus4Lyf ~~ Version 1.06 ~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// What is Timer32?
// - Timer32 implements a fully optimised timer loop for a struct.
// - Instances can be added to the loop, which will call .periodic every
// PERIOD until .stopPeriodic() is called.
//
// =Pros=
// - Efficient.
// - Simple.
//
// =Cons=
// - Only allows one period.
// - The called method must be named ".periodic".
//
// Methods:
// - struct.startPeriodic()
// - struct.stopPeriodic()
//
// - private method periodic takes nothing returns nothing
//
// This must be defined in structs that implement Periodic Module.
// It will be executed by the module every PERIOD until .stopPeriodic() is called.
// Put "implement T32x" BELOW this method.
//
// Modules:
// - T32x
// Has no safety on .stopPeriodic or .startPeriodic (except debug messages
// to warn).
//
// - T32xs
// Has safety on .stopPeriodic and .startPeriodic so if they are called
// multiple times, or while otherwise are already stopped/started respectively,
// no error will occur, the call will be ignored.
//
// - T32
// The original, old version of the T32 module. This remains for backwards
// compatability, and is deprecated. The periodic method must return a boolean,
// false to continue running or true to stop.
//
// Details:
// - Uses one timer.
//
// - Do not, within a .periodic method, follow a .stopPeriodic call with a
// .startPeriodic call.
//
// How to import:
// - Create a trigger named T32.
// - Convert it to custom text and replace the whole trigger text with this.
//
// Thanks:
// - Infinitegde for finding a bug in the debug message that actually altered
// system operation (when in debug mode).
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
library T32 initializer OnInit
globals
public constant real PERIOD=0.03125
public constant integer FPS=R2I(1/PERIOD)
public integer Tick=0 // very useful.
//==============================================================================
private trigger Trig=CreateTrigger()
endglobals
//==============================================================================
// The standard T32 module, T32x.
//
module T32x
private thistype next
private thistype prev
private static method PeriodicLoop takes nothing returns boolean
local thistype this=thistype(0).next
loop
exitwhen this==0
call this.periodic()
set this=this.next
endloop
return false
endmethod
method startPeriodic takes nothing returns nothing
debug if this.prev!=0 or thistype(0).next==this then
debug call BJDebugMsg("T32 ERROR: Struct #"+I2S(this)+" had startPeriodic called while already running!")
debug endif
set thistype(0).next.prev=this
set this.next=thistype(0).next
set thistype(0).next=this
set this.prev=thistype(0)
endmethod
method stopPeriodic takes nothing returns nothing
debug if this.prev==0 and thistype(0).next!=this then
debug call BJDebugMsg("T32 ERROR: Struct #"+I2S(this)+" had stopPeriodic called while not running!")
debug endif
// This is some real magic.
set this.prev.next=this.next
set this.next.prev=this.prev
// This will even work for the starting element.
debug set this.prev=0
endmethod
private static method onInit takes nothing returns nothing
call TriggerAddCondition(Trig,Condition(function thistype.PeriodicLoop))
endmethod
endmodule
//==============================================================================
// System Core.
//
private function OnExpire takes nothing returns nothing
set Tick=Tick+1
call TriggerEvaluate(Trig)
endfunction
private function OnInit takes nothing returns nothing
call TimerStart(CreateTimer(),PERIOD,true,function OnExpire)
endfunction
endlibrary
struct DestroyAfterSpecialEffect
private effect se
private integer endTick
private method periodic takes nothing returns nothing
if this.endTick == T32_Tick and se != null then
call DestroyEffect( se )
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes real duration, effect special returns thistype
local thistype this = thistype.allocate()
set this.se = special
set this.endTick = T32_Tick + R2I(duration / T32_PERIOD)
return this
endmethod
endstruct
struct DestroyAfterLightning
private lightning lg
private integer endTick
private method periodic takes nothing returns nothing
if this.endTick == T32_Tick and lg != null then
call DestroyLightning(lg)
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes real duration, lightning special returns thistype
local thistype this = thistype.allocate()
set this.lg = special
set this.endTick = T32_Tick + R2I(duration / T32_PERIOD)
return this
endmethod
endstruct
struct RemoveBuffAfter
private integer abilcode
private integer endTick
private unit u
private method periodic takes nothing returns nothing
if this.endTick == T32_Tick and u != null then
call UnitRemoveAbility( u, abilcode )
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes real duration, unit u, integer abilcode returns thistype
local thistype this = thistype.allocate()
set this.u = u
set this.abilcode = abilcode
set this.endTick = T32_Tick + R2I(duration / T32_PERIOD)
return this
endmethod
endstruct
struct RestoreManaTimed
private integer endTick
private unit source
private unit target
private real amount
private method periodic takes nothing returns nothing
local real start
local real maxResto
if this.endTick == T32_Tick and target != null then
call RestoreMana(source, target, amount)
set target = null
set source = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes real duration, unit source, unit target, real amount returns thistype
local thistype this = thistype.allocate()
set this.source = source
set this.target = target
set this.amount = amount
set this.endTick = T32_Tick + R2I(duration / T32_PERIOD)
return this
endmethod
endstruct
struct RepeatSpecialEffect
private string special
private real period
private integer nextTick
private integer endTick
private integer endDuration
private method periodic takes nothing returns nothing
if this.endTick == T32_Tick and special != null then
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes real duration, real period, string special returns thistype
local thistype this = thistype.allocate()
set this.special = special
set this.nextTick = T32_Tick + 2
set this.endTick = T32_Tick + R2I(duration + 1 / T32_PERIOD)
set this.endDuration = T32_Tick + R2I(duration + 1 / T32_PERIOD)
return this
endmethod
endstruct
struct ROUND_STATS
public static thistype instance
private integer startTick
private integer endTick
// these are global? also 100 -> [10][10]
private real array dmgDone[100]
private real array healDone[100]
private real array manaDone[100]
private method periodic takes nothing returns nothing
if (ModuloInteger(T32_Tick, 32) == 0) then
call ARENA_BOARD.update(this)
endif
endmethod
implement T32x
public method stop takes nothing returns nothing
set this.endTick = T32_Tick
call this.stopPeriodic()
//call this.destroy()
endmethod
public method setDmg takes real dmg, integer playerIndex returns nothing
set this.dmgDone[10 * udg_WaveIndex + playerIndex] = this.dmgDone[10 * udg_WaveIndex + playerIndex] + dmg
endmethod
public method getDmg takes integer playerIndex returns real
return this.dmgDone[10 * udg_WaveIndex + playerIndex]
endmethod
public method getDps takes integer waveIndex, integer playerIndex returns real
return this.dmgDone[10 * waveIndex + playerIndex] * 32 / (endTick - startTick)
endmethod
public method maxDpsIndex takes integer waveIndex returns integer
local integer i = 0
local real max = -1
local integer maxIndex = 0
loop
exitwhen i == 10
if (max < dmgDone[10 * waveIndex + i]) then
set max = dmgDone[10 * waveIndex + i]
set maxIndex = i
endif
set i = i + 1
endloop
return maxIndex
endmethod
public method getTime takes nothing returns integer
return (T32_Tick - startTick) / 32 + 1
endmethod
public static method registerRevive takes player caster, player target returns nothing
local integer prev = 0
if HaveSavedInteger(udg_ReviveStats, udg_WaveIndex, GetPlayerId(caster)) then
set prev = LoadInteger(udg_ReviveStats, udg_WaveIndex, GetPlayerId(caster))
call SaveInteger(udg_ReviveStats, udg_WaveIndex, GetPlayerId(caster), prev + 1)
else
call SaveInteger(udg_ReviveStats, udg_WaveIndex, GetPlayerId(caster), 1)
endif
endmethod
public static method maxRevives takes integer index returns integer
local integer count = 0
local integer i = 0
local integer max = 0
local integer maxIndex = -1
loop
exitwhen i == 10
if max < LoadInteger(udg_ReviveStats, index, i) then
set max = LoadInteger(udg_ReviveStats, index, i)
set maxIndex = i
endif
set i = i + 1
endloop
return maxIndex
endmethod
static method create takes nothing returns thistype
local thistype this = thistype.allocate()
set this.startTick = T32_Tick
return this
endmethod
endstruct
function Trig_NO_FRIENDLY_FIRE_Actions takes nothing returns nothing
if (udg_IsDamageAttack and IsPlayerAlly(GetOwningPlayer(udg_DamageEventSource), GetOwningPlayer(udg_DamageEventTarget))) then
set udg_DamageEventAmount = 0
endif
endfunction
//===========================================================================
function InitTrig_NO_FRIENDLY_FIRE takes nothing returns nothing
set gg_trg_NO_FRIENDLY_FIRE = CreateTrigger( )
call TriggerRegisterVariableEvent( gg_trg_NO_FRIENDLY_FIRE, "udg_PreDamageEvent", EQUAL, 1.00 )
call TriggerAddAction( gg_trg_NO_FRIENDLY_FIRE, function Trig_NO_FRIENDLY_FIRE_Actions )
endfunction
function Trig_GAMELOOP_Actions takes nothing returns nothing
local integer i
local unit u
local trigger onStun
local integer h
//main heroes stun
set i = 0
loop
exitwhen i > 10
set u = udg_MainHeroes[i]
if ( UnitHasBuffBJ(u, 'BUst') or UnitHasBuffBJ(u, 'BSTN') or UnitHasBuffBJ(u, 'BPSE') ) then
set h = GetHandleIdBJ(u)
set onStun = LoadTriggerHandleBJ(0, h, udg_NotifyRegistry)
if (onStun != null) then
set udg_OnStunHandleId = h
call TriggerExecute(onStun)
else
endif
else
endif
set i = i + 1
endloop
endfunction
//===========================================================================
function InitTrig_GAMELOOP takes nothing returns nothing
set gg_trg_GAMELOOP = CreateTrigger( )
// call TriggerRegisterTimerEventPeriodic( gg_trg_GAMELOOP, 0.10 )
call TriggerAddAction( gg_trg_GAMELOOP, function Trig_GAMELOOP_Actions )
endfunction
struct ArenaSpawns
private rect array regions[128]
private integer regionCount = 0
static method create takes nothing returns thistype
local thistype this = thistype.allocate()
return this
endmethod
public method push takes rect r returns nothing
set regions[regionCount] = r
set regionCount = regionCount + 1
endmethod
public method randomRect takes nothing returns rect
return regions[GetRandomInt(0, regionCount - 1)]
endmethod
endstruct
function ARENA_SPAWNS_CREATE takes nothing returns PlayableArea
local ArenaSpawns p = ArenaSpawns.create()
call p.push(gg_rct_SPAWN1)
call p.push(gg_rct_SPAWN2)
call p.push(gg_rct_SPAWN3)
call p.push(gg_rct_SPAWN4)
call p.push(gg_rct_SPAWN5)
call p.push(gg_rct_SPAWN6)
call p.push(gg_rct_SPAWN7)
call p.push(gg_rct_SPAWN8)
call p.push(gg_rct_SPAWN9)
return p
endfunction
function CAGE_SPAWNS_CREATE takes nothing returns PlayableArea
local ArenaSpawns p = ArenaSpawns.create()
call p.push(gg_rct_SPAWN1B)
call p.push(gg_rct_SPAWN2B)
call p.push(gg_rct_SPAWN3B)
call p.push(gg_rct_SPAWN4B)
call p.push(gg_rct_SPAWN5B)
call p.push(gg_rct_SPAWN6B)
return p
endfunction
struct Arena
public PlayableArea playableArea
public string name
public rect cameraBounds
public rect playerSpawn
public ArenaSpawns arenaSpawns
public string minimap
public boolean default
public static Arena MainArena
public static Arena CageArena
static method create takes nothing returns thistype
local thistype this = thistype.allocate()
return this
endmethod
static method init takes nothing returns nothing
set MainArena = create()
set MainArena.name = "Arena"
set MainArena.playableArea = ARENA_AREA_CREATE()
set MainArena.cameraBounds = gg_rct_BOUNDARENA
set MainArena.playerSpawn = gg_rct_ARENACENTER
set MainArena.arenaSpawns = ARENA_SPAWNS_CREATE()
set MainArena.minimap = "war3mapImported\\mainArena.blp"
set MainArena.default = true
set CageArena = create()
set CageArena.name = "|cff377683Cage Match|r"
set CageArena.playableArea = CAGE_AREA_CREATE()
set CageArena.cameraBounds = gg_rct_BOUND_CAGE
set CageArena.playerSpawn = gg_rct_CAGECENTER
set CageArena.arenaSpawns = CAGE_SPAWNS_CREATE()
set CageArena.minimap = "war3mapImported\\cageArena.blp"
set CageArena.default = false
endmethod
endstruct
function SetArenaBounds takes integer arena returns nothing
local Arena a = arena
//call SetCameraBoundsToRect(bj_mapInitialPlayableArea)
call SetCameraBoundsToRect(a.cameraBounds)
call switchCurrentPlayableArea(a.playableArea)
call BlzChangeMinimapTerrainTex(a.minimap)
endfunction
function Trig_Aggro_Save_Conditions takes nothing returns boolean
return GetOwningPlayer(udg_DamageEventTarget) == Player(23) and udg_DamageEventAmount > 0
endfunction
function Trig_Aggro_Save_Actions takes nothing returns nothing
local real multi = 1
if GetUnitAbilityLevel(udg_DamageEventSource, 'A034') > 0 then
set multi = 0.2
endif
call AddAggro(GetHandleId(udg_DamageEventTarget), udg_DamageEventSource, udg_DamageEventAmount * multi)
endfunction
//===========================================================================
function InitTrig_Aggro_Save takes nothing returns nothing
set gg_trg_Aggro_Save = CreateTrigger( )
call TriggerRegisterVariableEvent( gg_trg_Aggro_Save, "udg_OnDamageEvent", EQUAL, 1.00 )
call TriggerAddAction( gg_trg_Aggro_Save, function Trig_Aggro_Save_Actions )
call TriggerAddCondition( gg_trg_Aggro_Save, function Trig_Aggro_Save_Conditions )
endfunction
function Trig_ShowAggro_Each takes nothing returns nothing
local texttag tt = CreateTextTag()
local integer index = FindAggroUIndex(GetHandleId(GetEnumUnit()), udg_MainHeroes[GetPlayerId(udg_CurrentPlayerAggro)])
local real aggro = 0
if (index > 9) then
set aggro = LoadReal(udg_WaveBehaviorMap, GetHandleId(GetEnumUnit()), index + 1)
endif
call SetTextTagTextBJ(tt, R2S(aggro), 10)
call SetTextTagPosUnit(tt, GetEnumUnit(), 0)
call SetTextTagColor(tt, 0x1e, 0x90, 0xff, 0xdf)
call SetTextTagPermanent(tt, false)
call SetTextTagLifespan(tt, 0.8)
set tt = null
endfunction
function Trig_ShowAggro_Actions takes nothing returns nothing
local integer i = 0
loop
exitwhen i == 10
if GetLocalPlayer() == Player(i) and udg_AggroTextOn[i] then
set udg_CurrentPlayerAggro = Player(i)
call ForGroup(udg_CreepsInPlay, function Trig_ShowAggro_Each)
call ForGroup(udg_BossesInPlay, function Trig_ShowAggro_Each)
endif
set i = i + 1
endloop
endfunction
//===========================================================================
function InitTrig_ShowAggro takes nothing returns nothing
set gg_trg_ShowAggro = CreateTrigger( )
call DisableTrigger(gg_trg_ShowAggro)
call TriggerRegisterTimerEventPeriodic( gg_trg_ShowAggro, 0.8)
call TriggerAddAction( gg_trg_ShowAggro, function Trig_ShowAggro_Actions )
endfunction
function Trig_SFX_HINT_REVIVE_Highlight takes player p returns nothing
local integer i = 0
local unit dead
local effect se
local string path = "Abilities\\Spells\\Other\\Levelup\\LevelupCaster.mdl"
local texttag tt
set path = ""
if GetLocalPlayer() == p then
set path = "Abilities\\Spells\\Other\\Levelup\\LevelupCaster.mdl"
endif
loop
exitwhen i == 10
set dead = udg_MainHeroes[i]
if UnitDead(dead) and LoadUnitHandle(udg_UniqueEffectsMap, GetHandleId(dead), 'A00R') == null then
set se = AddSpecialEffect(path, GetUnitX(dead), GetUnitY(dead))
call DestroyEffect(se)
if GetLocalPlayer() == p then
set tt = CreateTextTag()
call SetTextTagTextBJ(tt, "Use No rest for the wicked to revive " + GetPlayerName(Player(i)), 10)
call SetTextTagPosUnit(tt, dead, 0)
call SetTextTagColor(tt, 0x32, 0xcd, 0x32, 0xdf)
call SetTextTagPermanent(tt, false)
call SetTextTagLifespan(tt, 2.0)
set tt = null
endif
endif
set i = i + 1
endloop
set dead = null
set se = null
endfunction
function Trig_SFX_HINT_REVIVE_Actions takes nothing returns nothing
local integer i = 0
local unit caster
loop
exitwhen i == 10
set caster = udg_MainHeroes[i]
if UnitAlive(caster) and (GetUnitAbilityLevel(caster, 'A00R') > 0 or GetUnitAbilityLevel(caster, 'A017') > 0) then
call Trig_SFX_HINT_REVIVE_Highlight(Player(i))
endif
set i = i + 1
endloop
set caster = null
endfunction
//===========================================================================
function InitTrig_SFX_HINT_REVIVE takes nothing returns nothing
set gg_trg_SFX_HINT_REVIVE = CreateTrigger( )
call TriggerRegisterTimerEventPeriodic( gg_trg_SFX_HINT_REVIVE, 2.00 )
call TriggerAddAction( gg_trg_SFX_HINT_REVIVE, function Trig_SFX_HINT_REVIVE_Actions )
endfunction
struct ARENA_BOARD
static method update takes integer roundStat returns nothing
local ROUND_STATS rs = roundStat
local integer row = 0
local integer i = 0
local integer count = CountPlayersInForceBJ(udg_HumanPlayers)
local integer time = rs.getTime()
local multiboarditem mbitem
local unit wicked = null
call MultiboardSetRowCount(udg_ArenaBoard, count + 3)
call MultiboardSetTitleText(udg_ArenaBoard, "Wave " + I2S(( udg_WaveIndex + 1 )))
//header
set mbitem = MultiboardGetItem(udg_ArenaBoard, row, 0)
call MultiboardSetItemStyle(mbitem, true, false)
call MultiboardSetItemValue(mbitem, "GLADIATOR")
call MultiboardSetItemWidth(mbitem, 0.12)
call MultiboardReleaseItem(mbitem)
set mbitem = MultiboardGetItem(udg_ArenaBoard, row, 1)
call MultiboardSetItemStyle(mbitem, true, false)
call MultiboardSetItemValue(mbitem, "STATUS")
call MultiboardSetItemWidth(mbitem, 0.05)
call MultiboardReleaseItem(mbitem)
set mbitem = MultiboardGetItem(udg_ArenaBoard, row, 2)
call MultiboardSetItemStyle(mbitem, true, false)
call MultiboardSetItemValue(mbitem, "DPS")
call MultiboardSetItemWidth(mbitem, 0.03)
call MultiboardReleaseItem(mbitem)
set row = row + 1
//stats
loop
exitwhen i == 10
if (IsPlayerInForce(Player(i), udg_HumanPlayers)) then
set mbitem = MultiboardGetItem(udg_ArenaBoard, row, 0)
call MultiboardSetItemStyle(mbitem, true, false)
call MultiboardSetItemValue(mbitem, udg_ColorPrefixes[(i)] + ( GetPlayerName(Player(i)) + "|r" ))
call MultiboardSetItemWidth(mbitem, 0.12)
call MultiboardReleaseItem(mbitem)
set mbitem = MultiboardGetItem(udg_ArenaBoard, row, 1)
call MultiboardSetItemStyle(mbitem, true, false)
if (UnitAlive(udg_MainHeroes[i])) then
call MultiboardSetItemValue(mbitem, "Alive")
else
set wicked = LoadUnitHandleBJ('A00R', GetHandleId(udg_MainHeroes[i]) , udg_UniqueEffectsMap)
if (wicked != null) then
call MultiboardSetItemValue(mbitem, "Raised")
else
call MultiboardSetItemValue(mbitem, "|cffe01010Resting|r")
endif
endif
call MultiboardSetItemWidth(mbitem, 0.05)
call MultiboardReleaseItem(mbitem)
set mbitem = MultiboardGetItem(udg_ArenaBoard, row, 2)
call MultiboardSetItemStyle(mbitem, true, false)
call MultiboardSetItemValue(mbitem, I2S(MathRound((ROUND_STATS.instance.getDmg(i) / time))))
call MultiboardSetItemWidth(mbitem, 0.03)
call MultiboardReleaseItem(mbitem)
set row = row + 1
endif
set i = i + 1
endloop
//empty row
set mbitem = MultiboardGetItem(udg_ArenaBoard, row, 0)
call MultiboardSetItemStyle(mbitem, true, false)
call MultiboardSetItemValue(mbitem, "")
call MultiboardSetItemWidth(mbitem, 0.2)
call MultiboardReleaseItem(mbitem)
set mbitem = MultiboardGetItem(udg_ArenaBoard, row, 1)
call MultiboardSetItemStyle(mbitem, true, false)
call MultiboardSetItemValue(mbitem, "")
call MultiboardSetItemWidth(mbitem, 0)
call MultiboardReleaseItem(mbitem)
set mbitem = MultiboardGetItem(udg_ArenaBoard, row, 2)
call MultiboardSetItemStyle(mbitem, true, false)
call MultiboardSetItemValue(mbitem, "")
call MultiboardSetItemWidth(mbitem, 0)
call MultiboardReleaseItem(mbitem)
set row = row + 1
//timer
set mbitem = MultiboardGetItem(udg_ArenaBoard, row,0)
call MultiboardSetItemStyle(mbitem, true, false)
call MultiboardSetItemValue(mbitem, "Timer: " + I2S(time))
call MultiboardSetItemWidth(mbitem, 0.2)
call MultiboardReleaseItem(mbitem)
set mbitem = MultiboardGetItem(udg_ArenaBoard, row,1)
call MultiboardSetItemStyle(mbitem, true, false)
call MultiboardSetItemValue(mbitem, "")
call MultiboardSetItemWidth(mbitem, 0)
call MultiboardReleaseItem(mbitem)
set mbitem = MultiboardGetItem(udg_ArenaBoard, row,2)
call MultiboardSetItemStyle(mbitem, true, false)
call MultiboardSetItemValue(mbitem, "")
call MultiboardSetItemWidth(mbitem, 0)
call MultiboardReleaseItem(mbitem)
set mbitem = null
endmethod
static method createBoard takes nothing returns nothing
set udg_ArenaBoard = CreateMultiboard()
call MultiboardSetRowCount(udg_ArenaBoard, 1)
call MultiboardSetColumnCount(udg_ArenaBoard, 3)
call MultiboardSetTitleText(udg_ArenaBoard, "TRIGSTR_973")
call MultiboardSetTitleTextColorBJ(udg_ArenaBoard, 100, 80, 20, 0 )
call thistype.update(ROUND_STATS.instance)
call MultiboardDisplay(udg_ArenaBoard, true)
endmethod
endstruct
function gtEqThanAll takes integer theOne, integer other1, integer other2, integer other3 returns boolean
return theOne >= other1 and theOne >= other2 and theOne >= other3
endfunction
function getTopVote takes nothing returns integer
local integer count1 = 0
local integer count2 = 0
local integer count3 = 0
local integer count4 = 0
local integer i = 0
local integer variantIndex = 0
local integer c = 0
local Wave w = udg_Waves[udg_WaveIndex]
loop
exitwhen i == 10
set c = WAVE_SELECTION_BOARD.votes[i]
set WAVE_SELECTION_BOARD.votes[i] = 0
if (c == 1) then
set count1 = count1 + udg_VoteWeight
elseif (c == 2) then
set count2 = count2 + udg_VoteWeight
elseif (c == 3) then
set count3 = count3 + udg_VoteWeight
elseif (c == 4) then
set count4 = count4 + udg_VoteWeight
endif
set i = i + 1
endloop
loop
exitwhen i == 20
set c = WAVE_SELECTION_BOARD.votes[i]
set WAVE_SELECTION_BOARD.votes[i] = 0
if (c == 1) then
set count1 = count1 + 1
elseif (c == 2) then
set count2 = count2 + 1
elseif (c == 3) then
set count3 = count3 + 1
elseif (c == 4) then
set count4 = count4 + 1
endif
set i = i + 1
endloop
//max
if (gtEqThanAll(count1, count2, count3, count4)) then
return 0
elseif (gtEqThanAll(count2, count1, count3, count4)) then
return 1
elseif (gtEqThanAll(count3, count2, count1, count4)) then
return 2
else
return 3
endif
endfunction
function Trig_NEXT_ARENA_loop_nested takes nothing returns nothing
local location l
local WaveVariant v = udg_Variant
local Arena a = v.arena
if (IsUnitType(GetEnumUnit(), UNIT_TYPE_STRUCTURE) == false) then
set l = GetRandomLocInRect(a.playerSpawn)
call SetUnitPositionLoc( GetEnumUnit(), l)
call AddSpecialEffectLocBJ( l, "Abilities\\Spells\\Human\\MassTeleport\\MassTeleportCaster.mdl" )
call DestroyEffect( GetLastCreatedEffectBJ() )
call PanCameraToTimedLocForPlayer( GetEnumPlayer(), l, 0.00 )
call RemoveLocation(l)
set l = null
endif
if (IsUnitType(GetEnumUnit(), UNIT_TYPE_HERO)) then
call GroupAddUnit(udg_GladiatorsInPlay, GetEnumUnit())
call GroupAddUnit(udg_Gladiators, GetEnumUnit())
endif
endfunction
function Trig_NEXT_ARENA_loop takes nothing returns nothing
set bj_wantDestroyGroup = true
call ForGroupBJ(GetUnitsOfPlayerAll(GetEnumPlayer()), function Trig_NEXT_ARENA_loop_nested)
endfunction
function Trig_NEXT_ARENA_Actions takes nothing returns nothing
local Wave w = udg_Waves[udg_WaveIndex]
local WaveVariant v = w.variants[getTopVote()]
set udg_Wave = w
set udg_Variant = v
set udg_PHASE = 2
call SetArenaBounds(v.arena)
set udg_DifficultyChangeEnabled = false
call ForForce(udg_HumanPlayers, function Trig_NEXT_ARENA_loop)
call QuestSetCompleted(udg_QuestDiff, true)
set ROUND_STATS.instance = ROUND_STATS.create()
call ROUND_STATS.instance.startPeriodic()
call ARENA_BOARD.createBoard()
call WAVE_SELECTION_BOARD.clearBoard()
call TriggerExecute( gg_trg_PRESEND )
endfunction
//===========================================================================
function InitTrig_NEXT_ARENA takes nothing returns nothing
set gg_trg_NEXT_ARENA = CreateTrigger( )
call TriggerAddAction( gg_trg_NEXT_ARENA, function Trig_NEXT_ARENA_Actions )
endfunction
function Trig_PRESEND_Actions takes nothing returns nothing
local integer sum = 0
local integer i = 0
local WaveVariant v = udg_Variant
loop
exitwhen i == v.preTriggerSize
call EnableTrigger( v.preTriggers[i] )
set i = i + 1
endloop
set i = 0
call TriggerExecute( gg_trg_SCALEWAVE )
loop
exitwhen i == v.compositionSize
set sum = sum + v.creepsNumber[i]
set i = i + 1
endloop
set udg_TotalInWave = sum
set udg_AMOVE_SIZE = IMaxBJ(sum / 12 + 1, udg_PlayerCount) //12 units per group max but at least nplayer group
//call DisplayTextToForce( bj_FORCE_PLAYER[0], ( "|cff00ff00DEBUG - total in wave " + I2S(udg_TotalInWave) ) )
set udg_TotalSent = 0
call EnableTrigger( gg_trg_SENDWAVE )
call EnableTrigger( gg_trg_CREEP_DIE )
endfunction
//===========================================================================
function InitTrig_PRESEND takes nothing returns nothing
set gg_trg_PRESEND = CreateTrigger( )
call TriggerAddAction( gg_trg_PRESEND, function Trig_PRESEND_Actions )
endfunction
function Trig_SCALEWAVE_Actions takes nothing returns nothing
local integer i = 0
local integer count = udg_PlayerCount
local WaveVariant v
if (count >= 5) then
set udg_BossHealthMultiplier = 0.2 * count
else
// 0.30 0.45 0.70 0.85
set udg_BossHealthMultiplier = 0.15 + 0.15 * count
endif
if (count >= 5) then
set udg_BossPowerMultiplier = 1 + count * 0.05
else
set udg_BossPowerMultiplier = 0.5 + count * 0.1
endif
set udg_BossPowerMultiplier = udg_BossPowerMultiplier * Difficulty.current.bossAttribute
set v = udg_Variant
loop
exitwhen i == v.compositionSize
set v.creepsNumber[i] = v.creepsNumber[i] * count
set i = i + 1
endloop
endfunction
//===========================================================================
function InitTrig_SCALEWAVE takes nothing returns nothing
set gg_trg_SCALEWAVE = CreateTrigger( )
call TriggerAddAction( gg_trg_SCALEWAVE, function Trig_SCALEWAVE_Actions )
endfunction
function Trig_SENDWAVE_Conditions takes nothing returns boolean
return udg_TotalSent <= udg_TotalInWave and BlzGroupGetSize(udg_CreepsInPlay) < 65
endfunction
function Trig_SENDWAVE_getBucketOrNext takes integer bucketIndex, integer waveVariant returns integer
local WaveVariant v = waveVariant
local integer i = bucketIndex
local integer bucketSize = v.creepsNumber[i]
loop
exitwhen bucketSize > 0
set i = ModuloInteger(i + 1, v.compositionSize)
set bucketSize = v.creepsNumber[i]
endloop
return i
endfunction
function RegisterCreep takes unit u returns nothing
call GroupAddUnit(udg_CreepsInPlay, u)
call GroupAddUnit(udg_AMOVE_GROUPS[ModuloInteger(udg_AMOVE_INDEX, udg_AMOVE_SIZE)], u)
set udg_AMOVE_INDEX = udg_AMOVE_INDEX + 1
set udg_UnitSpawned = u
set udg_OnUnitSpawn = 0.00
set udg_OnUnitSpawn = 1.00
endfunction
function MoveCreepToG20 takes unit u returns nothing
local integer i = 0
call GroupAddUnit(udg_AMOVE_GROUPS[20], u)
loop
exitwhen i == 20
call GroupRemoveUnit(udg_AMOVE_GROUPS[i], u)
set i = i + 1
endloop
endfunction
function Trig_SENDWAVE_Actions takes nothing returns nothing
local integer toSend = 0
local integer i = 0
local integer bucketIndex = 0
local integer bucketSize = 0
local rect reg
local location pspawn
local unit u
local WaveVariant v = udg_Variant
local Arena a = v.arena
set toSend = IMinBJ(v.spawnSize, udg_TotalInWave - udg_TotalSent)
set udg_TotalSent = udg_TotalSent + toSend
loop
exitwhen i == toSend
set reg = a.arenaSpawns.randomRect()
set bucketIndex = Trig_SENDWAVE_getBucketOrNext(GetRandomInt(0, v.compositionSize - 1), v)
set bucketSize = v.creepsNumber[bucketIndex]
set pspawn = GetRandomLocInRect(reg)
set u = CreateUnitAtLoc(Player(23), v.creepType[bucketIndex], pspawn, bj_UNIT_FACING)
call AddSpecialEffectLocBJ( pspawn , "Objects\\Spawnmodels\\Undead\\ImpaleTargetDust\\ImpaleTargetDust.mdl" )
call DestroyEffect( GetLastCreatedEffectBJ() )
call BlzSetUnitMaxHP(u, MathRound(BlzGetUnitMaxHP(u) * Difficulty.current.creepHealth))
call SetUnitState(u, UNIT_STATE_LIFE, GetUnitState(u, UNIT_STATE_MAX_LIFE))
call BlzSetUnitBaseDamage(u, MathRound(BlzGetUnitBaseDamage(u, 0) * Difficulty.current.creepDmg), 0)
//call IssuePointOrderLoc(u, "attack", pamove )
call SaveInteger(udg_WaveBehaviorMap, GetHandleId(u), 9, 0) // empty aggro
call SaveInteger(udg_WaveBehaviorMap, GetHandleId(u), 0, 1) // default behaviour
call SaveInteger(udg_UnitRewardMap, GetHandleId(u), 0, v.waveRewardExp / (udg_TotalInWave + 1)) // todo bosscount
call SaveInteger(udg_UnitRewardMap, GetHandleId(u), 1, v.waveRewardGold / (udg_TotalInWave + 1))
call RegisterCreep(u)
set v.creepsNumber[bucketIndex] = bucketSize - 1
call RemoveLocation (pspawn)
set i = i + 1
endloop
if ( udg_TotalSent == udg_TotalInWave ) then
call EnableTrigger( gg_trg_SENDBOSS )
call DisableTrigger( GetTriggeringTrigger() )
endif
set u = null
set pspawn = null
endfunction
//===========================================================================
function InitTrig_SENDWAVE takes nothing returns nothing
set gg_trg_SENDWAVE = CreateTrigger( )
call DisableTrigger( gg_trg_SENDWAVE )
call TriggerRegisterTimerEventPeriodic( gg_trg_SENDWAVE, 1.75 )
call TriggerAddCondition( gg_trg_SENDWAVE, Condition( function Trig_SENDWAVE_Conditions ) )
call TriggerAddAction( gg_trg_SENDWAVE, function Trig_SENDWAVE_Actions )
endfunction
function Trig_SENDBOSS_Actions takes nothing returns nothing
local integer triggerIndex = 0
local integer stat
local rect reg
local location pamove
local location lh
local unit h
local WaveVariant v = udg_Variant
local Arena a = v.arena
local integer bossType
set bossType = v.bossType
if v.bossTypeHard != 0 and Difficulty.level > 2 then
set bossType = v.bossTypeHard
endif
if (bossType != null) then
set reg = a.arenaSpawns.randomRect()
set lh = GetRandomLocInRect(reg)
set h = CreateUnitAtLoc(Player(23), bossType, lh, bj_UNIT_FACING)
set stat = v.str
if stat == 0 then
set stat = GetHeroStr(h, false)
endif
call SetHeroStr(h, MathRound(stat * udg_BossPowerMultiplier), true)
set stat = v.agi
if stat == 0 then
set stat = GetHeroAgi(h, false)
endif
call SetHeroAgi(h, MathRound(stat * udg_BossPowerMultiplier), true)
set stat = v.int
if stat == 0 then
set stat = GetHeroInt(h, false)
endif
call SetHeroInt(h, MathRound(stat * udg_BossPowerMultiplier), true)
if udg_WaveIndex + 1 > 1 then
call SetHeroLevel(h, udg_WaveIndex + 1, false)
endif
call BlzSetUnitMaxHP(h, MathRound(BlzGetUnitMaxHP(h) * udg_BossHealthMultiplier))
call SetUnitLifePercentBJ(h, 100)
call SetUnitManaPercentBJ(h, 100)
call AddSpecialEffectLocBJ( lh , "Objects\\Spawnmodels\\Undead\\ImpaleTargetDust\\ImpaleTargetDust.mdl" )
call DestroyEffect( GetLastCreatedEffectBJ() )
set pamove = GetRectCenter(gg_rct_ARENACENTER)
call IssuePointOrderLoc(h, "attack", pamove)
call GroupAddUnit(udg_BossesInPlay, h)
call SaveInteger(udg_UnitRewardMap, GetHandleId(h), 0, v.waveRewardExp / (udg_TotalInWave + 1)) // todo bosscount
call SaveInteger(udg_UnitRewardMap, GetHandleId(h), 1, v.waveRewardGold / (udg_TotalInWave + 1))
loop
exitwhen triggerIndex == v.bossTriggerSize
call EnableTrigger( v.bossTriggers[triggerIndex] )
set triggerIndex = triggerIndex + 1
endloop
set h = null
call RemoveLocation (lh)
call RemoveLocation (pamove)
set lh = null
set pamove = null
endif
call DisableTrigger(GetTriggeringTrigger())
endfunction
//===========================================================================
function InitTrig_SENDBOSS takes nothing returns nothing
set gg_trg_SENDBOSS = CreateTrigger( )
call DisableTrigger( gg_trg_SENDBOSS )
call TriggerRegisterTimerEventPeriodic( gg_trg_SENDBOSS, 1.75 )
call TriggerAddAction( gg_trg_SENDBOSS, function Trig_SENDBOSS_Actions )
endfunction
function Trig_CREEP_DIE_REWARD takes nothing returns nothing
local integer k = GetHandleId(GetDyingUnit())
if not HaveSavedInteger(udg_UnitRewardMap, k, 0) then
return
endif
call AddHeroXP(udg_MainHeroes[GetPlayerId(GetEnumPlayer())], LoadInteger(udg_UnitRewardMap, k, 0), true)
call SetPlayerState(GetEnumPlayer(), PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(GetEnumPlayer(), PLAYER_STATE_RESOURCE_GOLD) + LoadInteger(udg_UnitRewardMap, k, 1))
endfunction
function Trig_CREEP_DIE_REMAINDER takes nothing returns nothing
local integer percreep
local integer remainder
local integer total = udg_TotalInWave + 1 // bosscount todo
local WaveVariant v = udg_Variant
set percreep = v.waveRewardExp / total
set remainder = v.waveRewardExp - percreep * total
call AddHeroXP(udg_MainHeroes[GetPlayerId(GetEnumPlayer())], remainder, true)
set percreep = v.waveRewardGold / total
set remainder = v.waveRewardGold - percreep * total
call SetPlayerState(GetEnumPlayer(), PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(GetEnumPlayer(), PLAYER_STATE_RESOURCE_GOLD) + remainder)
endfunction
function Trig_CREEP_DIE_Conditions takes nothing returns boolean
return IsUnitInGroup(GetDyingUnit(), udg_CreepsInPlay) or IsUnitInGroup(GetDyingUnit(), udg_BossesInPlay)
endfunction
function Trig_CREEP_DIE_Actions takes nothing returns nothing
local integer triggerIndex = 0
local integer i = 0
local WaveVariant v = udg_Variant
call FlushChildHashtable(udg_WaveBehaviorMap, GetHandleId(GetDyingUnit()))
if (IsUnitInGroup(GetDyingUnit(), udg_CreepsInPlay)) then
call GroupRemoveUnit(udg_CreepsInPlay, GetDyingUnit())
endif
call ForForce(udg_HumanPlayers, function Trig_CREEP_DIE_REWARD)
call FlushChildHashtable(udg_UnitRewardMap, GetHandleId(GetDyingUnit()))
if (IsUnitGroupDeadBJ(udg_CreepsInPlay) and IsUnitGroupDeadBJ(udg_BossesInPlay)) then
call ForForce(udg_HumanPlayers, function Trig_CREEP_DIE_REMAINDER)
loop
exitwhen i == udg_AMOVE_SIZE
call GroupClear(udg_AMOVE_GROUPS[i])
set i = i + 1
endloop
call GroupClear(udg_AMOVE_GROUPS[20]) //special could have been used
set i = 0
loop
exitwhen i == v.bossTriggerSize
call DisableTrigger(v.bossTriggers[i])
set i = i + 1
endloop
set i = 0
loop
exitwhen i == v.preTriggerSize
call EnableTrigger( v.preTriggers[i] )
set i = i + 1
endloop
call DisableTrigger(GetTriggeringTrigger())
call TriggerExecute(gg_trg_ENDWAVE)
endif
endfunction
//===========================================================================
function InitTrig_CREEP_DIE takes nothing returns nothing
set gg_trg_CREEP_DIE = CreateTrigger( )
call DisableTrigger( gg_trg_CREEP_DIE )
call TriggerRegisterPlayerUnitEventSimple( gg_trg_CREEP_DIE, Player(23), EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_CREEP_DIE, Condition( function Trig_CREEP_DIE_Conditions ) )
call TriggerAddAction( gg_trg_CREEP_DIE, function Trig_CREEP_DIE_Actions )
endfunction
function Trig_AMOVE_LOOP_choose_target takes nothing returns unit
return GroupPickRandomUnit(udg_GladiatorsInPlay)
endfunction
// 0 behaviour
// 1 target
// 2-8 reserved
// 9 aggro size
// 10+ aggro
function Trig_AMOVE_LOOP_each takes nothing returns nothing
//TODO command whole groups
local unit u = GetEnumUnit()
local integer behavior
local unit target
local location tl
local integer i = 0
local integer key = GetHandleId(u)
if (HaveSavedInteger(udg_WaveBehaviorMap, key, 0) == false) then
call SaveIntegerBJ(1, 0, key, udg_WaveBehaviorMap) //default behavior
set target = Trig_AMOVE_LOOP_choose_target()
call SaveUnitHandleBJ(target, 1, key, udg_WaveBehaviorMap)
endif
set target = LoadUnitHandleBJ(1, key, udg_WaveBehaviorMap)
if (UnitDead(target)) then
set target = Trig_AMOVE_LOOP_choose_target()
call SaveUnitHandleBJ(target, 1, key, udg_WaveBehaviorMap)
endif
set tl = GetUnitLoc(target)
call IssuePointOrderLoc(u, "attack", tl)
call RemoveLocation (tl)
set tl = null
set target = null
set u = null
endfunction
function Trig_AMOVE_LOOP_BOSS_Actions takes nothing returns nothing
call ForGroup(udg_BossesInPlay, function Trig_AMOVE_LOOP_each)
endfunction
//===========================================================================
function InitTrig_AMOVE_LOOP_BOSS takes nothing returns nothing
set gg_trg_AMOVE_LOOP_BOSS = CreateTrigger( )
call TriggerRegisterTimerEventPeriodic( gg_trg_AMOVE_LOOP_BOSS, 1.25 )
call TriggerAddAction( gg_trg_AMOVE_LOOP_BOSS, function Trig_AMOVE_LOOP_BOSS_Actions )
endfunction
function Trig_AMOVE_LOOP_CREEPS_Actions takes nothing returns nothing
local integer i = 0
local group g
local integer k
local unit target
loop
exitwhen i == udg_AMOVE_SIZE
//call BJDebugMsg(I2S(i))
set g = udg_AMOVE_GROUPS[i]
set k = GetHandleId(g)
if (HaveSavedHandle(udg_WaveBehaviorMap, k, 1) == false) then
//call SaveIntegerBJ(1, 0, key, udg_WaveBehaviorMap) //default behavior // not supported anymore
set target = Trig_AMOVE_LOOP_choose_target()
call SaveUnitHandle(udg_WaveBehaviorMap, k, 1, target)
endif
set target = LoadUnitHandle(udg_WaveBehaviorMap, k, 1)
if (UnitDead(target)) then
set target = Trig_AMOVE_LOOP_choose_target()
call SaveUnitHandle(udg_WaveBehaviorMap, k, 1, target)
endif
//call GroupPointOrderLoc(g, "attack", GetUnitLoc(target))
call GroupPointOrder(g, "attack", GetUnitX(target), GetUnitY(target))
set target = null
set i = i + 1
endloop
set target = null
endfunction
//===========================================================================
function InitTrig_AMOVE_LOOP_CREEPS takes nothing returns nothing
set gg_trg_AMOVE_LOOP_CREEPS = CreateTrigger( )
call TriggerRegisterTimerEventPeriodic( gg_trg_AMOVE_LOOP_CREEPS, 1.25 )
call TriggerAddAction( gg_trg_AMOVE_LOOP_CREEPS, function Trig_AMOVE_LOOP_CREEPS_Actions )
endfunction
struct AttackLoopUnits
private integer nextTick
private integer nextBoss
private integer gindex
public static thistype instance
static method randomTarget takes nothing returns unit
return GroupPickRandomUnit(udg_GladiatorsInPlay)
endmethod
static method each takes nothing returns nothing
local group g = CreateGroup()
local unit u = GetEnumUnit()
local unit gu
local unit umax = null
local real max = -1
local integer index = -1
local player p = GetOwningPlayer(GetEnumUnit())
local integer k = GetHandleId(GetEnumUnit())
local integer count
local real prev
local integer i = 0
// attack max aggrp
call GroupEnumUnitsInRange(g, GetUnitX(u), GetUnitY(u), 500, function True_Filter)
loop
set gu = FirstOfGroup(g)
exitwhen gu == null
call GroupRemoveUnit(g, gu)
if (IsUnitEnemy(gu, p) and UnitAlive(gu) and GetUnitAbilityLevel(gu,'Avul') < 1 ) then
set index = FindAggroUIndex(k, gu)
if index > 9 then
if max < LoadReal(udg_WaveBehaviorMap, k, index + 1) then
set max = LoadReal(udg_WaveBehaviorMap, k, index + 1)
set umax = gu
endif
endif
endif
endloop
//call BJDebugMsg(R2S(max))
if umax != null then
call IssueTargetOrder(u, "attack", umax)
else
//fallback
set umax = randomTarget()
call IssuePointOrder(u, "attack", GetUnitX(umax), GetUnitY(umax))
endif
call DestroyGroup(g)
// decrease aggro
set count = LoadInteger(udg_WaveBehaviorMap, k, 9)
loop
exitwhen i == count
set prev = LoadReal(udg_WaveBehaviorMap, k, 10 + i * 2 + 1)
call SaveReal(udg_WaveBehaviorMap, k, 10 + i * 2 + 1, RMaxBJ(0, prev - 50))
set i = i + 1
endloop
set g = null
set u = null
set gu = null
set umax = null
endmethod
public method start takes nothing returns nothing
set nextTick = T32_Tick + 2
set nextBoss = nextTick
set gindex = 0
call this.startPeriodic()
endmethod
private method periodic takes nothing returns nothing
local integer i = 0
local group g
local integer k
local unit target
if T32_Tick == nextTick then
set nextTick = nextTick + 60 / udg_AMOVE_SIZE + 4
//call BJDebugMsg("group")
set g = udg_AMOVE_GROUPS[ModuloInteger(gindex, udg_AMOVE_SIZE)]
call ForGroup(g, function thistype.each)
set gindex = gindex + 1
set target = null
set g = null
endif
if T32_Tick == nextBoss then
set nextBoss = nextBoss + 64
call ForGroup(udg_BossesInPlay, function thistype.each)
endif
endmethod
implement T32x
static method create takes nothing returns thistype
local thistype this = thistype.allocate()
return this
endmethod
endstruct
function Trig_ENDWAVE_ClearBosses takes nothing returns nothing
call GroupRemoveUnit(udg_BossesInPlay, GetEnumUnit())
call RemoveUnit(GetEnumUnit())
endfunction
function Trig_ENDWAVE_Actions takes nothing returns nothing
local WaveVariant v = udg_Variant
local integer i = 0
call ROUND_STATS.instance.stop()
loop
exitwhen i == v.bossTriggerSize
call DisableTrigger( v.bossTriggers[i] )
set i = i + 1
endloop
call TriggerSleepAction( 2 )
call TriggerExecute( gg_trg_REVIVEPLAYERS )
call TriggerSleepAction( 2 )
call MultiboardDisplay(udg_ArenaBoard, false)
call MultiboardClear(udg_ArenaBoard)
set udg_ALL_ROUND_STATS[udg_WaveIndex] = ROUND_STATS.instance
if ( udg_WaveIndex == udg_LastWaveIndex ) then
call ConditionalTriggerExecute( gg_trg_VICTORY )
else
set udg_WaveIndex = udg_WaveIndex + 1
call ConditionalTriggerExecute( gg_trg_NEXT_HUB )
call ForGroup(udg_BossesInPlay, function Trig_ENDWAVE_ClearBosses)
endif
endfunction
//===========================================================================
function InitTrig_ENDWAVE takes nothing returns nothing
set gg_trg_ENDWAVE = CreateTrigger( )
call TriggerAddAction( gg_trg_ENDWAVE, function Trig_ENDWAVE_Actions )
endfunction
function Trig_REVIVEPLAYERS_Actions takes nothing returns nothing
local integer i
local unit u
local unit wicked
local integer key
local location l
local location lw
set i = 0
loop
exitwhen i == 10
set u = udg_MainHeroes[i]
if ( u != null ) then
//remove wicked
set key = GetHandleId(u)
set wicked = LoadUnitHandleBJ('A00R', key, udg_UniqueEffectsMap)
if (wicked != null) then
call SaveUnitHandleBJ(null, 'A00R', key, udg_UniqueEffectsMap)
set lw = GetUnitLoc(wicked)
call AddSpecialEffectLocBJ( lw, "Objects\\Spawnmodels\\Undead\\UndeadDissipate\\UndeadDissipate.mdl" )
call DestroyEffect(GetLastCreatedEffectBJ())
call RemoveUnit(wicked)
call RemoveLocation(lw)
set wicked = null
endif
// revive hero
set l = GetUnitLoc(u)
call ReviveHeroLoc( u, l, true )
call RemoveLocation (l)
call GroupAddUnit(udg_GladiatorsInPlay, u)
endif
set i = i + 1
endloop
set u = null
set wicked = null
set l = null
set lw = null
endfunction
//===========================================================================
function InitTrig_REVIVEPLAYERS takes nothing returns nothing
set gg_trg_REVIVEPLAYERS = CreateTrigger( )
call TriggerAddAction( gg_trg_REVIVEPLAYERS, function Trig_REVIVEPLAYERS_Actions )
endfunction
struct VotePrompts
private static integer sizeV = 0
private static integer sizeD = 0
private static string array vote
private static string array dissent
static method create takes nothing returns thistype
local thistype this = thistype.allocate()
return this
endmethod
static method pushPrompt takes string s returns nothing
set vote[sizeV] = s
set sizeV = sizeV + 1
endmethod
static method pushDissentPrompt takes string s returns nothing
set dissent[sizeD] = s
set sizeD = sizeD + 1
endmethod
static method random takes nothing returns string
return vote[GetRandomInt(0, sizeV - 1)]
endmethod
static method randomDissent takes nothing returns string
return dissent[GetRandomInt(0, sizeD - 1)]
endmethod
endstruct
function Trig_InitExtraCharacters_Actions takes nothing returns nothing
set udg_ExtraCharacters[19] = gg_unit_u009_0026
set udg_ExtraCharacters[18] = gg_unit_u00G_0030
call VotePrompts.pushPrompt("I plan to vote for ")
call VotePrompts.pushPrompt("My vote will go to ")
call VotePrompts.pushPrompt("I intend to vote for ")
call VotePrompts.pushPrompt("I'll be voting for ")
call VotePrompts.pushPrompt("I will vote for ")
call VotePrompts.pushPrompt("I've decided to vote for ")
call VotePrompts.pushPrompt("I'm gonna vote for ")
call VotePrompts.pushPrompt("My vote goes to ")
call VotePrompts.pushPrompt("My choice is ")
call VotePrompts.pushPrompt("My pick is ")
call VotePrompts.pushPrompt("I'm going with ")
call VotePrompts.pushPrompt("I'm choosing ")
call VotePrompts.pushPrompt("My favorite is ")
call VotePrompts.pushPrompt("I'm opting for ")
call VotePrompts.pushPrompt("I'm selecting ")
call VotePrompts.pushPrompt("Let's do ")
call VotePrompts.pushPrompt("It's time for ")
call VotePrompts.pushPrompt("Let's vote for ")
call VotePrompts.pushPrompt("Let's pick ")
call VotePrompts.pushPrompt("Please, let's do ")
call VotePrompts.pushDissentPrompt("That's lame. ")
call VotePrompts.pushDissentPrompt("I'm opposed to that. ")
call VotePrompts.pushDissentPrompt("I don't think that's a good idea. ")
call VotePrompts.pushDissentPrompt("I have concerns about that choice... ")
call VotePrompts.pushDissentPrompt("No. ")
call VotePrompts.pushDissentPrompt("Nah. ")
call VotePrompts.pushDissentPrompt("I'm not for that. ")
call VotePrompts.pushDissentPrompt("I hate that wave. ")
call VotePrompts.pushDissentPrompt("Nah, let's do another wave instead. ")
endfunction
//===========================================================================
function InitTrig_InitExtraCharacters takes nothing returns nothing
set gg_trg_InitExtraCharacters = CreateTrigger( )
call TriggerAddAction( gg_trg_InitExtraCharacters, function Trig_InitExtraCharacters_Actions )
endfunction
function Trig_CREATE_VOTING_ALTARS_Actions takes nothing returns nothing
local integer i = 0
local location l
set l = GetUnitLoc(gg_unit_n003_0019)
loop
exitwhen i == 10
if (udg_HeroPicked[i]) then
set udg_VotingAltars[i] = CreateUnitAtLoc(Player(i), 'n006', l, bj_UNIT_FACING )
endif
set i = i + 1
endloop
call RemoveLocation(l)
set l = null
endfunction
//===========================================================================
function InitTrig_CREATE_VOTING_ALTARS takes nothing returns nothing
set gg_trg_CREATE_VOTING_ALTARS = CreateTrigger( )
call TriggerAddAction( gg_trg_CREATE_VOTING_ALTARS, function Trig_CREATE_VOTING_ALTARS_Actions )
endfunction
function Trig_VOTING_ALTAR_HELPER_CLICK_Conditions takes nothing returns boolean
return GetTriggerUnit() == gg_unit_n003_0019
endfunction
function Trig_VOTING_ALTAR_HELPER_CLICK_Actions takes nothing returns nothing
local player p = GetTriggerPlayer()
call SelectUnitForPlayerSingle( udg_VotingAltars[GetPlayerId(p)], p )
endfunction
//===========================================================================
function InitTrig_VOTING_ALTAR_HELPER_CLICK takes nothing returns nothing
set gg_trg_VOTING_ALTAR_HELPER_CLICK = CreateTrigger( )
call TriggerRegisterPlayerSelectionEventBJ( gg_trg_VOTING_ALTAR_HELPER_CLICK, Player(0), true )
call TriggerRegisterPlayerSelectionEventBJ( gg_trg_VOTING_ALTAR_HELPER_CLICK, Player(1), true )
call TriggerRegisterPlayerSelectionEventBJ( gg_trg_VOTING_ALTAR_HELPER_CLICK, Player(2), true )
call TriggerRegisterPlayerSelectionEventBJ( gg_trg_VOTING_ALTAR_HELPER_CLICK, Player(3), true )
call TriggerRegisterPlayerSelectionEventBJ( gg_trg_VOTING_ALTAR_HELPER_CLICK, Player(4), true )
call TriggerRegisterPlayerSelectionEventBJ( gg_trg_VOTING_ALTAR_HELPER_CLICK, Player(5), true )
call TriggerRegisterPlayerSelectionEventBJ( gg_trg_VOTING_ALTAR_HELPER_CLICK, Player(6), true )
call TriggerRegisterPlayerSelectionEventBJ( gg_trg_VOTING_ALTAR_HELPER_CLICK, Player(7), true )
call TriggerRegisterPlayerSelectionEventBJ( gg_trg_VOTING_ALTAR_HELPER_CLICK, Player(8), true )
call TriggerRegisterPlayerSelectionEventBJ( gg_trg_VOTING_ALTAR_HELPER_CLICK, Player(9), true )
call TriggerAddCondition( gg_trg_VOTING_ALTAR_HELPER_CLICK, Condition( function Trig_VOTING_ALTAR_HELPER_CLICK_Conditions ) )
call TriggerAddAction( gg_trg_VOTING_ALTAR_HELPER_CLICK, function Trig_VOTING_ALTAR_HELPER_CLICK_Actions )
endfunction
function Trig_CREATE_WAVE_SELECTION_nested takes unit u returns nothing
local Wave nextWave
local WaveVariant v
local integer size
local integer array codes
local integer i = 0
set nextWave = udg_Waves[udg_WaveIndex]
set size = nextWave.size
set codes[0] = 'A00L'
set codes[1] = 'A00M'
set codes[2] = 'A00N'
set codes[3] = 'A00O'
loop
exitwhen i == 4
call UnitRemoveAbility(u, codes[i])
if (size > i) then
set v = nextWave.variants[i]
call UnitAddAbility(u, codes[i])
if v.arena.default then
call BlzSetAbilityTooltip( codes[i], "Vote " + v.name, 0 )
else
call BlzSetAbilityTooltip( codes[i], "Vote " + v.arena.name + " - " + v.name, 0 )
endif
call BlzSetAbilityExtendedTooltip( codes[i], v.description + "|n|nReward exp: |cff0f64ff" + I2S(v.waveRewardExp) + "|r|nReward gold: |cffeac117" + I2S(v.waveRewardGold) + "|r", 0 )
call BlzSetAbilityIcon( codes[i], v.icon )
endif
set i = i + 1
endloop
set u = null
endfunction
function Trig_CREATE_WAVE_SELECTION_Actions takes nothing returns nothing
local integer i = 0
local unit u
loop
exitwhen i == 10
if (udg_HeroPicked[i]) then
set u = udg_VotingAltars[i]
call Trig_CREATE_WAVE_SELECTION_nested(u)
endif
set i = i + 1
endloop
set u = null
call WAVE_SELECTION_BOARD.createBoard()
endfunction
//===========================================================================
function InitTrig_CREATE_WAVE_SELECTION takes nothing returns nothing
set gg_trg_CREATE_WAVE_SELECTION = CreateTrigger( )
call TriggerAddAction( gg_trg_CREATE_WAVE_SELECTION, function Trig_CREATE_WAVE_SELECTION_Actions )
endfunction
struct WAVE_SELECTION_BOARD
static integer array votes[20]
static boolean enabled = true
static integer rowCount
static method castVote takes integer index, integer choice returns nothing
set votes[index] = choice
endmethod
static method update takes nothing returns nothing
local integer option = 0
local Wave nextWave
local integer count1 = 0
local integer count2 = 0
local integer count3 = 0
local integer count4 = 0
local integer i = 0
local integer c = 0
local integer row = 0
local integer count = 0
if (enabled == false) then
return
endif
set nextWave = udg_Waves[udg_WaveIndex]
//count
loop
exitwhen i == 20
set c = votes[i]
if (c == 1) then
set count1 = count1 + 1
elseif (c == 2) then
set count2 = count2 + 1
elseif (c == 3) then
set count3 = count3 + 1
elseif (c == 4) then
set count4 = count4 + 1
endif
set i = i + 1
endloop
//header counts
if (count1 > 0) then
set count = count + 1
endif
if (count2 > 0) then
set count = count + 1
endif
if (count3 > 0) then
set count = count + 1
endif
if (count4 > 0) then
set count = count + 1
endif
//separators
if (count > 0) then
set count = count * 2 - 1
endif
//votes
set count = count + count1 + count2 + count3 + count4
//BUG: must decrease by one row at the time
loop
exitwhen count >= rowCount
set rowCount = rowCount - 1
call MultiboardSetRowCount(udg_WaveSelectionBoard, rowCount)
endloop
call MultiboardSetRowCount(udg_WaveSelectionBoard, count)
set rowCount = count
if (count1 > 0 ) then
set row = appendOptionVotes(1, row, count1, nextWave.variants[0])
endif
if (count2 > 0 ) then
set row = appendOptionVotes(2, row, count2, nextWave.variants[1])
endif
if (count3 > 0 ) then
set row = appendOptionVotes(3, row, count3, nextWave.variants[2])
endif
if (count4 > 0 ) then
set row = appendOptionVotes(4, row, count4, nextWave.variants[3])
endif
if (not IsMultiboardDisplayed(udg_WaveSelectionBoard)) then
call MultiboardDisplay(udg_WaveSelectionBoard, true)
endif
endmethod
private static method appendOptionVotes takes integer c, integer row, integer count, integer variant returns integer
local WaveVariant v = variant
local multiboarditem mbitem
local integer i = 0
local integer sum = 0
//separator
if (row > 0) then
set mbitem = MultiboardGetItem(udg_WaveSelectionBoard, row, 0)
call MultiboardSetItemStyle(mbitem, true, false)
call MultiboardSetItemValue(mbitem, "")
call MultiboardSetItemWidth(mbitem, 0.1)
call MultiboardReleaseItem(mbitem)
set mbitem = MultiboardGetItem(udg_WaveSelectionBoard, row, 1)
call MultiboardSetItemStyle(mbitem, true, false)
call MultiboardSetItemValue(mbitem, "")
call MultiboardSetItemWidth(mbitem, 0.1)
call MultiboardReleaseItem(mbitem)
set row = row + 1
endif
//sum
loop
exitwhen i == 10
if (c == votes[i]) then
set sum = sum + udg_VoteWeight
endif
set i = i + 1
endloop
loop
exitwhen i == 20
if (c == votes[i]) then
set sum = sum + 1
endif
set i = i + 1
endloop
set i = 0
//header
set mbitem = MultiboardGetItem(udg_WaveSelectionBoard, row, 0)
call MultiboardSetItemStyle(mbitem, true, true)
call MultiboardSetItemIcon(mbitem, v.icon)
call MultiboardSetItemValue(mbitem, v.name)
call MultiboardSetItemWidth(mbitem, 0.15)
call MultiboardReleaseItem(mbitem)
set mbitem = MultiboardGetItem(udg_WaveSelectionBoard, row, 1)
call MultiboardSetItemStyle(mbitem, true, false)
call MultiboardSetItemValue(mbitem, I2S(sum))
call MultiboardSetItemWidth(mbitem, 0.05)
call MultiboardReleaseItem(mbitem)
set row = row + 1
loop
exitwhen i == 10
if (c == votes[i]) then
set mbitem = MultiboardGetItem(udg_WaveSelectionBoard, row, 0)
call MultiboardSetItemStyle(mbitem, true, false)
call MultiboardSetItemValue(mbitem, udg_ColorPrefixes[(i)] + ( GetPlayerName(Player(i)) + "|r" ))
call MultiboardSetItemWidth(mbitem, 0.15)
call MultiboardReleaseItem(mbitem)
set mbitem = MultiboardGetItem(udg_WaveSelectionBoard, row, 1)
call MultiboardSetItemStyle(mbitem, true, false)
call MultiboardSetItemValue(mbitem, "(" + I2S(udg_VoteWeight) + ")")
call MultiboardSetItemWidth(mbitem, 0.05)
call MultiboardReleaseItem(mbitem)
set row = row + 1
endif
set i = i + 1
endloop
loop
exitwhen i == 20
if (c == votes[i]) then
set mbitem = MultiboardGetItem(udg_WaveSelectionBoard, row, 0)
call MultiboardSetItemStyle(mbitem, true, false)
call MultiboardSetItemValue(mbitem, udg_ColorPrefixes[(19)] + GetUnitName(udg_ExtraCharacters[i]) + "|r")
call MultiboardSetItemWidth(mbitem, 0.15)
call MultiboardReleaseItem(mbitem)
set mbitem = MultiboardGetItem(udg_WaveSelectionBoard, row, 1)
call MultiboardSetItemStyle(mbitem, true, false)
call MultiboardSetItemValue(mbitem, "(1)")
call MultiboardSetItemWidth(mbitem, 0.05)
call MultiboardReleaseItem(mbitem)
set row = row + 1
endif
set i = i + 1
endloop
set mbitem = null
return row
endmethod
static method createBoard takes nothing returns nothing
set udg_WaveSelectionBoard = CreateMultiboard()
call MultiboardSetRowCount(udg_WaveSelectionBoard, 1)
set rowCount = 1
call MultiboardSetColumnCount(udg_WaveSelectionBoard, 2)
call MultiboardSetTitleText(udg_WaveSelectionBoard, "NEXT CHALLENGE!")
call MultiboardSetTitleTextColorBJ( udg_WaveSelectionBoard, 100, 80, 20, 0 )
set thistype.enabled = true
endmethod
static method clearBoard takes nothing returns nothing
//local integer i = 0
set thistype.enabled = false
call MultiboardClear(udg_WaveSelectionBoard)
/*
loop
exitwhen i == 20
set votes[i] = 0
set i = i + 1
endloop */
endmethod
endstruct
function Trig_ON_VOTE_Actions takes nothing returns nothing
local player p = GetTriggerPlayer()
local integer c = GetSpellAbilityId()
if (c == 'A00L') then
call WAVE_SELECTION_BOARD.castVote(GetPlayerId(p), 1)
elseif (c == 'A00M') then
call WAVE_SELECTION_BOARD.castVote(GetPlayerId(p), 2)
elseif (c == 'A00N') then
call WAVE_SELECTION_BOARD.castVote(GetPlayerId(p), 3)
else
call WAVE_SELECTION_BOARD.castVote(GetPlayerId(p), 4)
endif
call WAVE_SELECTION_BOARD.update()
endfunction
function Trig_ON_VOTE_Conditions takes nothing returns boolean
local integer c = GetSpellAbilityId()
return c == 'A00L' or c == 'A00M' or c == 'A00N' or c == 'A00O' and WAVE_SELECTION_BOARD.enabled == true
endfunction
//===========================================================================
function InitTrig_ON_VOTE takes nothing returns nothing
set gg_trg_ON_VOTE = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_ON_VOTE, EVENT_PLAYER_UNIT_SPELL_CAST )
call TriggerAddCondition( gg_trg_ON_VOTE, function Trig_ON_VOTE_Conditions )
call TriggerAddAction( gg_trg_ON_VOTE, function Trig_ON_VOTE_Actions )
endfunction
function CastCrewVotes takes nothing returns nothing
call WAVE_SELECTION_BOARD.castVote(19, 2)
call WAVE_SELECTION_BOARD.update()
endfunction
function Trig_TIMER_EXTRACHARS_EXPIRE_Actions takes nothing returns nothing
local integer i = 19
local integer vote
local integer prevVote = -1
local Wave nextWave
local WaveVariant wv
set nextWave = udg_Waves[udg_WaveIndex]
loop
exitwhen i < 18 //10
if GetRandomReal(0, 1) > 0.33 then
set vote = GetRandomInt(0, nextWave.size - 1)
set wv = nextWave.variants[vote]
if prevVote != -1 and prevVote != vote then
call TransmissionFromUnitWithNameBJ(GetPlayersAll(), udg_ExtraCharacters[i], GetUnitName(udg_ExtraCharacters[i]), null, VotePrompts.randomDissent() + VotePrompts.random() + wv.name, bj_TIMETYPE_SET, 0.50, true)
else
call TransmissionFromUnitWithNameBJ(GetPlayersAll(), udg_ExtraCharacters[i], GetUnitName(udg_ExtraCharacters[i]), null, VotePrompts.random() + wv.name, bj_TIMETYPE_SET, 0.50, true)
endif
call WAVE_SELECTION_BOARD.castVote(i, vote + 1)
call WAVE_SELECTION_BOARD.update()
set prevVote = vote
endif
set i = i - 1
endloop
endfunction
//===========================================================================
function InitTrig_TIMER_EXTRACHARS_EXPIRE takes nothing returns nothing
set gg_trg_TIMER_EXTRACHARS_EXPIRE = CreateTrigger( )
call TriggerRegisterTimerExpireEventBJ( gg_trg_TIMER_EXTRACHARS_EXPIRE, udg_TimerExtraCharsVote )
call TriggerAddAction( gg_trg_TIMER_EXTRACHARS_EXPIRE, function Trig_TIMER_EXTRACHARS_EXPIRE_Actions )
endfunction
function Trig_CREATE_CLASS_SHOPS_Actions takes nothing returns nothing
local integer i = 0
local location l
local integer ut
set l = GetUnitLoc(gg_unit_n005_0024)
// ghoul
call SaveIntegerBJ( 'h00H', 0, 'U001', udg_ClassShopMap ) //no weap
call SaveIntegerBJ( 'h00H', 0, 'U003', udg_ClassShopMap ) //pile
call SaveIntegerBJ( 'h00I', 0, 'U002', udg_ClassShopMap ) //lightning
// necro
call SaveIntegerBJ( 'h00J', 0, 'U000', udg_ClassShopMap ) //lightning
call SaveIntegerBJ( 'h00J', 0, 'U005', udg_ClassShopMap ) //no weap
call SaveIntegerBJ( 'h00J', 0, 'U007', udg_ClassShopMap ) //pile
// assassin
call SaveIntegerBJ( 'h00S', 0, 'U00D', udg_ClassShopMap ) //lightning
call SaveIntegerBJ( 'h00S', 0, 'U00C', udg_ClassShopMap ) //no weap
call SaveIntegerBJ( 'h00S', 0, 'U00B', udg_ClassShopMap ) //pile
loop
exitwhen i == 10
if (udg_HeroPicked[i]) then
set ut = LoadIntegerBJ(0, GetUnitTypeId(udg_MainHeroes[i]), udg_ClassShopMap )
set udg_ClassShops[i] = CreateUnitAtLoc(Player(i), ut, l, bj_UNIT_FACING )
endif
set i = i + 1
endloop
call RemoveLocation(l)
set l = null
endfunction
//===========================================================================
function InitTrig_CREATE_CLASS_SHOPS takes nothing returns nothing
set gg_trg_CREATE_CLASS_SHOPS = CreateTrigger( )
call TriggerAddAction( gg_trg_CREATE_CLASS_SHOPS, function Trig_CREATE_CLASS_SHOPS_Actions )
endfunction
function Trig_CLASS_SHOP_HELPER_CLICK_Conditions takes nothing returns boolean
return GetTriggerUnit() == gg_unit_n005_0024
endfunction
function Trig_CLASS_SHOP_HELPER_CLICK_Actions takes nothing returns nothing
local player p = GetTriggerPlayer()
// call SelectUnitForPlayerSingle( udg_ClassShops[0], Player(0) )
call SelectUnitForPlayerSingle( udg_ClassShops[GetPlayerId(p)], p )
endfunction
//===========================================================================
function InitTrig_CLASS_SHOP_HELPER_CLICK takes nothing returns nothing
set gg_trg_CLASS_SHOP_HELPER_CLICK = CreateTrigger( )
call TriggerRegisterPlayerSelectionEventBJ( gg_trg_CLASS_SHOP_HELPER_CLICK, Player(0), true )
call TriggerRegisterPlayerSelectionEventBJ( gg_trg_CLASS_SHOP_HELPER_CLICK, Player(1), true )
call TriggerRegisterPlayerSelectionEventBJ( gg_trg_CLASS_SHOP_HELPER_CLICK, Player(2), true )
call TriggerRegisterPlayerSelectionEventBJ( gg_trg_CLASS_SHOP_HELPER_CLICK, Player(3), true )
call TriggerRegisterPlayerSelectionEventBJ( gg_trg_CLASS_SHOP_HELPER_CLICK, Player(4), true )
call TriggerRegisterPlayerSelectionEventBJ( gg_trg_CLASS_SHOP_HELPER_CLICK, Player(5), true )
call TriggerRegisterPlayerSelectionEventBJ( gg_trg_CLASS_SHOP_HELPER_CLICK, Player(6), true )
call TriggerRegisterPlayerSelectionEventBJ( gg_trg_CLASS_SHOP_HELPER_CLICK, Player(7), true )
call TriggerRegisterPlayerSelectionEventBJ( gg_trg_CLASS_SHOP_HELPER_CLICK, Player(8), true )
call TriggerRegisterPlayerSelectionEventBJ( gg_trg_CLASS_SHOP_HELPER_CLICK, Player(9), true )
call TriggerAddCondition( gg_trg_CLASS_SHOP_HELPER_CLICK, Condition( function Trig_CLASS_SHOP_HELPER_CLICK_Conditions ) )
call TriggerAddAction( gg_trg_CLASS_SHOP_HELPER_CLICK, function Trig_CLASS_SHOP_HELPER_CLICK_Actions )
endfunction
function Trig_START_HUB_Unit takes nothing returns nothing
local location l = GetRandomLocInRect(gg_rct_HUBCENTER)
call SetUnitPositionLoc(GetEnumUnit(), l)
call AddSpecialEffectLocBJ(l, "Abilities\\Spells\\Human\\MassTeleport\\MassTeleportCaster.mdl")
call DestroyEffect(GetLastCreatedEffectBJ())
call RemoveLocation(l)
set l = null
endfunction
function Trig_START_HUB_Player takes nothing returns nothing
local location l
set bj_wantDestroyGroup = true
call ForGroupBJ(GetUnitsOfPlayerAll(GetEnumPlayer()), function Trig_START_HUB_Unit)
set l = GetUnitLoc(udg_MainHeroes[GetPlayerId(GetEnumPlayer())])
call PanCameraToTimedLocForPlayer(GetEnumPlayer(), l, 0.00 )
call RemoveLocation(l)
set l = null
endfunction
function Trig_START_HUB_Actions takes nothing returns nothing
set udg_PHASE = 1
call TriggerExecute(gg_trg_SET_HUB_BOUND)
call ForForce(udg_HumanPlayers, function Trig_START_HUB_Player)
call StartTimerBJ( udg_TimerHub, false, 20.00 )
call CreateTimerDialogBJ(udg_TimerHub, "TRIGSTR_1612")
call TimerDialogDisplayBJ( true, GetLastCreatedTimerDialogBJ() )
set udg_TimerHubWindow = GetLastCreatedTimerDialogBJ()
call TriggerExecute( gg_trg_CREATE_VOTING_ALTARS )
call TriggerExecute( gg_trg_CREATE_WAVE_SELECTION )
call TriggerExecute( gg_trg_CREATE_CLASS_SHOPS )
call DestroyMultiboard(udg_PickBoard)
set udg_StoppableTimerEnabled = true
call PolledWait( 3.00 )
call DisableTrigger( gg_trg_CREATE_PICK_BOARD )
call DisableTrigger( gg_trg_UPDATE_PICK_BOARD )
call TransmissionFromUnitWithNameBJ( GetPlayersAll(), gg_unit_u00G_0030, "TRIGSTR_1613", null, "TRIGSTR_1614", bj_TIMETYPE_SET, 2.00, true )
call StartTimerBJ( udg_TimerExtraCharsVote, false, 3.50 )
call StartTimerBJ( udg_Timer_Difficulty_Prompt, false, 6.00 )
call EnableTrigger( gg_trg_ShowAggro )
set AttackLoopUnits.instance = AttackLoopUnits.create()
call AttackLoopUnits.instance.start()
endfunction
//===========================================================================
function InitTrig_START_HUB takes nothing returns nothing
set gg_trg_START_HUB = CreateTrigger( )
call TriggerAddAction( gg_trg_START_HUB, function Trig_START_HUB_Actions )
endfunction
function Trig_NEXT_HUB_playerLoop2 takes nothing returns nothing
local location l
if (IsUnitType(GetEnumUnit(), UNIT_TYPE_STRUCTURE) == false) then
set l = GetRandomLocInRect(gg_rct_HUBCENTER)
call SetUnitPositionLoc(GetEnumUnit(), l)
call AddSpecialEffectLocBJ(l, "Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilSpecialArt.mdl")
call DestroyEffect(GetLastCreatedEffectBJ())
call RemoveLocation (l)
set l = null
call SetUnitLifePercentBJ( GetEnumUnit(), 100 )
call SetUnitManaPercentBJ( GetEnumUnit(), 100 )
endif
endfunction
function Trig_NEXT_HUB_playerLoop takes nothing returns nothing
local location l
set bj_wantDestroyGroup = true
call ForGroupBJ(GetUnitsOfPlayerAll(GetEnumPlayer()), function Trig_NEXT_HUB_playerLoop2)
set l = GetUnitLoc(udg_MainHeroes[GetPlayerId(GetEnumPlayer())])
call PanCameraToTimedLocForPlayer(GetEnumPlayer(), l, 0.00)
call RemoveLocation (l)
set l = null
endfunction
function BuildGameDpsString takes integer maxWave, integer index returns string
local ROUND_STATS rs
local integer i = 0
local boolean dirty = false
local string s = "Your dps across the game was "
loop
exitwhen i > maxWave
set rs = udg_ALL_ROUND_STATS[i]
if dirty then
set s = s + " --> "
else
set dirty = true
endif
set s = s + R2S(rs.getDps(i, index))
set i = i + 1
endloop
return s
endfunction
function DisplayRoundStats takes integer windex returns nothing
local ROUND_STATS rs = udg_ALL_ROUND_STATS[windex]
local integer pid = rs.maxDpsIndex(windex)
local integer i = 0
local player p
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "Last wave the top dps was: " + R2S(rs.getDps(windex, pid)) + " (" + udg_ColorPrefixes[pid] + GetPlayerName(Player(pid)) + "|r)" )
loop
exitwhen i == 10
set p = Player(i)
if GetLocalPlayer() == p then
call DisplayTextToPlayer(p, 0, 0, BuildGameDpsString(windex, i))
endif
set i = i + 1
endloop
set pid = ROUND_STATS.maxRevives(windex)
if pid > -1 then
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "Most wicked servant raised: " + I2S(LoadInteger(udg_ReviveStats, windex, pid)) + " (" + udg_ColorPrefixes[pid] + GetPlayerName(Player(pid)) + "|r)" )
endif
endfunction
function Trig_NEXT_HUB_Actions takes nothing returns nothing
local WaveVariant v = udg_Variant
set udg_PHASE = 1
call TriggerExecute(gg_trg_SET_HUB_BOUND)
call ForForce(udg_HumanPlayers, function Trig_NEXT_HUB_playerLoop)
call DisplayRoundStats(udg_WaveIndex - 1)
call StartTimerBJ(udg_TimerHub, false, 30.00)
call StartTimerBJ(udg_TimerExtraCharsVote, false, 5.00)
call TimerDialogDisplay(udg_TimerHubWindow, true)
call TriggerExecute( gg_trg_CREATE_WAVE_SELECTION )
set udg_StoppableTimerEnabled = true
call PolledWait( 3.00 )
call QuestMessageBJ(GetPlayersAll(), bj_QUESTMESSAGE_ALWAYSHINT, "TRIGSTR_051") //player red can stop time
endfunction
//===========================================================================
function InitTrig_NEXT_HUB takes nothing returns nothing
set gg_trg_NEXT_HUB = CreateTrigger( )
call TriggerAddAction( gg_trg_NEXT_HUB, function Trig_NEXT_HUB_Actions )
endfunction
function Trig_TIMER_DIFF_PROMPT_EXPIRE_Conditions takes nothing returns boolean
//return true
return Difficulty.level == 0 //unset
endfunction
function Trig_TIMER_DIFF_PROMPT_EXPIRE_Actions takes nothing returns nothing
local integer count = CountSelectedHeroes()
local string msg = "Difficulty set to "
if (count > 1) then
call SetDifficulty(Difficulty.normal, false)
else
call SetDifficulty(Difficulty.easy, false)
endif
set msg = msg + Difficulty.current.name + " - " + Difficulty.current.description
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, msg)
call TriggerSleepAction(1.0)
set msg = "Before the arena starts player red can use the commands "
set msg = msg + "|cff6677ee" + Difficulty.easy.prompt + "|r, "
set msg = msg + "|cff6677ee" + Difficulty.normal.prompt + "|r "
set msg = msg + "to change the difficulty"
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, msg)
endfunction
//===========================================================================
function InitTrig_TIMER_DIFF_PROMPT_EXPIRE takes nothing returns nothing
set gg_trg_TIMER_DIFF_PROMPT_EXPIRE = CreateTrigger( )
call TriggerRegisterTimerExpireEventBJ( gg_trg_TIMER_DIFF_PROMPT_EXPIRE, udg_Timer_Difficulty_Prompt )
call TriggerAddCondition(gg_trg_TIMER_DIFF_PROMPT_EXPIRE, Condition(function Trig_TIMER_DIFF_PROMPT_EXPIRE_Conditions))
call TriggerAddAction( gg_trg_TIMER_DIFF_PROMPT_EXPIRE, function Trig_TIMER_DIFF_PROMPT_EXPIRE_Actions )
endfunction
function Trig_SET_HUB_BOUND_playerLoop takes nothing returns nothing
call SetCameraBoundsToRectForPlayerBJ( GetEnumPlayer(), gg_rct_BOUNDHUB )
endfunction
function Trig_SET_HUB_BOUND_Actions takes nothing returns nothing
call ForForce( udg_HumanPlayers, function Trig_SET_HUB_BOUND_playerLoop )
call switchCurrentPlayableArea(HUB_AREA_CREATE())
call BlzChangeMinimapTerrainTex("war3mapImported\\hubWhite.blp")
endfunction
//===========================================================================
function InitTrig_SET_HUB_BOUND takes nothing returns nothing
set gg_trg_SET_HUB_BOUND = CreateTrigger( )
call TriggerAddAction( gg_trg_SET_HUB_BOUND, function Trig_SET_HUB_BOUND_Actions )
endfunction
function Trig_ElevatedThreat_Conditions takes nothing returns boolean
return udg_PHASE == 2
endfunction
function Trig_ElevatedThreat_ApplyThreat takes unit h returns nothing
local unit u
local group g = CreateGroup()
local player p = GetOwningPlayer(h)
local integer index = -1
local real prev
call GroupEnumUnitsInRange(g, GetUnitX(h), GetUnitY(h), 400, function True_Filter)
loop
set u = FirstOfGroup(g)
exitwhen u == null
call GroupRemoveUnit(g, u)
if IsUnitEnemy(u,p) and UnitAlive(u) and GetUnitAbilityLevel(u, 'Avul') < 1 then
call AddAggro(GetHandleId(u), h, GetHeroStr(h, true) * 3)
endif
endloop
call DestroyGroup(g)
set u = null
set g = null
endfunction
function Trig_ElevatedThreat_Actions takes nothing returns nothing
local unit h
local integer i = 0
loop
exitwhen i == 10
set h = udg_MainHeroes[i]
if (h != null and GetUnitAbilityLevel(h, 'A035') > 0) then
call Trig_ElevatedThreat_ApplyThreat(h)
endif
set i = i + 1
endloop
set h = null
endfunction
//===========================================================================
function InitTrig_ElevatedThreat takes nothing returns nothing
set gg_trg_ElevatedThreat = CreateTrigger( )
call TriggerRegisterTimerEventPeriodic( gg_trg_ElevatedThreat, 1)
call TriggerAddCondition( gg_trg_ElevatedThreat, Condition( function Trig_ElevatedThreat_Conditions ) )
call TriggerAddAction( gg_trg_ElevatedThreat, function Trig_ElevatedThreat_Actions )
endfunction
function Trig_W10V1_AI_Shield1_Conditions takes nothing returns boolean
return (udg_SeniorPaladinPhase == 0 and GetUnitTypeId(GetAttackedUnitBJ()) == 'H00N' and GetUnitLifePercent(GetAttackedUnitBJ()) < 25.00)
endfunction
function Trig_W10V1_AI_Shield1_Actions takes nothing returns nothing
local unit dummy
local location l
local unit u = GetTriggerUnit()
call DisableTrigger(gg_trg_W10V1_AI_Shield1)
set l = GetUnitLoc(u)
call BossPrompt(u, "Pfffffh")
set dummy = CreateUnitAtLoc(GetOwningPlayer(u), 'h004', l, bj_UNIT_FACING )
call RemoveGuardPosition( dummy )
call UnitAddAbility(dummy, 'A01U')
call UnitApplyTimedLife(dummy, 'BTLF', 2.0)
call IssueTargetOrder( dummy, "innerfire", u )
call PaladinHolyShieldHeal.create(7.0, u, GetHeroInt(u, true)).startPeriodic()
call EnableTrigger(gg_trg_W10PaladinMightyHammer1)
call RemoveLocation(l)
set l = null
set dummy = null
endfunction
//===========================================================================
function InitTrig_W10V1_AI_Shield1 takes nothing returns nothing
set gg_trg_W10V1_AI_Shield1 = CreateTrigger( )
//call DisableTrigger( gg_trg_W10V1_AI_Shield1 )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W10V1_AI_Shield1, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddCondition( gg_trg_W10V1_AI_Shield1, Condition( function Trig_W10V1_AI_Shield1_Conditions ) )
call TriggerAddAction( gg_trg_W10V1_AI_Shield1, function Trig_W10V1_AI_Shield1_Actions )
endfunction
function Trig_W10V1_AI_Shield2_Conditions takes nothing returns boolean
return (udg_SeniorPaladinPhase == 1 and GetUnitTypeId(GetAttackedUnitBJ()) == 'H00N' and GetUnitLifePercent(GetAttackedUnitBJ()) < 25.00)
endfunction
function Trig_W10V1_AI_Shield2_Actions takes nothing returns nothing
local unit dummy
local location l
local unit u = GetTriggerUnit()
call DisableTrigger(gg_trg_W10V1_AI_Shield2)
set l = GetUnitLoc(u)
call BossPrompt(u, "It's not over yet!")
set dummy = CreateUnitAtLoc(GetOwningPlayer(u), 'h004', l, bj_UNIT_FACING )
call RemoveGuardPosition( dummy )
call UnitAddAbility(dummy, 'A01U')
call UnitApplyTimedLife(dummy, 'BTLF', 2.0)
call IssueTargetOrder( dummy, "innerfire", u )
call PaladinHolyShieldHeal.create(7.0, u, GetHeroInt(u, true)).startPeriodic()
call RemoveLocation(l)
set l = null
set dummy = null
endfunction
//===========================================================================
function InitTrig_W10V1_AI_Shield2 takes nothing returns nothing
set gg_trg_W10V1_AI_Shield2 = CreateTrigger( )
//call DisableTrigger( gg_trg_W10V1_AI_Shield2 )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W10V1_AI_Shield2, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddCondition( gg_trg_W10V1_AI_Shield2, Condition( function Trig_W10V1_AI_Shield2_Conditions ) )
call TriggerAddAction( gg_trg_W10V1_AI_Shield2, function Trig_W10V1_AI_Shield2_Actions )
endfunction
function Trig_W10PaladinMitigation_Conditions takes nothing returns boolean
return UnitHasBuffBJ(udg_DamageEventTarget, 'B008')
endfunction
function Trig_W10PaladinMitigation_Actions takes nothing returns nothing
set udg_DamageEventAmount = udg_DamageEventAmount * 0.1
endfunction
//===========================================================================
function InitTrig_W10PaladinMitigation takes nothing returns nothing
set gg_trg_W10PaladinMitigation = CreateTrigger( )
call TriggerAddCondition(gg_trg_W10PaladinMitigation, function Trig_W10PaladinMitigation_Conditions )
call TriggerRegisterVariableEvent( gg_trg_W10PaladinMitigation, "udg_PreDamageEvent", EQUAL, 1.00 )
call TriggerAddAction( gg_trg_W10PaladinMitigation, function Trig_W10PaladinMitigation_Actions )
endfunction
function Trig_W10PaladinMightyHammer1_Conditions takes nothing returns boolean
return GetUnitTypeId(udg_DamageEventSource) == 'H00N' and udg_IsDamageAttack and udg_SeniorPaladinPhase > 0
endfunction
function Trig_W10PaladinMightyHammer1_filter takes nothing returns boolean
local boolean retval
local unit u = GetFilterUnit()
local player p = GetOwningPlayer(udg_DamageEventSource)
set retval = IsUnitEnemy(u,p) and UnitAlive(u) and GetUnitAbilityLevel(u,'Avul') < 1
set u = null
set p = null
return retval
endfunction
function Trig_W10PaladinMightyHammer1_Actions takes nothing returns nothing
local integer stat
local location l
local unit u
local unit t
local group g
local real x
local real y
set u = udg_DamageEventSource
set l = GetUnitLoc(udg_DamageEventTarget)
set x = GetUnitX(udg_DamageEventTarget)
set y = GetUnitY(udg_DamageEventTarget)
set stat = GetHeroStr(u, true)
set g = CreateGroup()
call GroupEnumUnitsInRange(g, x, y, 200, function Trig_W10PaladinMightyHammer1_filter)
call AddSpecialEffectLocBJ( l, "Abilities\\Spells\\Orc\\WarStomp\\WarStompCaster.mdl" )
call DestroyEffect( GetLastCreatedEffectBJ() )
loop
set t = FirstOfGroup(g)
exitwhen t == null
call GroupRemoveUnit(g, t)
call UnitDamageTargetBJ( u, t, 1.0 * stat, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL )
endloop
call RemoveLocation(l)
call DestroyGroup(g)
set l = null
set g = null
set u = null
endfunction
//===========================================================================
function InitTrig_W10PaladinMightyHammer1 takes nothing returns nothing
set gg_trg_W10PaladinMightyHammer1 = CreateTrigger( )
call DisableTrigger( gg_trg_W10PaladinMightyHammer1 )
call TriggerAddCondition(gg_trg_W10PaladinMightyHammer1, function Trig_W10PaladinMightyHammer1_Conditions )
call TriggerRegisterVariableEvent( gg_trg_W10PaladinMightyHammer1, "udg_DamageEvent", EQUAL, 1.00 )
call TriggerAddAction( gg_trg_W10PaladinMightyHammer1, function Trig_W10PaladinMightyHammer1_Actions )
endfunction
struct PaladinHolyShieldHeal
private unit u
private integer stat
private integer endTick
private integer nextTick
private method periodic takes nothing returns nothing
local location l
local integer i = 0
if nextTick == T32_Tick and UnitAlive(u) then
set l = GetUnitLoc(u)
call AddSpecialEffectLocBJ( l, "Abilities\\Spells\\Human\\HolyBolt\\HolyBoltSpecialArt.mdl" )
call SetUnitLifeBJ( u, GetUnitStateSwap(UNIT_STATE_LIFE, u) + stat * 20)
call DestroyEffect( GetLastCreatedEffectBJ() )
set nextTick = nextTick + 16
call RemoveLocation(l)
set l = null
endif
if this.endTick == T32_Tick then
call SetUnitManaPercentBJ( u, 100 )
set udg_SeniorPaladinPhase = udg_SeniorPaladinPhase + 1
set u = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes real duration, unit paladin, integer stat returns thistype
local thistype this = thistype.allocate()
set this.u = paladin
set this.nextTick = T32_Tick + 16
set this.stat = stat
set this.endTick = T32_Tick + R2I(duration / T32_PERIOD)
return this
endmethod
endstruct
function Trig_W10PaladinMassHolyLight_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A01R'
endfunction
function Trig_W10PaladinMassHolyLight_Actions takes nothing returns nothing
local integer stat
local location l
local unit u
set u = GetTriggerUnit()
set l = GetUnitLoc(u)
set stat = GetHeroStatBJ(bj_HEROSTAT_INT, u, true)
call BossPrompt(u, "Mass Holy Light")
call PaladinMassHolyLightEffectEffect.create(u, l, stat).startPeriodic()
set u = null
set l = null
endfunction
//===========================================================================
function InitTrig_W10PaladinMassHolyLight takes nothing returns nothing
set gg_trg_W10PaladinMassHolyLight = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W10PaladinMassHolyLight, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_W10PaladinMassHolyLight, Condition( function Trig_W10PaladinMassHolyLight_Conditions ) )
call TriggerAddAction( gg_trg_W10PaladinMassHolyLight, function Trig_W10PaladinMassHolyLight_Actions )
endfunction
struct PaladinMassHolyLightEffectEffect
private unit u
private location center
private integer stat
private integer endTick
private integer tick1
private integer tick2
private integer tick3
private integer tick4
private integer tick5
private integer tick6
private method periodic takes nothing returns nothing
local location strikeLoc
local integer i = 0
if tick1 == T32_Tick and UnitAlive(u) then
loop
exitwhen i == 6
set strikeLoc = PolarProjectionBJ(center, 150, i * 60)
call PaladinMassHolyLightStrike.create(2.0, u, strikeLoc, stat).startPeriodic()
set i = i + 1
endloop
set strikeLoc = null
endif
if tick2 == T32_Tick and UnitAlive(u) then
loop
exitwhen i == 12
set strikeLoc = PolarProjectionBJ(center, 300, i * 30 + 45)
call PaladinMassHolyLightStrike.create(2.0, u, strikeLoc, stat).startPeriodic()
set i = i + 1
endloop
set strikeLoc = null
endif
if tick3 == T32_Tick and UnitAlive(u) then
loop
exitwhen i == 24
set strikeLoc = PolarProjectionBJ(center, 450, i * 15)
call PaladinMassHolyLightStrike.create(2.0, u, strikeLoc, stat).startPeriodic()
set i = i + 1
endloop
set strikeLoc = null
endif
if tick4 == T32_Tick and UnitAlive(u) then
loop
exitwhen i == 12
set strikeLoc = PolarProjectionBJ(center, 300, i * 30 + 15)
call PaladinMassHolyLightStrike.create(2.0, u, strikeLoc, stat).startPeriodic()
set i = i + 1
endloop
set strikeLoc = null
endif
if tick5 == T32_Tick and UnitAlive(u) then
loop
exitwhen i == 6
set strikeLoc = PolarProjectionBJ(center, 150, i * 60)
call PaladinMassHolyLightStrike.create(2.0, u, strikeLoc, stat).startPeriodic()
set i = i + 1
endloop
set strikeLoc = null
endif
if this.endTick == T32_Tick then
call RemoveLocation(center)
set u = null
set center = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes unit paladin, location l, integer stat returns thistype
local thistype this = thistype.allocate()
set this.u = paladin
set this.tick1 = T32_Tick + 24
set this.tick2 = T32_Tick + 40
set this.tick3 = T32_Tick + 56
set this.tick4 = T32_Tick + 80
set this.tick5 = T32_Tick + 96
set this.stat = stat
set this.center = l
set this.endTick = T32_Tick + 120
return this
endmethod
endstruct
struct PaladinMassHolyLightStrike
private unit caster
private unit targetingDummy
private location l
private integer stat
private integer endTick
private integer nextTick
private integer secondTick
private method periodic takes nothing returns nothing
local real x
local real y
local group g
local unit t
if secondTick == T32_Tick then
set targetingDummy = CreateUnitAtLoc(GetOwningPlayer(caster), 'h00F', l, bj_UNIT_FACING )
endif
if nextTick == T32_Tick then
call RemoveUnit(targetingDummy)
set targetingDummy = null
call AddSpecialEffectLocBJ( l, "Abilities\\Spells\\Human\\HolyBolt\\HolyBoltSpecialArt.mdl" )
call DestroyEffect( GetLastCreatedEffectBJ() )
set x = GetLocationX(l)
set y = GetLocationY(l)
set g = CreateGroup()
call GroupEnumUnitsInRange(g, x, y, 85, function True_Filter)
loop
set t = FirstOfGroup(g)
exitwhen t == null
call GroupRemoveUnit(g, t)
if (IsUnitEnemy(t,GetOwningPlayer(caster)) and UnitAlive(t)) then
call UnitDamageTargetBJ( caster, t, 3.0 * stat, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC )
endif
set t = null
endloop
call DestroyGroup(g)
set g = null
endif
if this.endTick == T32_Tick then
call RemoveLocation(l)
set caster = null
set l = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes real duration, unit caster, location l, integer stat returns thistype
local thistype this = thistype.allocate()
set this.caster = caster
set this.l = l
set this.stat = stat
set this.endTick = T32_Tick + R2I(duration / T32_PERIOD)
set this.nextTick = T32_Tick + R2I(duration / T32_PERIOD) / 2
set this.secondTick = T32_Tick + 1
return this
endmethod
endstruct
function Trig_W10PaladinSummon_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A01S'
endfunction
function Trig_W10PaladinSummon_Loc takes location start returns location target
local location loc
local PlayableArea pa = udg_CURRENT_PLAYABLE_AREA
loop
set loc = PolarProjectionBJ(start, GetRandomInt(200, 600), GetRandomInt(0, 359))
exitwhen pa.containsLocation(loc)
call RemoveLocation(loc)
endloop
return loc
endfunction
function Trig_W10PaladinSummon_Actions takes nothing returns nothing
local location l
local location ls
local unit u
local player p
local integer i
local integer str
local integer int
set u = GetTriggerUnit()
set l = GetUnitLoc(u)
set int = GetHeroInt(u, true)
set str = GetHeroStr(u, true)
call BossPrompt(u, "Summon Reinforments")
set i = MathRound(CountPlayersInForceBJ(udg_HumanPlayers) * 1.4 - 1 )
set p = GetOwningPlayer(u)
loop
exitwhen i == 0
set ls = Trig_W10PaladinSummon_Loc(l)
call AddSpecialEffectLocBJ( ls, "Abilities\\Spells\\Human\\MassTeleport\\MassTeleportCaster.mdl" )
call DestroyEffect(GetLastCreatedEffectBJ())
set u = CreateUnitAtLoc(p, 'h00O', ls, bj_UNIT_FACING)
call BlzSetUnitMaxHP(u, str * 8)
call SetUnitLifePercentBJ(u, 100)
call BlzSetUnitBaseDamage(u, MathRound(int), 0)
call RegisterCreep(u)
set i = i - 1
call RemoveLocation(ls)
endloop
set ls = null
set u = null
set l = null
endfunction
//===========================================================================
function InitTrig_W10PaladinSummon takes nothing returns nothing
set gg_trg_W10PaladinSummon = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W10PaladinSummon, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_W10PaladinSummon, Condition( function Trig_W10PaladinSummon_Conditions ) )
call TriggerAddAction( gg_trg_W10PaladinSummon, function Trig_W10PaladinSummon_Actions )
endfunction
function Trig_W10PaladinBloodlust1_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A01W'
endfunction
function Trig_W10PaladinBloodlust1_Actions takes nothing returns nothing
local unit dummy
local location l
local unit u = GetTriggerUnit()
set l = GetUnitLoc(u)
set dummy = CreateUnitAtLoc(GetOwningPlayer(u), 'h004', l, bj_UNIT_FACING )
call RemoveGuardPosition( dummy )
call UnitAddAbility(dummy, 'A01V')
call UnitApplyTimedLife(dummy, 'BTLF', 2.0)
call IssueTargetOrder( dummy, "bloodlust", u )
endfunction
//===========================================================================
function InitTrig_W10PaladinBloodlust1 takes nothing returns nothing
set gg_trg_W10PaladinBloodlust1 = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W10PaladinBloodlust1, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_W10PaladinBloodlust1, Condition( function Trig_W10PaladinBloodlust1_Conditions ) )
call TriggerAddAction( gg_trg_W10PaladinBloodlust1, function Trig_W10PaladinBloodlust1_Actions )
endfunction
function Trig_W10PaladinSweep_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A01X'
endfunction
function Trig_W10PaladinSweep_Actions takes nothing returns nothing
local integer stat
local unit u = GetTriggerUnit()
set stat = GetHeroStatBJ(bj_HEROSTAT_INT, u, true)
call BossPrompt(u, "Sweep")
call PaladinSweepEffect.create(u, stat).startPeriodic()
set u = null
endfunction
//===========================================================================
function InitTrig_W10PaladinSweep takes nothing returns nothing
set gg_trg_W10PaladinSweep = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W10PaladinSweep, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_W10PaladinSweep, Condition( function Trig_W10PaladinSweep_Conditions ) )
call TriggerAddAction( gg_trg_W10PaladinSweep, function Trig_W10PaladinSweep_Actions )
endfunction
struct PaladinSweepEffect
private unit u
private real angle
private integer stat
private integer endTick
private integer nextTick
private method periodic takes nothing returns nothing
local location strikeLoc
local location lu
local integer i = 0
if nextTick == T32_Tick and UnitAlive(u) then
loop
exitwhen i == 12
set lu = GetUnitLoc(u)
set strikeLoc = PolarProjectionBJ(lu, 150 + i * 150, GetUnitFacing(u) + angle)
call PaladinMassHolyLightStrike.create(2.0, u, strikeLoc, stat).startPeriodic()
set i = i + 1
endloop
set strikeLoc = null
call RemoveLocation(lu)
set lu = null
set nextTick = nextTick + 8
set angle = angle - 5
endif
if this.endTick == T32_Tick then
set u = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes unit paladin, integer stat returns thistype
local thistype this = thistype.allocate()
set this.u = paladin
set this.nextTick = T32_Tick + 24
set this.stat = stat
set this.endTick = T32_Tick + 120
set this.angle = 40.0
return this
endmethod
endstruct
function Trig_W9ArchmageBlizz_Actions takes nothing returns nothing
local unit u = GetTriggerUnit()
local unit farthest = null
local real distanceF = 0
local real distanceC
local unit c
local group g = CreateGroup()
local location l = GetUnitLoc(u)
local location lc
local player p = GetOwningPlayer(u)
local integer stat = GetHeroInt(u, true)
call GroupEnumUnitsInRangeOfLoc(g, l, 800, function True_Filter)
loop
set c = FirstOfGroup(g)
exitwhen c == null
call GroupRemoveUnit(g, c)
if (IsUnitEnemy(c, p) and UnitAlive(c) and GetUnitAbilityLevel(c,'Avul') < 1 ) then
set lc = GetUnitLoc(c)
set distanceC = DistanceBetweenPoints(l, lc)
if (distanceC > distanceF) then
set distanceF = distanceC
set farthest = c
endif
call RemoveLocation(lc)
endif
endloop
if (farthest != null) then
set lc = GetUnitLoc(farthest)
call BossPrompt(u, "Blizzard")
call ArchmageBlizzardEffect.create(u, farthest, stat).startPeriodic()
endif
call DestroyGroup(g)
call RemoveLocation(l)
set lc = null
set l = null
set u = null
set c = null
set farthest = null
set g = null
set p = null
endfunction
function Trig_W9ArchmageBlizz_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A033'
endfunction
//===========================================================================
function InitTrig_W9ArchmageBlizz takes nothing returns nothing
set gg_trg_W9ArchmageBlizz = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(gg_trg_W9ArchmageBlizz, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(gg_trg_W9ArchmageBlizz, function Trig_W9ArchmageBlizz_Conditions)
call TriggerAddAction( gg_trg_W9ArchmageBlizz, function Trig_W9ArchmageBlizz_Actions )
endfunction
struct ArchmageBlizzardEffect
private unit u
private unit t
private unit dummy
private unit targeting
private integer stat
private integer nextTick
private integer castTick
private integer endTick
private method periodic takes nothing returns nothing
if nextTick == T32_Tick then
if dummy == null or DistanceBetweenUnits(dummy, t) > 300 then
set dummy = CreateUnit(GetOwningPlayer(u), 'h004', GetUnitX(t), GetUnitY(t), bj_UNIT_FACING)
call UnitAddAbility(dummy, 'A032')
call BlzSetAbilityRealLevelField(BlzGetUnitAbility(dummy, 'A032'), ABILITY_RLF_DAMAGE_HBZ2, 0, stat * 3) //1x int
call UnitApplyTimedLife(dummy, 'BTLF', 8.0)
//call IssuePointOrder(dummy, "blizzard", GetUnitX(t), GetUnitY(t))
set targeting = CreateUnit(GetOwningPlayer(u), 'h00D', GetUnitX(t), GetUnitY(t), bj_UNIT_FACING)
call SetUnitScale(targeting, 3, 3, 3)
call UnitApplyTimedLife(targeting, 'BTLF', 8.0)
endif
set castTick = T32_Tick + 24
set nextTick = T32_Tick + 32
endif
if castTick == T32_Tick then
call IssuePointOrder(dummy, "blizzard", GetUnitX(targeting), GetUnitY(targeting))
set targeting = null
endif
if endTick == T32_Tick then
set u = null
set dummy = null
set t = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes unit u, unit t, integer stat returns thistype
local thistype this = thistype.allocate()
set this.u = u
set this.t = t
set this.stat = stat
set this.nextTick = T32_Tick + 16
set this.endTick = T32_Tick + R2I(8.0 / T32_PERIOD)
return this
endmethod
endstruct
function Trig_W8V2_AI_Wall_Conditions takes nothing returns boolean
return GetUnitTypeId(GetAttacker()) == 'H015'
endfunction
function Trig_W8V2_AI_Wall_Actions takes nothing returns nothing
call IssueImmediateOrder(GetAttacker(), "roar")
endfunction
//===========================================================================
function InitTrig_W8V2_AI_Wall takes nothing returns nothing
set gg_trg_W8V2_AI_Wall = CreateTrigger( )
call DisableTrigger(gg_trg_W8V2_AI_Wall)
call TriggerRegisterAnyUnitEventBJ( gg_trg_W8V2_AI_Wall, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddCondition( gg_trg_W8V2_AI_Wall, Condition( function Trig_W8V2_AI_Wall_Conditions ) )
call TriggerAddAction( gg_trg_W8V2_AI_Wall, function Trig_W8V2_AI_Wall_Actions )
endfunction
function Trig_W8DominaWall_Actions takes nothing returns nothing
local unit u = GetTriggerUnit()
local integer stat = GetHeroInt(u, true)
local real roll = GetRandomReal(0, 1)
call BossPrompt(u, "Summon Duplicates")
if roll > 0.6666 then
call DominaWallEffectC.create(u, stat).startPeriodic()
elseif roll > 0.3333 then
call DominaWallEffectB.create(u, stat).startPeriodic()
else
call DominaWallEffect.create(u, stat).startPeriodic()
endif
set u = null
endfunction
function Trig_W8DominaWall_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A030'
endfunction
//===========================================================================
function InitTrig_W8DominaWall takes nothing returns nothing
set gg_trg_W8DominaWall = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(gg_trg_W8DominaWall, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(gg_trg_W8DominaWall, function Trig_W8DominaWall_Conditions)
call TriggerAddAction( gg_trg_W8DominaWall, function Trig_W8DominaWall_Actions )
endfunction
struct DominaWallEffect
private unit u
private integer stat
private integer iterations
private real angle
private boolean dirty
private integer startTick
private integer endTick
private integer ticks
private integer tickIncrements
private method periodic takes nothing returns nothing
if dirty == false then
set dirty = true
set tickIncrements = 18
set ticks = tickIncrements
set angle = GetUnitFacing(u)
set iterations = 0
endif
if startTick + ticks == T32_Tick then
if iterations == 8 then
set endTick = T32_Tick + tickIncrements
call SetUnitAnimation(u, "victory")
elseif iterations == 7 then
call SetUnitAnimation(u, "victory")
set ticks = ticks + R2I(tickIncrements * 5)
elseif iterations == 6 then
set ticks = ticks + R2I(tickIncrements * 2)
else
call DominaWallEffectClone.create(u, PolarProjectionU(u, 100 * iterations + 100, angle + 90), angle + GetRandomInt(0, 1) * 180, R2I(tickIncrements * (6.5 - iterations)), 5 * tickIncrements, stat).startPeriodic()
call DominaWallEffectClone.create(u, PolarProjectionU(u, 100 * iterations + 100, angle - 90), angle + GetRandomInt(0, 1) * 180, R2I(tickIncrements * (6.5 - iterations)), 5 * tickIncrements, stat).startPeriodic()
set ticks = ticks + tickIncrements
endif
set iterations = iterations + 1
endif
if UnitDead(u) then
set endTick = T32_Tick
endif
if endTick == T32_Tick then
set u = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes unit u, integer stat returns thistype
local thistype this = thistype.allocate()
set this.u = u
set this.stat = stat
set this.dirty = false
set this.startTick = T32_Tick
set this.endTick = 0
return this
endmethod
endstruct
struct DominaWallEffectB
private unit u
private integer stat
private integer iterations
private real angle
private boolean dirty
private integer startTick
private integer endTick
private integer ticks
private integer tickIncrements
private method periodic takes nothing returns nothing
local location l
local location lu
if dirty == false then
set dirty = true
set tickIncrements = 18
set ticks = tickIncrements
set angle = GetUnitFacing(u)
set iterations = 0
endif
if startTick + ticks == T32_Tick then
if iterations == 8 then
set endTick = T32_Tick + tickIncrements
call SetUnitAnimation(u, "victory")
elseif iterations == 7 then
call SetUnitAnimation(u, "victory")
set ticks = ticks + R2I(tickIncrements * 5)
elseif iterations == 6 then
set ticks = ticks + R2I(tickIncrements * 2)
else
set lu = GetUnitLoc(u)
set l = PolarProjectionU(u, 700, 0 + iterations * 30)
call DominaWallEffectClone.create(u, l, AngleBetweenPoints(l , lu), R2I(tickIncrements * (6.5 - iterations)), 5 * tickIncrements, stat).startPeriodic()
set l = PolarProjectionU(u, 700, 180 + iterations * 30)
call DominaWallEffectClone.create(u, l, AngleBetweenPoints(l , lu), R2I(tickIncrements * (6.5 - iterations)), 5 * tickIncrements, stat).startPeriodic()
set ticks = ticks + tickIncrements
call RemoveLocation(lu)
set lu = null
set l = null
endif
set iterations = iterations + 1
endif
if UnitDead(u) then
set endTick = T32_Tick
endif
if endTick == T32_Tick then
set u = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes unit u, integer stat returns thistype
local thistype this = thistype.allocate()
set this.u = u
set this.stat = stat
set this.dirty = false
set this.startTick = T32_Tick
set this.endTick = 0
return this
endmethod
endstruct
struct DominaWallEffectC
private unit u
private integer stat
private integer iterations
private real angle
private boolean dirty
private integer startTick
private integer endTick
private integer ticks
private integer tickIncrements
private method periodic takes nothing returns nothing
local location l
local location lu
if dirty == false then
set dirty = true
set tickIncrements = 18
set ticks = tickIncrements
set angle = GetUnitFacing(u)
set iterations = 0
endif
if startTick + ticks == T32_Tick then
if iterations == 8 then
set endTick = T32_Tick + tickIncrements
call SetUnitAnimation(u, "victory")
elseif iterations == 7 then
call SetUnitAnimation(u, "victory")
set ticks = ticks + R2I(tickIncrements * 5)
elseif iterations == 6 then
set ticks = ticks + R2I(tickIncrements * 2)
else
set lu = GetUnitLoc(u)
set l = PolarProjectionU(u, 400, 0 + iterations * 30)
call DominaWallEffectClone.create(u, l, AngleBetweenPoints(lu, l), R2I(tickIncrements * (6.5 - iterations)), 5 * tickIncrements, stat).startPeriodic()
set l = PolarProjectionU(u, 400, 180 + iterations * 30)
call DominaWallEffectClone.create(u, l, AngleBetweenPoints(lu, l), R2I(tickIncrements * (6.5 - iterations)), 5 * tickIncrements, stat).startPeriodic()
set ticks = ticks + tickIncrements
call RemoveLocation(lu)
set lu = null
set l = null
endif
set iterations = iterations + 1
endif
if UnitDead(u) then
set endTick = T32_Tick
endif
if endTick == T32_Tick then
set u = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes unit u, integer stat returns thistype
local thistype this = thistype.allocate()
set this.u = u
set this.stat = stat
set this.dirty = false
set this.startTick = T32_Tick
set this.endTick = 0
return this
endmethod
endstruct
struct DominaWallEffectClone
private unit u
private unit dummy
private integer stat
private integer delay
private integer delay2
private real angle
private location l
private boolean dirty
private effect se
private integer startTick
private integer endTick
private integer ticks
private integer tickIncrements
private method periodic takes nothing returns nothing
local location lt
if dirty == false then
set dummy = CreateUnitAtLoc(GetOwningPlayer(u), 'n007', l, angle)
set se = AddSpecialEffectLoc("Abilities\\Spells\\Items\\AIil\\AIilTarget.mdl", l)
set dirty = true
endif
if startTick + delay == T32_Tick then
set lt = PolarProjectionBJ(l, 100, angle)
call IssuePointOrderLoc(dummy, "carrionswarm", lt)
call RemoveLocation(lt)
call DestroyEffect(se)
set lt = null
endif
if startTick + delay + delay2 / 2 == T32_Tick then
set angle = angle /*+ GetRandomInt(0, 1) **/ + 180
set se = AddSpecialEffectLoc("Abilities\\Spells\\Items\\AIil\\AIilTarget.mdl", l)
call BlzSetUnitFacingEx(dummy, angle)
endif
if startTick + delay + delay2 == T32_Tick then
set lt = PolarProjectionBJ(l, 100, angle)
call IssuePointOrderLoc(dummy, "carrionswarm", lt)
call RemoveLocation(lt)
set lt = null
set endTick = T32_Tick + 32
endif
if UnitDead(u) then
set endTick = T32_Tick
endif
if endTick == T32_Tick then
call RemoveUnit(dummy)
set dummy = null
call RemoveLocation(l)
set l = null
set u = null
set angle = angle
call DestroyEffect(se)
set se = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes unit u, location l, real angle, integer delay, integer delay2, integer stat returns thistype
local thistype this = thistype.allocate()
set this.u = u
set this.l = l
set this.angle = angle
set this.delay = delay
set this.delay2 = delay2
set this.stat = stat
set this.dirty = false
set this.startTick = T32_Tick
set this.endTick = 0
return this
endmethod
endstruct
function Trig_W8V2RG_AI_Conditions takes nothing returns boolean
return GetUnitTypeId(GetTriggerUnit()) == 'w821'
endfunction
function Trig_W8V2RG_AI_Actions takes nothing returns nothing
local real roll = GetRandomReal(0, 1)
if (roll < 0.1) then
call IssueImmediateOrder(GetTriggerUnit(), "creepthunderclap")
endif
endfunction
//===========================================================================
function InitTrig_W8V2RG_AI takes nothing returns nothing
set gg_trg_W8V2RG_AI = CreateTrigger( )
call DisableTrigger(gg_trg_W8V2RG_AI)
call TriggerRegisterAnyUnitEventBJ( gg_trg_W8V2RG_AI, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddCondition( gg_trg_W8V2RG_AI, Condition( function Trig_W8V2RG_AI_Conditions ) )
call TriggerAddAction( gg_trg_W8V2RG_AI, function Trig_W8V2RG_AI_Actions )
endfunction
function Trig_W8V2RG_AI_2_Conditions takes nothing returns boolean
return GetUnitTypeId(GetAttacker()) == 'w821'
endfunction
function Trig_W8V2RG_AI_2_Actions takes nothing returns nothing
local real roll = GetRandomReal(0, 1)
if (roll < 0.7) then
call IssueImmediateOrder(GetAttacker(), "creepthunderclap")
endif
endfunction
//===========================================================================
function InitTrig_W8V2RG_AI_2 takes nothing returns nothing
set gg_trg_W8V2RG_AI_2 = CreateTrigger( )
call DisableTrigger(gg_trg_W8V2RG_AI_2)
call TriggerRegisterAnyUnitEventBJ( gg_trg_W8V2RG_AI_2, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddCondition( gg_trg_W8V2RG_AI_2, Condition( function Trig_W8V2RG_AI_2_Conditions ) )
call TriggerAddAction( gg_trg_W8V2RG_AI_2, function Trig_W8V2RG_AI_2_Actions )
endfunction
function Trig_W8V2RGRockSlam_Actions takes nothing returns nothing
local integer stat = 200
local unit u = GetTriggerUnit()
local real angle = GetUnitFacing(u)
local location l = GetUnitLoc(u)
local location l2
local group g
local unit gu
call UnitPrompt(u, "Rock slam!")
call SetUnitTimeScale(u, 1.7)
//1 enemy target
set g = CreateGroup()
call GroupEnumUnitsInRangeOfLoc(g, l, 550, function EAnI_Filter)
set gu = FirstOfGroup(g)
if (gu != null) then
set l2 = GetUnitLoc(gu)
else
//fallback random
set l2 = PolarProjectionBJ(l, GetRandomReal(250, 450), GetUnitFacing(u) + GetRandomReal(-60, 60))
endif
call DestroyGroup(g)
set g = null
call RGRockSlamEffect.create(u, l2, stat).startPeriodic()
//1 close
set l2 = PolarProjectionBJ(l, GetRandomReal(100, 450), GetUnitFacing(u) + GetRandomReal(-45, 45))
call RGRockSlamEffect.create(u, l2, stat).startPeriodic()
//1 far
set l2 = PolarProjectionBJ(l, GetRandomReal(550, 850), GetUnitFacing(u) + GetRandomReal(-30, 30))
call RGRockSlamEffect.create(u, l2, stat).startPeriodic()
call RemoveLocation(l)
set u = null
set gu = null
set l = null
set l2 = null
endfunction
function Trig_W8V2RGRockSlam_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A02Z'
endfunction
//===========================================================================
function InitTrig_W8V2RGRockSlam takes nothing returns nothing
set gg_trg_W8V2RGRockSlam = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ(gg_trg_W8V2RGRockSlam, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition( gg_trg_W8V2RGRockSlam, Condition( function Trig_W8V2RGRockSlam_Conditions ) )
call TriggerAddAction( gg_trg_W8V2RGRockSlam, function Trig_W8V2RGRockSlam_Actions )
endfunction
struct RGRockSlamEffect
private unit u
private unit dummy
private unit dummyTarget
private real perTick
private integer stat
private real angle
private location target
private boolean dirty
private group g
private effect se
private integer startTick
private integer ticks
private integer ticks2
private real speedZ
private method periodic takes nothing returns nothing
local unit gu
local effect se
local location l
if dirty == false then
set l = GetUnitLoc(u)
set angle = AngleBetweenPoints(l, target)
set dummy = CreateUnit(GetOwningPlayer(u), 'h016', GetUnitX(u), GetUnitY(u), angle)
set dummyTarget = CreateUnitAtLoc(GetOwningPlayer(u), 'h00F', target, angle)
set speedZ = 600.0 / ticks2
call SetUnitFlyHeight(dummy, speedZ, 0)
call UnitApplyTimedLife(dummyTarget, 'BTLF', ticks / 32.0)
call UnitAddAbility(dummy, 'Amrf')
call UnitRemoveAbility(dummy, 'Amrf')
set perTick = DistanceBetweenPoints(target, l) * 1.0 / ticks
set g = CreateGroup()
set dirty = true
call RemoveLocation(l)
set l = null
endif
set l = PolarProjectionU(dummy, perTick, angle)
call SetUnitPositionLoc(dummy, l)
call RemoveLocation(l)
set l = null
if T32_Tick < startTick + ticks2 then
call SetUnitFlyHeight(dummy, 6000, speedZ * (startTick + ticks2 - T32_Tick))
elseif T32_Tick > startTick + ticks2 then
call SetUnitFlyHeight(dummy, 0, speedZ * (T32_Tick - startTick - ticks2))
endif
if startTick + ticks == T32_Tick then
set se = AddSpecialEffectLoc("abilities\\weapons\\catapult\\catapultmissile.mdl", target)
call BlzPlaySpecialEffect(se, ANIM_TYPE_DEATH)
call BlzSetSpecialEffectScale(se, 1)
call DestroyEffect(se)
set se = null
call GroupEnumUnitsInRangeOfLoc(g, target, 85, function True_Filter)
loop
set gu = FirstOfGroup(g)
exitwhen gu == null
call GroupRemoveUnit(g, gu)
if (IsUnitEnemy(gu,GetOwningPlayer(u)) and UnitAlive(gu)) then
call UnitDamageTargetBJ(u, gu, 3.0 * stat, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_ENHANCED)
endif
endloop
call RemoveUnit(dummy)
set dummy = null
call RemoveUnit(dummyTarget)
set dummyTarget = null
set u = null
set gu = null
call DestroyGroup(g)
set g = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes unit caster, location target, integer stat returns thistype
local thistype this = thistype.allocate()
set this.u = caster
set this.stat = stat
set this.target = target
set this.dirty = false
set this.ticks = R2I(1.5 / T32_PERIOD)
set this.ticks2 = ticks / 2
set this.startTick = T32_Tick
return this
endmethod
endstruct
function Trig_W8V2GWE_AI_Conditions takes nothing returns boolean
return GetUnitTypeId(GetAttacker()) == 'w822'
endfunction
function Trig_W8V2GWE_AI_Actions takes nothing returns nothing
local real roll = GetRandomReal(0, 1)
if (roll < 0.2) then
call IssueImmediateOrder(GetAttacker(), "roar")
elseif (roll < 0.4) then
call IssueImmediateOrder(GetAttacker(), "avatar")
endif
endfunction
//===========================================================================
function InitTrig_W8V2GWE_AI takes nothing returns nothing
set gg_trg_W8V2GWE_AI = CreateTrigger( )
call DisableTrigger(gg_trg_W8V2GWE_AI)
call TriggerRegisterAnyUnitEventBJ( gg_trg_W8V2GWE_AI, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddCondition( gg_trg_W8V2GWE_AI, Condition( function Trig_W8V2GWE_AI_Conditions ) )
call TriggerAddAction( gg_trg_W8V2GWE_AI, function Trig_W8V2GWE_AI_Actions )
endfunction
function Trig_W8V2GWESplash_Actions takes nothing returns nothing
local integer stat = 200
local integer i = 0
local unit u = GetTriggerUnit()
local real angle = GetUnitFacing(u)
local location l = GetUnitLoc(u)
local location l2
call UnitPrompt(u, "Splash")
call SetUnitTimeScale(u, 1.7)
set l2 = PolarProjectionBJ(l, 500, GetUnitFacing(u))
call GWESplashStrike.create(3, u, l2, stat).startPeriodic()
call RemoveLocation(l)
set u = null
set l = null
set l2 = null
endfunction
function Trig_W8V2GWESplash_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A02X'
endfunction
//===========================================================================
function InitTrig_W8V2GWESplash takes nothing returns nothing
set gg_trg_W8V2GWESplash = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ(gg_trg_W8V2GWESplash, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition( gg_trg_W8V2GWESplash, Condition( function Trig_W8V2GWESplash_Conditions ) )
call TriggerAddAction( gg_trg_W8V2GWESplash, function Trig_W8V2GWESplash_Actions )
endfunction
function Trig_W8V2GWESplashFinish_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A02X'
endfunction
function Trig_W8V2GWESplashFinish_Actions takes nothing returns nothing
call SetUnitTimeScale(GetTriggerUnit(), 1)
endfunction
//===========================================================================
function InitTrig_W8V2GWESplashFinish takes nothing returns nothing
set gg_trg_W8V2GWESplashFinish = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W8V2GWESplashFinish, EVENT_PLAYER_UNIT_SPELL_FINISH )
call TriggerAddCondition( gg_trg_W8V2GWESplashFinish, Condition( function Trig_W8V2GWESplashFinish_Conditions ) )
call TriggerAddAction( gg_trg_W8V2GWESplashFinish, function Trig_W8V2GWESplashFinish_Actions )
endfunction
struct GWESplashStrike
private unit caster
private unit targetingDummy
private location l
private integer stat
private integer endTick
private integer nextTick
private integer secondTick
private method periodic takes nothing returns nothing
local real x
local real y
local group g
local unit t
local effect se
if secondTick == T32_Tick then
set targetingDummy = CreateUnitAtLoc(GetOwningPlayer(caster), 'h00D', l, bj_UNIT_FACING )
call SetUnitScale(targetingDummy, 3, 3, 3)
endif
if nextTick == T32_Tick then
call RemoveUnit(targetingDummy)
set targetingDummy = null
if UnitAlive(caster) then
set se = AddSpecialEffectLoc("Objects\\Spawnmodels\\Naga\\NagaDeath\\NagaDeath.mdl", l)
call BlzSetSpecialEffectScale(se, 3)
call DestroyEffect(se)
set se = null
set x = GetLocationX(l)
set y = GetLocationY(l)
set g = CreateGroup()
call GroupEnumUnitsInRange(g, x, y, 300, function True_Filter)
loop
set t = FirstOfGroup(g)
exitwhen t == null
call GroupRemoveUnit(g, t)
if (IsUnitEnemy(t,GetOwningPlayer(caster)) and UnitAlive(t)) then
call UnitDamageTargetBJ( caster, t, 5.0 * stat, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC )
endif
set t = null
endloop
call DestroyGroup(g)
set g = null
endif
endif
if this.endTick == T32_Tick then
call RemoveLocation(l)
set caster = null
set l = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes real duration, unit caster, location l, integer stat returns thistype
local thistype this = thistype.allocate()
set this.caster = caster
set this.l = l
set this.stat = stat
set this.nextTick = T32_Tick + R2I(duration / T32_PERIOD)
set this.endTick = nextTick + 5
set this.secondTick = T32_Tick + 1
return this
endmethod
endstruct
function Trig_W8V2GWETsunami_Actions takes nothing returns nothing
local integer stat = 200
local integer i = 0
local unit u = GetTriggerUnit()
local real angle = GetUnitFacing(u)
local location l = GetUnitLoc(u)
local location l2
call UnitPrompt(u, "Tsunami")
call SetUnitTimeScale(u, 1.8)
loop
exitwhen i == 8
set l2 = PolarProjectionBJ(l, 150 + i * 150, angle)
call GWETsunamiStrike.create(2 + i * 0.1, u, l2, stat).startPeriodic()
set i = i + 1
endloop
call RemoveLocation(l)
set u = null
set l = null
set l2 = null
endfunction
function Trig_W8V2GWETsunami_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A02Y'
endfunction
//===========================================================================
function InitTrig_W8V2GWETsunami takes nothing returns nothing
set gg_trg_W8V2GWETsunami = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ(gg_trg_W8V2GWETsunami, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition( gg_trg_W8V2GWETsunami, Condition( function Trig_W8V2GWETsunami_Conditions ) )
call TriggerAddAction( gg_trg_W8V2GWETsunami, function Trig_W8V2GWETsunami_Actions )
endfunction
function Trig_W8V2GWETsunamiFinish_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A02Y'
endfunction
function Trig_W8V2GWETsunamiFinish_Actions takes nothing returns nothing
call SetUnitTimeScale(GetTriggerUnit(), 1)
endfunction
//===========================================================================
function InitTrig_W8V2GWETsunamiFinish takes nothing returns nothing
set gg_trg_W8V2GWETsunamiFinish = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W8V2GWETsunamiFinish, EVENT_PLAYER_UNIT_SPELL_FINISH )
call TriggerAddCondition( gg_trg_W8V2GWETsunamiFinish, Condition( function Trig_W8V2GWETsunamiFinish_Conditions ) )
call TriggerAddAction( gg_trg_W8V2GWETsunamiFinish, function Trig_W8V2GWETsunamiFinish_Actions )
endfunction
struct GWETsunamiStrike
private unit caster
private unit targetingDummy
private location l
private integer stat
private integer endTick
private integer nextTick
private integer secondTick
private method periodic takes nothing returns nothing
local real x
local real y
local group g
local unit t
local effect se
if secondTick == T32_Tick then
set targetingDummy = CreateUnitAtLoc(GetOwningPlayer(caster), 'h00F', l, bj_UNIT_FACING )
endif
if nextTick == T32_Tick then
call RemoveUnit(targetingDummy)
set targetingDummy = null
if UnitAlive(caster) then
set se = AddSpecialEffectLoc("Abilities\\Spells\\Other\\CrushingWave\\CrushingWaveDamage.mdl", l)
call BlzSetSpecialEffectScale(se, 2)
call DestroyEffect(se)
set se = null
set x = GetLocationX(l)
set y = GetLocationY(l)
set g = CreateGroup()
call GroupEnumUnitsInRange(g, x, y, 85, function True_Filter)
loop
set t = FirstOfGroup(g)
exitwhen t == null
call GroupRemoveUnit(g, t)
if (IsUnitEnemy(t,GetOwningPlayer(caster)) and UnitAlive(t)) then
call UnitDamageTargetBJ( caster, t, 3.0 * stat, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC )
endif
set t = null
endloop
call DestroyGroup(g)
set g = null
endif
endif
if this.endTick == T32_Tick then
call RemoveLocation(l)
set caster = null
set l = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes real duration, unit caster, location l, integer stat returns thistype
local thistype this = thistype.allocate()
set this.caster = caster
set this.l = l
set this.stat = stat
set this.nextTick = T32_Tick + R2I(duration / T32_PERIOD)
set this.endTick = nextTick + 5
set this.secondTick = T32_Tick + 1
return this
endmethod
endstruct
function Trig_W8V1WendigoClap_Actions takes nothing returns nothing
local integer stat = GetHeroStr(GetTriggerUnit(), true)
call BossPrompt(GetTriggerUnit(), "TRIPLE CLAP!")
call WendigoClapEffect.create(GetTriggerUnit(), stat).startPeriodic()
endfunction
function Trig_W8V1WendigoClap_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A01N'
endfunction
//===========================================================================
function InitTrig_W8V1WendigoClap takes nothing returns nothing
set gg_trg_W8V1WendigoClap = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W8V1WendigoClap, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_W8V1WendigoClap, Condition( function Trig_W8V1WendigoClap_Conditions ) )
call TriggerAddAction( gg_trg_W8V1WendigoClap, function Trig_W8V1WendigoClap_Actions )
endfunction
struct WendigoClapEffect
private unit u
private integer stat
private integer endTick
private integer nextTick
private integer iteration
private boolean dirty
private unit marker
private integer aoe
private method periodic takes nothing returns nothing
local location l
local integer i = 0
local unit dummy
if not dirty then
set dirty = true
set aoe = 175
set marker = CreateUnit(GetOwningPlayer(u), 'h00D', GetUnitX(u), GetUnitY(u), bj_UNIT_FACING)
call SetUnitScale(marker, aoe * 0.01, aoe * 0.01, aoe * 0.01)
endif
if nextTick == T32_Tick and UnitAlive(u) then
set l = GetUnitLoc(marker)
set dummy = CreateUnitAtLoc(GetOwningPlayer(u), 'h004', l, bj_UNIT_FACING)
call RemoveGuardPosition( dummy )
call UnitAddAbility(dummy, 'A01O')
call BlzSetAbilityRealLevelField(BlzGetUnitAbility(dummy, 'A01O'), ABILITY_RLF_AOE_DAMAGE, 0, stat * (2 + 1 * iteration))
call BlzSetAbilityRealLevelField(BlzGetUnitAbility(dummy, 'A01O'), ABILITY_RLF_AREA_OF_EFFECT, 0, aoe)
call IssueImmediateOrder(dummy, "thunderclap")
call UnitApplyTimedLifeBJ( 53.00, 'BTLF', dummy)
if (iteration < 2) then
set aoe = aoe + 110
call SetUnitPosition(marker, GetUnitX(u), GetUnitY(u))
call SetUnitScale(marker, aoe * 0.01, aoe * 0.01, aoe * 0.01)
else
call RemoveUnit(marker)
set marker = null
endif
set this.nextTick = T32_Tick + 32
set this.iteration = iteration + 1
call RemoveLocation (l)
set l = null
set dummy = null
endif
if this.endTick == T32_Tick then
set u = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes unit wendigo, integer stat returns thistype
local thistype this = thistype.allocate()
set this.u = wendigo
set this.dirty = false
set this.nextTick = T32_Tick + 32
set this.stat = stat
set this.endTick = T32_Tick + R2I(3.5 / T32_PERIOD)
set this.iteration = 0
return this
endmethod
endstruct
function Trig_W7KnightCommanderBreaktrough_Actions takes nothing returns nothing
local integer stat = GetHeroStr(GetTriggerUnit(), true)
call BossPrompt(GetTriggerUnit(), "BREAKTROUGH!")
call KnightBreaktroughEffect.create(GetTriggerUnit(), stat).startPeriodic()
endfunction
function Trig_W7KnightCommanderBreaktrough_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A02W'
endfunction
//===========================================================================
function InitTrig_W7KnightCommanderBreaktrough takes nothing returns nothing
set gg_trg_W7KnightCommanderBreaktrough = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W7KnightCommanderBreaktrough, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_W7KnightCommanderBreaktrough, Condition( function Trig_W7KnightCommanderBreaktrough_Conditions ) )
call TriggerAddAction( gg_trg_W7KnightCommanderBreaktrough, function Trig_W7KnightCommanderBreaktrough_Actions )
endfunction
struct KnightBreaktroughEffect
private unit u
private location ls
private location lt
private boolean started
private integer firstTick
private integer stat
private integer ticks
private real incrementX
private real incrementY
private real dmg
private effect se
private method periodic takes nothing returns nothing
local real angle
local real distance
local PlayableArea pa
local unit gu
local group g
if (this.started == false) then
set started = true
set distance = 700
set angle = GetUnitFacing(u)
set lt = PolarProjectionBJ(ls, distance, angle)
//IF CURRENT DISTANCE WOULD BE OUTSIDE, BIN SEARCH A SHORTER DISTANCE THAT'S INSIDE. but only if the unit started inside the playable are in the first place
set pa = udg_CURRENT_PLAYABLE_AREA
if (pa.containsLocation(ls)) then
loop
exitwhen pa.containsLocation(lt)
set distance = distance * 0.5
call RemoveLocation(lt)
set lt = PolarProjectionBJ(ls, distance, angle)
endloop
endif
set firstTick = T32_Tick
set ticks = MathRound(1.5 * 32)
set incrementX = 0.66666 * (GetLocationX(lt) - GetLocationX(ls)) / ticks
set incrementY = 0.66666 * (GetLocationY(lt) - GetLocationY(ls)) / ticks
set dmg = stat * 0.2
set se = AddSpecialEffectTarget("Abilities\\Spells\\Orc\\Shockwave\\ShockwaveMissile.mdl", u, "origin")
call BlzSetSpecialEffectScale(se, 1.0)
endif
//speed up
if this.firstTick + (ticks * 1 / 2) == T32_Tick then
set incrementX = incrementX * 2
set incrementY = incrementY * 2
set dmg = dmg * 3
endif
if (u != null and UnitAlive(u)) then
call SetUnitX(u, GetUnitX(u) + incrementX)
call SetUnitY(u, GetUnitY(u) + incrementY)
set g = CreateGroup()
call GroupEnumUnitsInRange(g, GetUnitX(u), GetUnitY(u), 100, function True_Filter)
loop
set gu = FirstOfGroup(g)
exitwhen gu == null
call GroupRemoveUnit(g, gu)
if IsUnitEnemy(gu, GetOwningPlayer(u)) and UnitAlive(gu) and GetUnitAbilityLevel(gu,'Avul') < 1 then
call UnitDamageTarget(u, gu, dmg, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_METAL_HEAVY_SLICE)
exitwhen true
endif
endloop
else
set ticks = T32_Tick - firstTick
endif
if this.firstTick + ticks == T32_Tick then
set u = null
call RemoveLocation(lt)
call RemoveLocation(ls)
call DestroyEffect(se)
set se = null
set lt = null
set ls = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes unit u, integer stat returns thistype
local thistype this = thistype.allocate()
set this.u = u
set this.stat = stat
set ls = GetUnitLoc(u)
set started = false
return this
endmethod
endstruct
function Trig_W7RainPreload_Actions takes nothing returns nothing
local unit u = PreloadUnit('h013')
call IssuePointOrder(u, "blizzard", GetUnitX(u) + 100, GetUnitY(u))
set u = null
endfunction
//===========================================================================
function InitTrig_W7RainPreload takes nothing returns nothing
set gg_trg_W7RainPreload = CreateTrigger( )
call TriggerRegisterTimerEventSingle( gg_trg_W7RainPreload, 5 )
call TriggerAddAction( gg_trg_W7RainPreload, function Trig_W7RainPreload_Actions )
endfunction
function Trig_W7V1FurbolgRain_Actions takes nothing returns nothing
local integer stat
local unit target
local unit u
local group g
local real x
local real y
set u = GetTriggerUnit()
set x = GetUnitX(u)
set y = GetUnitY(u)
set stat = GetHeroStatBJ(bj_HEROSTAT_INT, u, true)
call BossPrompt(GetTriggerUnit(), "Frigid Rain")
set g = CreateGroup()
call GroupEnumUnitsInRange(g, x, y, 1200, function EAnI_Filter)
loop
set target = FirstOfGroup(g)
exitwhen target == null
call GroupRemoveUnit(g, target)
call FurbolgRainStrike.create(u, GetUnitLoc(target), stat).startPeriodic()
endloop
call DestroyGroup(g)
set g = null
set u = null
set target = null
endfunction
function Trig_W7V1FurbolgRain_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A01L'
endfunction
//===========================================================================
function InitTrig_W7V1FurbolgRain takes nothing returns nothing
set gg_trg_W7V1FurbolgRain = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W7V1FurbolgRain, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_W7V1FurbolgRain, Condition( function Trig_W7V1FurbolgRain_Conditions ) )
call TriggerAddAction( gg_trg_W7V1FurbolgRain, function Trig_W7V1FurbolgRain_Actions )
endfunction
struct FurbolgRainStrike
private unit caster
private unit targetingDummy
private location l
private integer stat
private unit dummy
private integer endTick
private integer nextTick
private integer secondTick
private method periodic takes nothing returns nothing
//local unit dummy
if secondTick == T32_Tick then
set targetingDummy = CreateUnitAtLoc(GetOwningPlayer(caster), 'h00F', l, bj_UNIT_FACING)
set dummy = CreateUnitAtLoc(GetOwningPlayer(caster), 'h004', l, bj_UNIT_FACING )
call UnitAddAbility(dummy, 'A01M')
call BlzSetAbilityRealLevelField(BlzGetUnitAbility(dummy, 'A01M'), ABILITY_RLF_DAMAGE_HBZ2, 0, stat) //1x int
call UnitApplyTimedLife(dummy, 'BTLF', 10.0)
endif
if nextTick == T32_Tick then
call RemoveUnit(targetingDummy)
set targetingDummy = null
call RemoveGuardPosition(dummy)
call IssuePointOrderLoc(dummy, "blizzard", l)
set dummy = null
endif
if this.endTick == T32_Tick then
call RemoveLocation(l)
set caster = null
set l = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes unit caster, location l, integer stat returns thistype
local thistype this = thistype.allocate()
set this.caster = caster
set this.l = l
set this.stat = stat
set this.endTick = T32_Tick + R2I(15 / T32_PERIOD)
set this.nextTick = T32_Tick + R2I(1.5 / T32_PERIOD)
set this.secondTick = T32_Tick + 1
return this
endmethod
endstruct
struct BmIllusionBladestormEffect
private unit u
private unit caster
private real stat
private real angle
private integer endTick
private real incrementX
private real incrementY
private real dmg
private effect se
private method periodic takes nothing returns nothing
call PolarProjectionUU(u, u, 8, angle)
if this.endTick == T32_Tick then
call RemoveUnit(u)
set u = null
set caster = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes unit caster, unit u, real angle, real stat returns thistype
local thistype this = thistype.allocate()
set this.caster = caster
set this.u = u
set this.angle = angle
set this.stat = stat
set endTick = T32_Tick + R2I(6.0 / T32_PERIOD)
return this
endmethod
endstruct
function Trig_W6V3_IllusionBladestorm_Actions takes nothing returns nothing
local integer stat
local unit u
local unit dummy
local integer i = 0
local real angle
local location l
set u = GetTriggerUnit()
set stat = GetHeroStatBJ(bj_HEROSTAT_AGI, u, true)
call BossPrompt(GetTriggerUnit(), "Bladestorm")
set angle = GetRandomReal(0, 360)
loop
exitwhen i == 3
set l = PolarProjectionU(u, 100, angle)
set dummy = CreateUnitAtLoc(GetOwningPlayer(u), 'h01M', l, angle)
call BlzSetAbilityRealLevelField(BlzGetUnitAbility(dummy, 'A03X'), ABILITY_RLF_DAMAGE_PER_SECOND_OWW1, 0, stat)
call BlzSetAbilityRealLevelField(BlzGetUnitAbility(dummy, 'A03X'), ABILITY_RLF_DAMAGE_PER_SECOND_OWW1, 1, stat)
call IncUnitAbilityLevel(dummy, 'A03X')
call DecUnitAbilityLevel(dummy, 'A03X')
call IssueImmediateOrder(dummy, "whirlwind")
call UnitApplyTimedLife(dummy, 'BTLF', 20.00)
call SetUnitVertexColor(dummy, 255, 255, 255, 60)
call BmIllusionBladestormEffect.create(u, dummy, angle, stat).startPeriodic()
set i = i + 1
set angle = angle + GetRandomReal(45, 75)
call RemoveLocation(l)
endloop
set l = null
set u = null
set dummy = null
endfunction
function Trig_W6V3_IllusionBladestorm_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A03Y'
endfunction
//===========================================================================
function InitTrig_W6V3_IllusionBladestorm takes nothing returns nothing
set gg_trg_W6V3_IllusionBladestorm = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W6V3_IllusionBladestorm, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_W6V3_IllusionBladestorm, Condition( function Trig_W6V3_IllusionBladestorm_Conditions ) )
call TriggerAddAction( gg_trg_W6V3_IllusionBladestorm, function Trig_W6V3_IllusionBladestorm_Actions )
endfunction
function Trig_W6V3_CritsSplash_Conditions takes nothing returns boolean
return GetUnitTypeId(udg_DamageEventSource) == 'H01L' and udg_IsDamageAttack and GetUnitAbilityLevel(udg_DamageEventSource, 'A03W') > 0
endfunction
function Trig_W6V3_CritsSplash_filter takes nothing returns boolean
local boolean retval
local unit u = GetFilterUnit()
local player p = GetOwningPlayer(udg_DamageEventSource)
set retval = IsUnitEnemy(u,p) and UnitAlive(u) and GetUnitAbilityLevel(u,'Avul') < 1
set u = null
set p = null
return retval
endfunction
function Trig_W6V3_CritsSplash_Actions takes nothing returns nothing
local integer stat
local location l
local unit u
local unit t
local group g
local real x
local real y
set u = udg_DamageEventSource
set l = GetUnitLoc(udg_DamageEventTarget)
set x = GetUnitX(udg_DamageEventTarget)
set y = GetUnitY(udg_DamageEventTarget)
set g = CreateGroup()
call GroupEnumUnitsInRange(g, x, y, 200, function Trig_W6V3_CritsSplash_filter)
call GroupRemoveUnit(g, udg_DamageEventTarget)
loop
set t = FirstOfGroup(g)
exitwhen t == null
call GroupRemoveUnit(g, t)
call UnitDamageTarget(u, t, 0.5 * udg_DamageEventAmount, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
endloop
call RemoveLocation(l)
call DestroyGroup(g)
set l = null
set g = null
set u = null
endfunction
//===========================================================================
function InitTrig_W6V3_CritsSplash takes nothing returns nothing
set gg_trg_W6V3_CritsSplash = CreateTrigger( )
call DisableTrigger( gg_trg_W6V3_CritsSplash )
call TriggerAddCondition(gg_trg_W6V3_CritsSplash, function Trig_W6V3_CritsSplash_Conditions )
call TriggerRegisterVariableEvent( gg_trg_W6V3_CritsSplash, "udg_DamageEvent", EQUAL, 1.00 )
call TriggerAddAction( gg_trg_W6V3_CritsSplash, function Trig_W6V3_CritsSplash_Actions )
endfunction
function Trig_W6V3_AI_Crits_Conditions takes nothing returns boolean
return (udg_SeniorPaladinPhase == 0 and GetUnitTypeId(GetAttackedUnitBJ()) == 'H01L' and GetUnitLifePercent(GetAttackedUnitBJ()) < 55.00)
endfunction
function Trig_W6V3_AI_Crits_Actions takes nothing returns nothing
local unit u = GetTriggerUnit()
call DisableTrigger(gg_trg_W6V3_AI_Crits)
call BossPrompt(u, "OOOOOH")
call UnitAddAbility(u, 'A03W')
call EnableTrigger(gg_trg_W6V3_CritsSplash)
set u = null
endfunction
//===========================================================================
function InitTrig_W6V3_AI_Crits takes nothing returns nothing
set gg_trg_W6V3_AI_Crits = CreateTrigger( )
//call DisableTrigger( gg_trg_W6V3_AI_Crits )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W6V3_AI_Crits, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddCondition( gg_trg_W6V3_AI_Crits, Condition( function Trig_W6V3_AI_Crits_Conditions ) )
call TriggerAddAction( gg_trg_W6V3_AI_Crits, function Trig_W6V3_AI_Crits_Actions )
endfunction
function Trig_W6V3_AI_Warlock_Conditions takes nothing returns boolean
return GetUnitTypeId(GetAttacker()) == 'w632' and BlzGetUnitAbilityCooldownRemaining(GetAttacker(), 'A02O') == 0.0 and GetUnitCurrentOrder(GetAttacker()) != OrderId("firebolt")
endfunction
function Trig_W6V3_AI_Warlock_Actions takes nothing returns nothing
local unit u = GetTriggerUnit()
local unit t
if (GetRandomReal(0, 1) < 0.50) then
set t = highestAggroInRange(u, 700)
if t == null then
set t = randomEnemyInRange(u, 700)
endif
if t != null then
call IssueTargetOrder(GetTriggerUnit(), "firebolt", t)
set t = null
endif
endif
set u = null
endfunction
//===========================================================================
function InitTrig_W6V3_AI_Warlock takes nothing returns nothing
set gg_trg_W6V3_AI_Warlock = CreateTrigger( )
call DisableTrigger(gg_trg_W6V3_AI_Warlock)
call TriggerRegisterAnyUnitEventBJ( gg_trg_W6V3_AI_Warlock, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddCondition( gg_trg_W6V3_AI_Warlock, Condition( function Trig_W6V3_AI_Warlock_Conditions ) )
call TriggerAddAction( gg_trg_W6V3_AI_Warlock, function Trig_W6V3_AI_Warlock_Actions )
endfunction
function Trig_W6V2_AI_Conditions takes nothing returns boolean
return GetUnitTypeId(GetAttacker()) == 'H00Z' and BlzGetUnitAbilityCooldownRemaining(GetAttacker(), 'A02U') == 0.0 and GetUnitCurrentOrder(GetAttacker()) != OrderId("curse")
endfunction
function Trig_W6V2_AI_Actions takes nothing returns nothing
local unit c
local group g = CreateGroup()
local unit u = GetAttacker()
local location l = GetUnitLoc(u)
local player p = GetOwningPlayer(u)
call GroupEnumUnitsInRangeOfLoc(g, l, 700, function True_Filter)
loop
set c = FirstOfGroup(g)
exitwhen c == null
call GroupRemoveUnit(g, c)
if (IsUnitEnemy(c, p) and UnitAlive(c) and GetUnitAbilityLevel(c,'Avul') < 1 and GetUnitAbilityLevel(c, 'B00F') < 1) then
exitwhen true
endif
endloop
if (c != null) then
call IssueTargetOrder(u, "curse", c)
endif
call DestroyGroup(g)
call RemoveLocation(l)
set l = null
set u = null
set c = null
set g = null
set p = null
endfunction
//===========================================================================
function InitTrig_W6V2_AI takes nothing returns nothing
set gg_trg_W6V2_AI = CreateTrigger( )
call DisableTrigger( gg_trg_W6V2_AI )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W6V2_AI, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddCondition( gg_trg_W6V2_AI, Condition( function Trig_W6V2_AI_Conditions ) )
call TriggerAddAction( gg_trg_W6V2_AI, function Trig_W6V2_AI_Actions )
endfunction
function Trig_W6SpyMasterMarkTarget_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A02U'
endfunction
function Trig_W6SpyMasterMarkTarget_Actions takes nothing returns nothing
call BossPrompt(GetTriggerUnit(), "Mark target...")
endfunction
//===========================================================================
function InitTrig_W6SpyMasterMarkTarget takes nothing returns nothing
set gg_trg_W6SpyMasterMarkTarget = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W6SpyMasterMarkTarget, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_W6SpyMasterMarkTarget, Condition( function Trig_W6SpyMasterMarkTarget_Conditions ) )
call TriggerAddAction( gg_trg_W6SpyMasterMarkTarget, function Trig_W6SpyMasterMarkTarget_Actions )
endfunction
struct MasterAndPetBinding
public unit master
public unit pet
private real noise = GetRandomReal(0, 90)
private method periodic takes nothing returns nothing
local group g
local integer i = 0
local unit dummy
local unit gu
if UnitAlive(master) then
call PolarProjectionUU(master, pet, 175, noise + ModuloInteger(T32_Tick, 240) * 1.5)
else
call KillUnit(pet)
set master = null
set pet = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes unit master, unit pet returns thistype
local thistype this = thistype.allocate()
set this.master = master
set this.pet = pet
set noise = GetRandomReal(0, 90)
return this
endmethod
endstruct
struct PetAttackBuffed
private unit pet
private integer stat
private integer nextTick
private integer buffcode
private method periodic takes nothing returns nothing
local group g
local unit dummy
local unit gu
if this.nextTick == T32_Tick then
if UnitAlive(pet) then
set g = CreateGroup()
call GroupEnumUnitsInRange(g, GetUnitX(pet), GetUnitY(pet), 1000, function True_Filter)
loop
set gu = FirstOfGroup(g)
exitwhen gu == null
call GroupRemoveUnit(g, gu)
if IsUnitEnemy(gu, GetOwningPlayer(pet)) and UnitAlive(gu) and GetUnitAbilityLevel(gu,'Avul') < 1 and GetUnitAbilityLevel(gu, buffcode) > 0 then
set dummy = CreateUnit(GetOwningPlayer(pet), 'h010', GetUnitX(pet), GetUnitY(pet), bj_UNIT_FACING)
call BlzSetUnitWeaponIntegerField(dummy, UNIT_WEAPON_IF_ATTACK_DAMAGE_BASE, 0, MathRound(stat * 0.6))
call UnitApplyTimedLife(dummy, 'BTLF', 1.00)
call IssueTargetOrder(dummy, "attack", gu)
endif
endloop
set nextTick = nextTick + 45
else
set pet = null
call this.stopPeriodic()
call this.destroy()
endif
endif
endmethod
implement T32x
static method create takes unit pet, integer stat, integer buffcode returns thistype
local thistype this = thistype.allocate()
set this.pet = pet
set this.stat = stat
set this.nextTick = T32_Tick + 45
set this.buffcode = buffcode
return this
endmethod
endstruct
function Trig_W6SpyMasterCreatePet_Actions takes nothing returns nothing
local unit boss = FirstOfGroup(udg_BossesInPlay)
local unit pet
local MasterAndPetBinding mapb
if (boss == null or GetUnitTypeId(boss) != 'H00Z') then
set boss = null
return
endif
set pet = CreateUnit(GetOwningPlayer(boss), 'h011', GetUnitX(boss), GetUnitY(boss), bj_UNIT_FACING)
call UnitAddAbility(pet, 'Amrf')
call UnitRemoveAbility(pet, 'Amrf')
call SetUnitFlyHeight(pet, 200, 2000)
set mapb = MasterAndPetBinding.create(boss, pet)
call mapb.startPeriodic()
call PetAttackBuffed.create(pet, GetHeroInt(boss, true), 'B00F').startPeriodic()
call DisableTrigger(GetTriggeringTrigger())
endfunction
//===========================================================================
function InitTrig_W6SpyMasterCreatePet takes nothing returns nothing
set gg_trg_W6SpyMasterCreatePet = CreateTrigger( )
call DisableTrigger( gg_trg_W6SpyMasterCreatePet )
call TriggerRegisterTimerEventPeriodic( gg_trg_W6SpyMasterCreatePet, 2.00)
call TriggerAddAction( gg_trg_W6SpyMasterCreatePet, function Trig_W6SpyMasterCreatePet_Actions )
endfunction
function Trig_W6V1TurtleBreathOfFire_Actions takes nothing returns nothing
local integer stat = GetHeroStatBJ(bj_HEROSTAT_INT, GetTriggerUnit(), true)
call BossPrompt(GetTriggerUnit(), "BREATH OF FIRE!")
call TurtleBreathOfFireEffect.create(5.0, GetTriggerUnit(), stat).startPeriodic()
endfunction
function Trig_W6V1TurtleBreathOfFire_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A01J'
endfunction
//===========================================================================
function InitTrig_W6V1TurtleBreathOfFire takes nothing returns nothing
set gg_trg_W6V1TurtleBreathOfFire = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W6V1TurtleBreathOfFire, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_W6V1TurtleBreathOfFire, Condition( function Trig_W6V1TurtleBreathOfFire_Conditions ) )
call TriggerAddAction( gg_trg_W6V1TurtleBreathOfFire, function Trig_W6V1TurtleBreathOfFire_Actions )
endfunction
struct TurtleBreathOfFireEffect
private unit u
private integer stat
private integer endTick
private integer nextTick
private method periodic takes nothing returns nothing
local location l
local location lt
local integer i = 0
local unit dummy
if nextTick == T32_Tick and UnitAlive(u) then
set l = GetUnitLoc(u)
set dummy = CreateUnitAtLoc(GetOwningPlayer(u), 'h004', l, bj_UNIT_FACING )
call RemoveGuardPosition( dummy )
call UnitAddAbility(dummy, 'A01K')
call BlzSetAbilityRealLevelField( BlzGetUnitAbility(dummy, 'A01K'), ABILITY_RLF_DAMAGE_UCS1, 0, stat * 1.25) //5x int
set lt = PolarProjectionBJ(l, 50, GetUnitFacing(u))
call IssuePointOrderLoc( dummy, "breathoffire", lt)
call UnitApplyTimedLife(dummy, 'BTLF', 5.0)
set this.nextTick = T32_Tick + 32
call RemoveLocation (l)
call RemoveLocation (lt)
set l = null
set lt = null
set dummy = null
endif
if this.endTick == T32_Tick then
set u = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes real duration, unit turtle, integer stat returns thistype
local thistype this = thistype.allocate()
set this.u = turtle
set this.nextTick = T32_Tick + 32
set this.stat = stat
set this.endTick = T32_Tick + R2I(duration / T32_PERIOD)
return this
endmethod
endstruct
function Trig_W5KhanH_Actions takes nothing returns nothing
local unit u = udg_UnitSpawned
if GetUnitTypeId(u) == 'H01F' and Difficulty.level > 2 then
call UnitAddAbility(u, 'A03J')
endif
set u = null
endfunction
//===========================================================================
function InitTrig_W5KhanH takes nothing returns nothing
set gg_trg_W5KhanH = CreateTrigger( )
call DisableTrigger( gg_trg_W5KhanH )
call TriggerRegisterVariableEvent( gg_trg_W5KhanH, "udg_OnUnitSpawn", EQUAL, 1.00 )
call TriggerAddAction( gg_trg_W5KhanH, function Trig_W5KhanH_Actions )
endfunction
function Trig_W5KhanRumble_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A03L'
endfunction
function Trig_W5KhanRumble_Actions takes nothing returns nothing
local unit caster = GetTriggerUnit()
local unit lcu = CreateUnit(GetOwningPlayer(caster), 'h004', GetUnitX(caster), GetUnitY(caster), bj_UNIT_FACING)
call BossPrompt(caster, "RUMBLE")
call UnitApplyTimedLifeBJ(12.00, 'BTLF', lcu)
call UnitAddAbility(lcu, 'S000')
call IssuePointOrder(lcu, "earthquake", GetUnitX(caster), GetUnitY(caster))
set caster = null
set lcu = null
endfunction
//===========================================================================
function InitTrig_W5KhanRumble takes nothing returns nothing
set gg_trg_W5KhanRumble = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W5KhanRumble, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_W5KhanRumble, Condition( function Trig_W5KhanRumble_Conditions ) )
call TriggerAddAction( gg_trg_W5KhanRumble, function Trig_W5KhanRumble_Actions )
endfunction
function Trig_W5V3_AI_Run_Away_Actions takes nothing returns nothing
local group g = CreateGroup()
local unit u = GetTriggerUnit()
local real avgx = 0
local real avgy = 0
local integer count = 0
local unit gu
local real angle
//avg position of enemy units
call GroupEnumUnitsInRange(g, GetUnitX(u), GetUnitY(u), 700, function EAnI_Filter)
loop
set gu = FirstOfGroup(g)
exitwhen gu == null
call GroupRemoveUnit(g, gu)
set count = count + 1
set avgx = avgx + GetUnitX(gu)
set avgy = avgy + GetUnitY(gu)
endloop
set gu = null
set avgx = avgx / count
set avgy = avgy / count
set angle = bj_RADTODEG * Atan2(GetUnitY(u) - avgy, GetUnitX(u) - avgx)
call IssuePointOrderLoc(u, "move", PolarProjectionU(u, GetRandomReal(250, 350), angle))
call DestroyGroup(g)
set g = null
set u = null
endfunction
function Trig_W5V3_AI_Run_Away_Conditions takes nothing returns boolean
return GetUnitTypeId(GetTriggerUnit()) == 'w531' or GetUnitTypeId(GetTriggerUnit()) == 'w532'
endfunction
//===========================================================================
function InitTrig_W5V3_AI_Run_Away takes nothing returns nothing
set gg_trg_W5V3_AI_Run_Away = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W5V3_AI_Run_Away, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddCondition( gg_trg_W5V3_AI_Run_Away, Condition( function Trig_W5V3_AI_Run_Away_Conditions ) )
call TriggerAddAction( gg_trg_W5V3_AI_Run_Away, function Trig_W5V3_AI_Run_Away_Actions )
endfunction
function Trig_W5V3_CentaurH_Actions takes nothing returns nothing
local unit u = udg_UnitSpawned
local real range = BlzGetUnitWeaponRealField(u, UNIT_WEAPON_RF_ATTACK_RANGE, 0) + 550.0
if GetUnitTypeId(u) == 'w531' and Difficulty.level > 2 then
call SetUnitAcquireRange(u, range)
call BlzSetUnitWeaponRealField(u, UNIT_WEAPON_RF_ATTACK_RANGE, 0, range)
call BlzSetUnitWeaponRealField(u, UNIT_WEAPON_RF_ATTACK_RANGE, 1, range)
call UnitAddAbility(u, 'A03M')
call IssueImmediateOrder(u, "coldarrows")
endif
if GetUnitTypeId(u) == 'w532' and Difficulty.level > 2 then
call SetUnitAcquireRange(u, range)
call BlzSetUnitWeaponRealField(u, UNIT_WEAPON_RF_ATTACK_RANGE, 0, range - 300)
call BlzSetUnitWeaponRealField(u, UNIT_WEAPON_RF_ATTACK_RANGE, 1, range - 300)
endif
set u = null
endfunction
//===========================================================================
function InitTrig_W5V3_CentaurH takes nothing returns nothing
set gg_trg_W5V3_CentaurH = CreateTrigger( )
call DisableTrigger( gg_trg_W5V3_CentaurH )
call TriggerRegisterVariableEvent( gg_trg_W5V3_CentaurH, "udg_OnUnitSpawn", EQUAL, 1.00 )
call TriggerAddAction( gg_trg_W5V3_CentaurH, function Trig_W5V3_CentaurH_Actions )
endfunction
function Trig_W5FootiesH_Actions takes nothing returns nothing
local unit u = udg_UnitSpawned
if (GetUnitTypeId(u) == 'w421' or GetUnitTypeId(u) == 'w422') and Difficulty.level > 2 then
call UnitAddAbility(u, 'A03O')
endif
set u = null
endfunction
//===========================================================================
function InitTrig_W5FootiesH takes nothing returns nothing
set gg_trg_W5FootiesH = CreateTrigger( )
call DisableTrigger( gg_trg_W5FootiesH )
call TriggerRegisterVariableEvent( gg_trg_W5FootiesH, "udg_OnUnitSpawn", EQUAL, 1.00 )
call TriggerAddAction( gg_trg_W5FootiesH, function Trig_W5FootiesH_Actions )
endfunction
function Trig_W5V2_AI_Rally_Actions takes nothing returns nothing
local unit boss = FirstOfGroup(udg_BossesInPlay)
if (boss == null) then
return
endif
if (DistanceBetweenUnits(GetTriggerUnit(), boss) < 400 and IsUnitAlly(GetTriggerUnit(), GetOwningPlayer(boss))) then
call IssueImmediateOrder(boss, "thunderclap")
endif
set boss = null
endfunction
//===========================================================================
function InitTrig_W5V2_AI_Rally takes nothing returns nothing
set gg_trg_W5V2_AI_Rally = CreateTrigger( )
call DisableTrigger( gg_trg_W5V2_AI_Rally )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W5V2_AI_Rally, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddAction( gg_trg_W5V2_AI_Rally, function Trig_W5V2_AI_Rally_Actions )
endfunction
function W5CaptainRallyProtectLoopC takes nothing returns nothing
local unit boss = FirstOfGroup(udg_BossesInPlay)
local unit u = GetEnumUnit()
//group order again?
if (DistanceBetweenUnits(boss, u) > 350) then
// regroup
call IssuePointOrder(u, "move", GetUnitX(boss), GetUnitY(boss))
else
// do your thing
call IssuePointOrder(u, "attack", GetUnitX(boss), GetUnitY(boss))
endif
set u = null
set boss = null
endfunction
function Trig_W5CaptainRallyProtectLoop_Actions takes nothing returns nothing
call ForGroup(udg_AMOVE_GROUPS[20], function W5CaptainRallyProtectLoopC)
endfunction
//===========================================================================
function InitTrig_W5CaptainRallyProtectLoop takes nothing returns nothing
set gg_trg_W5CaptainRallyProtectLoop = CreateTrigger( )
call DisableTrigger( gg_trg_W5CaptainRallyProtectLoop )
call TriggerRegisterTimerEventPeriodic( gg_trg_W5CaptainRallyProtectLoop, 1.00 )
call TriggerAddAction( gg_trg_W5CaptainRallyProtectLoop, function Trig_W5CaptainRallyProtectLoop_Actions )
endfunction
function Trig_W5CaptainRally_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A02T'
endfunction
function Trig_W5CaptainRally_Actions takes nothing returns nothing
local unit caster = GetTriggerUnit()
local unit u
local player p = GetOwningPlayer(caster)
local group g = CreateGroup()
local CaptainRallyEffect cre
call BossPrompt(caster, "RALLY!")
call GroupEnumUnitsInRange(g, GetUnitX(caster), GetUnitY(caster), 700, function AAnI_Filter)
loop
set u = FirstOfGroup(g)
exitwhen u == null
call GroupRemoveUnit(g, u)
call MoveCreepToG20(u)
endloop
set cre = CaptainRallyEffect.create(caster, GetHeroInt(caster, true), 500)
call SaveInteger(udg_UtilMap, GetHandleId(caster), 0, cre)
call cre.startPeriodic()
call DestroyGroup(g)
set g = null
set u = null
set p = null
set caster = null
endfunction
//===========================================================================
function InitTrig_W5CaptainRally takes nothing returns nothing
set gg_trg_W5CaptainRally = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W5CaptainRally, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_W5CaptainRally, Condition( function Trig_W5CaptainRally_Conditions ) )
call TriggerAddAction( gg_trg_W5CaptainRally, function Trig_W5CaptainRally_Actions )
endfunction
function Trig_W5CaptainRallyFinishCast_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A02T'
endfunction
function Trig_W5CaptainRallyFinishCast_Actions takes nothing returns nothing
local CaptainRallyEffect cre
local unit u
set cre = LoadInteger(udg_UtilMap, GetHandleId(GetTriggerUnit()), 0)
if (cre != 0) then
call cre.end()
call FlushChildHashtable(udg_UtilMap, GetHandleId(GetTriggerUnit()))
endif
loop
set u = FirstOfGroup(udg_AMOVE_GROUPS[20])
exitwhen u == null
call GroupRemoveUnit(udg_AMOVE_GROUPS[20], u)
call RegisterCreep(u)
endloop
endfunction
//===========================================================================
function InitTrig_W5CaptainRallyFinishCast takes nothing returns nothing
set gg_trg_W5CaptainRallyFinishCast = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ( gg_trg_W5CaptainRallyFinishCast, EVENT_PLAYER_UNIT_SPELL_ENDCAST )
call TriggerAddCondition( gg_trg_W5CaptainRallyFinishCast, Condition( function Trig_W5CaptainRallyFinishCast_Conditions ) )
call TriggerAddAction( gg_trg_W5CaptainRallyFinishCast, function Trig_W5CaptainRallyFinishCast_Actions )
endfunction
struct CaptainRallyEffect
private unit u
private integer stat
private real range
public method end takes nothing returns nothing
set u = null
call this.stopPeriodic()
call this.destroy()
endmethod
private method periodic takes nothing returns nothing
local group g
local location l
local unit t
local effect se
if ModuloInteger(T32_Tick, 74) == 0 then
set g = CreateGroup()
call GroupEnumUnitsInRange(g, GetUnitX(u), GetUnitY(u), range, function True_Filter)
loop
set t = FirstOfGroup(g)
exitwhen t == null
call GroupRemoveUnit(g, t)
if IsUnitAlly(t, GetOwningPlayer(u)) and IsUnitAlive(t) and GetUnitAbilityLevel(t,'Avul') < 1 and u != t then
set se = AddSpecialEffect("Abilities\\Spells\\Items\\AIre\\AIreTarget.mdl", GetUnitX(t), GetUnitY(t))
call RestoreHealth(u, t, stat * 3)
call DestroyEffect(se)
endif
endloop
if Difficulty.level > 2 then
set se = AddSpecialEffect("Abilities\\Spells\\Items\\AIre\\AIreTarget.mdl", GetUnitX(u), GetUnitY(u))
call RestoreHealth(u, u, stat * 3)
call DestroyEffect(se)
endif
call DestroyGroup(g)
set g = null
set t = null
set se = null
endif
endmethod
implement T32x
static method create takes unit caster, integer stat, real range returns thistype
local thistype this = thistype.allocate()
set this.u = caster
set this.stat = stat
set this.range = range
return this
endmethod
endstruct
function Trig_W5V2_AI_Multislash_Conditions takes nothing returns boolean
return GetUnitTypeId(GetAttacker()) == 'H00W' and BlzGetUnitAbilityCooldownRemaining(GetAttacker(), 'A02S') == 0.0 and GetUnitCurrentOrder(GetAttacker()) != OrderId("roar")
endfunction
function Trig_W5V2_AI_Multislash_Actions takes nothing returns nothing
call IssueImmediateOrder(GetAttacker(), "roar")
endfunction
//===========================================================================
function InitTrig_W5V2_AI_Multislash takes nothing returns nothing
set gg_trg_W5V2_AI_Multislash = CreateTrigger( )
call DisableTrigger( gg_trg_W5V2_AI_Multislash )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W5V2_AI_Multislash, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddCondition( gg_trg_W5V2_AI_Multislash, Condition( function Trig_W5V2_AI_Multislash_Conditions ) )
call TriggerAddAction( gg_trg_W5V2_AI_Multislash, function Trig_W5V2_AI_Multislash_Actions )
endfunction
function Trig_W5CaptainMultislash_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A02S'
endfunction
function Trig_W5CaptainMultislash_Actions takes nothing returns nothing
local unit caster
local location l
set caster = GetTriggerUnit()
set l = GetUnitLoc(caster)
call BossPrompt(caster, "MULTISLASH")
call CaptainMultislashEffect.create(caster, 3 + udg_PlayerCount / 2, GetHeroStr(caster, true)).startPeriodic()
set l = null
set caster = null
endfunction
//===========================================================================
function InitTrig_W5CaptainMultislash takes nothing returns nothing
set gg_trg_W5CaptainMultislash = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W5CaptainMultislash, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_W5CaptainMultislash, Condition( function Trig_W5CaptainMultislash_Conditions ) )
call TriggerAddAction( gg_trg_W5CaptainMultislash, function Trig_W5CaptainMultislash_Actions )
endfunction
struct CaptainMultislashEffect
private unit u
private integer stat
private integer count
private method periodic takes nothing returns nothing
local unit gu
local effect se
local unit dummy
if ModuloInteger(T32_Tick, 7) == 0 then
set count = count - 1
call CaptainMultislashEffectSlash.create(u, stat).startPeriodic()
endif
if this.count == 0 then
set u = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes unit caster, integer count, integer stat returns thistype
local thistype this = thistype.allocate()
set this.u = caster
set this.stat = stat
set this.count = count
return this
endmethod
endstruct
struct CaptainMultislashEffectSlash
private unit u
private unit dummy
private integer stat
private boolean dirty
private integer endTick
private method periodic takes nothing returns nothing
local group g
local location l
local unit t
if dirty == false then
set dirty = true
set dummy = CreateUnit(GetOwningPlayer(u), 'h00Y', GetUnitX(u), GetUnitY(u), GetUnitFacing(u))
call SetUnitVertexColorBJ(dummy, 100, 100, 100, 70.00)
call SetUnitAnimation(dummy, "attack")
endif
if this.endTick == T32_Tick then
set g = CreateGroup()
set l = PolarProjectionU(dummy, 100, GetUnitFacing(dummy))
call GroupEnumUnitsInRangeOfLoc(g, l, 100, function True_Filter)
loop
set t = FirstOfGroup(g)
exitwhen t == null
call GroupRemoveUnit(g, t)
if (IsUnitEnemy(t,GetOwningPlayer(u)) and UnitAlive(t) and GetUnitAbilityLevel(t,'Avul') < 1) then
call UnitDamageTarget(u, t, stat * 2, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_METAL_MEDIUM_SLICE)
exitwhen true
endif
endloop
set t = null
call RemoveLocation(l)
set l = null
call RemoveUnit(dummy)
set dummy = null
call DestroyGroup(g)
set g = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes unit caster, integer stat returns thistype
local thistype this = thistype.allocate()
set this.u = caster
set this.endTick = T32_Tick + R2I(0.5 / T32_PERIOD)
set this.stat = stat
set this.dirty = false
return this
endmethod
endstruct
function Trig_W5TrollsH_Actions takes nothing returns nothing
local unit u = udg_UnitSpawned
if GetUnitTypeId(u) == 'w515' and Difficulty.level > 2 then
call UnitAddAbility(u, 'ACro')
endif
if GetUnitTypeId(u) == 'w514' and Difficulty.level > 2 then
call UnitAddAbility(u, 'ACuf')
endif
set u = null
endfunction
//===========================================================================
function InitTrig_W5TrollsH takes nothing returns nothing
set gg_trg_W5TrollsH = CreateTrigger( )
call DisableTrigger( gg_trg_W5TrollsH )
call TriggerRegisterVariableEvent( gg_trg_W5TrollsH, "udg_OnUnitSpawn", EQUAL, 1.00 )
call TriggerAddAction( gg_trg_W5TrollsH, function Trig_W5TrollsH_Actions )
endfunction
struct TrollTornado
private unit u
private integer stat
private integer iteration
private integer nextTick
private method periodic takes nothing returns nothing
local integer i = 0
local location l
local unit t
if this.nextTick == T32_Tick then
set iteration = iteration - 1
set nextTick = T32_Tick + 48
loop
exitwhen i == 4
call GenericSkillshotPierce.create(u, GetRandomReal(-45, 45) + i * 90, stat, 'h01H').startPeriodic()
set i = i + 1
endloop
endif
if iteration == 0 then
set u = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes unit caster, integer stat returns thistype
local thistype this = thistype.allocate()
set this.u = caster
set this.stat = stat
set this.nextTick = T32_Tick + 48
set iteration = 1
if Difficulty.level > 2 then
set iteration = 3
endif
return this
endmethod
endstruct
function Trig_W5Troll_Tornado_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A01E'
endfunction
function Trig_W5Troll_Tornado_Actions takes nothing returns nothing
local unit caster
local integer i = 0
set caster = GetTriggerUnit()
if Difficulty.level > 2 then
call BossPrompt(caster, "Triple Tornado")
else
call BossPrompt(caster, "Tornado")
endif
call TrollTornado.create(caster, GetHeroInt(caster, true)).startPeriodic()
set caster = null
endfunction
//===========================================================================
function InitTrig_W5Troll_Tornado takes nothing returns nothing
set gg_trg_W5Troll_Tornado = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W5Troll_Tornado, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_W5Troll_Tornado, Condition( function Trig_W5Troll_Tornado_Conditions ) )
call TriggerAddAction( gg_trg_W5Troll_Tornado, function Trig_W5Troll_Tornado_Actions )
endfunction
function Trig_W4V1_WolfMirrorH_Actions takes nothing returns nothing
local unit u = udg_UnitSpawned
if GetUnitTypeId(u) == 'w431' and Difficulty.level > 2 then
call UnitAddAbility(u, 'A03K')
endif
set u = null
endfunction
//===========================================================================
function InitTrig_W4V1_WolfMirrorH takes nothing returns nothing
set gg_trg_W4V1_WolfMirrorH = CreateTrigger( )
call DisableTrigger( gg_trg_W4V1_WolfMirrorH )
call TriggerRegisterVariableEvent( gg_trg_W4V1_WolfMirrorH, "udg_OnUnitSpawn", EQUAL, 1.00 )
call TriggerAddAction( gg_trg_W4V1_WolfMirrorH, function Trig_W4V1_WolfMirrorH_Actions )
endfunction
function Trig_W4V3WarlockFireball_Actions takes nothing returns nothing
local unit u = GetTriggerUnit()
local integer stat = GetHeroInt(u, true) * 3
local location l = GetUnitLoc(u)
local location l2
local group g
local unit gu
local integer i = 0
local real cos
local real angleDiff
call BossPrompt(u, "Mass Fireballs!")
//1 enemy target
set g = CreateGroup()
call GroupEnumUnitsInRangeOfLoc(g, l, 900, function EAnI_Filter)
loop
set gu = FirstOfGroup(g)
exitwhen i == 5
if gu == null then
set l2 = PolarProjectionBJ(l, GetRandomReal(250, 750), GetUnitFacing(u) + GetRandomReal(-75, 75))
call WarlockFireballEffect.create(u, l2, stat).startPeriodic()
set i = i + 1
else
set l2 = GetUnitLoc(gu)
set angleDiff = GetUnitFacing(u) - AngleBetweenPoints(l, l2)
set cos = Cos(angleDiff*bj_DEGTORAD)
// cos 0.259 -> 75° angle --> 150 radius
if (cos > 0.259) then
call WarlockFireballEffect.create(u, l2, stat).startPeriodic()
set i = i + 1
else
//skip
call RemoveLocation(l2)
endif
call GroupRemoveUnit(g, gu)
endif
endloop
call DestroyGroup(g)
set g = null
call RemoveLocation(l)
set u = null
set gu = null
set l = null
set l2 = null
endfunction
function Trig_W4V3WarlockFireball_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A03I'
endfunction
//===========================================================================
function InitTrig_W4V3WarlockFireball takes nothing returns nothing
set gg_trg_W4V3WarlockFireball = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ(gg_trg_W4V3WarlockFireball, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition( gg_trg_W4V3WarlockFireball, Condition( function Trig_W4V3WarlockFireball_Conditions ) )
call TriggerAddAction( gg_trg_W4V3WarlockFireball, function Trig_W4V3WarlockFireball_Actions )
endfunction
struct WarlockFireballEffect
private unit u
private unit dummy
private unit dummyTarget
private real perTick
private integer stat
private real angle
private location target
private boolean dirty
private group g
private integer startTick
private integer ticks
private integer ticks2
private real speedZ
private method periodic takes nothing returns nothing
local unit gu
local location l
if dirty == false then
set l = GetUnitLoc(u)
set angle = AngleBetweenPoints(l, target)
set dummy = CreateUnit(GetOwningPlayer(u), 'h01E', GetUnitX(u), GetUnitY(u), angle)
set dummyTarget = CreateUnitAtLoc(GetOwningPlayer(u), 'h00D', target, angle)
set speedZ = 200.0 / ticks2
call SetUnitFlyHeight(dummy, speedZ, 100)
call UnitApplyTimedLife(dummyTarget, 'BTLF', ticks / 32.0)
call UnitAddAbility(dummy, 'Amrf')
call UnitRemoveAbility(dummy, 'Amrf')
set perTick = DistanceBetweenPoints(target, l) * 1.0 / ticks
set g = CreateGroup()
set dirty = true
call RemoveLocation(l)
set l = null
endif
set l = PolarProjectionU(dummy, perTick, angle)
call SetUnitPositionLoc(dummy, l)
call RemoveLocation(l)
set l = null
if T32_Tick < startTick + ticks2 then
call SetUnitFlyHeight(dummy, 6000, speedZ * (startTick + ticks2 - T32_Tick))
elseif T32_Tick > startTick + ticks2 then
call SetUnitFlyHeight(dummy, 0, speedZ * (T32_Tick - startTick - ticks2))
endif
if startTick + ticks == T32_Tick then
call GroupEnumUnitsInRangeOfLoc(g, target, 115, function True_Filter)
loop
set gu = FirstOfGroup(g)
exitwhen gu == null
call GroupRemoveUnit(g, gu)
if (IsUnitEnemy(gu,GetOwningPlayer(u)) and UnitAlive(gu)) then
call UnitDamageTargetBJ(u, gu, 3.0 * stat, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_FIRE)
endif
endloop
if Difficulty.level > 2 then
call LingeringFlame.create(u, GetUnitLoc(dummy), stat).startPeriodic()
endif
call KillUnit(dummy)
set dummy = null
call RemoveUnit(dummyTarget)
set dummyTarget = null
set u = null
set gu = null
call DestroyGroup(g)
set g = null
call RemoveLocation(target)
set target = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes unit caster, location target, integer stat returns thistype
local thistype this = thistype.allocate()
set this.u = caster
set this.stat = stat
set this.target = target
set this.dirty = false
set this.ticks = R2I(1.5 / T32_PERIOD)
set this.ticks2 = ticks / 2
set this.startTick = T32_Tick
return this
endmethod
endstruct
struct LingeringFlame
private unit u
private integer stat
private boolean dirty
private location l
private integer endTick
private integer nextTick
private effect se
private method periodic takes nothing returns nothing
local group g
local unit gu
local effect su
if dirty == false then
set se = AddSpecialEffectLoc("Abilities\\Spells\\Human\\FlameStrike\\FlameStrikeEmbers.mdl", l)
call BlzSetSpecialEffectScale(se, 3.5)
set nextTick = T32_Tick + 12
set dirty = true
endif
if nextTick == T32_Tick then
if u != null and UnitAlive(u) then
set g = CreateGroup()
call GroupEnumUnitsInRangeOfLoc(g, l, 115, function True_Filter)
loop
set gu = FirstOfGroup(g)
exitwhen gu == null
call GroupRemoveUnit(g, gu)
if IsUnitEnemy(gu, GetOwningPlayer(u)) and UnitAlive(gu) then
call UnitDamageTargetBJ(u, gu, 0.3 * stat, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_FIRE)
set su = AddSpecialEffect("Abilities\\Weapons\\FireBallMissile\\FireBallMissile.mdl", GetUnitX(gu), GetUnitY(gu))
call DestroyEffect(su)
set su = null
endif
endloop
set gu = null
call DestroyGroup(g)
set g = null
set nextTick = nextTick + 12
else
set endTick = T32_Tick
endif
endif
if endTick == T32_Tick then
call RemoveLocation(l)
set l = null
set u = null
call DestroyEffect(se)
set se = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes unit caster, location l, integer stat returns thistype
local thistype this = thistype.allocate()
set this.u = caster
set this.stat = stat
set this.l = l
set this.dirty = false
set this.endTick = T32_Tick + R2I(20 / T32_PERIOD)
return this
endmethod
endstruct
function Trig_W4V3_AI_Warlock_Conditions takes nothing returns boolean
return GetUnitTypeId(GetAttacker()) == 'w432' and BlzGetUnitAbilityCooldownRemaining(GetAttacker(), 'A02O') == 0.0 and GetUnitCurrentOrder(GetAttacker()) != OrderId("firebolt")
endfunction
function Trig_W4V3_AI_Warlock_Actions takes nothing returns nothing
local unit u = GetTriggerUnit()
local unit t
if (GetRandomReal(0, 1) < 0.50) then
set t = highestAggroInRange(u, 700)
if t == null then
set t = randomEnemyInRange(u, 700)
endif
if t != null then
call IssueTargetOrder(GetTriggerUnit(), "firebolt", t)
set t = null
endif
endif
set u = null
endfunction
//===========================================================================
function InitTrig_W4V3_AI_Warlock takes nothing returns nothing
set gg_trg_W4V3_AI_Warlock = CreateTrigger( )
call DisableTrigger(gg_trg_W4V3_AI_Warlock)
call TriggerRegisterAnyUnitEventBJ( gg_trg_W4V3_AI_Warlock, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddCondition( gg_trg_W4V3_AI_Warlock, Condition( function Trig_W4V3_AI_Warlock_Conditions ) )
call TriggerAddAction( gg_trg_W4V3_AI_Warlock, function Trig_W4V3_AI_Warlock_Actions )
endfunction
function Trig_W4V3_AI_WarlockArcher_Conditions takes nothing returns boolean
return GetUnitTypeId(GetAttacker()) == 'w433' and BlzGetUnitAbilityCooldownRemaining(GetAttacker(), 'A03H') == 0.0 and GetUnitCurrentOrder(GetAttacker()) != OrderId("forkedlightning")
endfunction
function Trig_W4V3_AI_WarlockArcher_Actions takes nothing returns nothing
local unit u = GetTriggerUnit()
local unit t
if (GetRandomReal(0, 1) < 0.50) then
set t = highestAggroInRange(u, 700)
if t == null then
set t = randomEnemyInRange(u, 700)
endif
if t != null then
call IssueTargetOrder(GetTriggerUnit(), "forkedlightning", t)
set t = null
endif
endif
set u = null
endfunction
//===========================================================================
function InitTrig_W4V3_AI_WarlockArcher takes nothing returns nothing
set gg_trg_W4V3_AI_WarlockArcher = CreateTrigger( )
call DisableTrigger(gg_trg_W4V3_AI_WarlockArcher)
call TriggerRegisterAnyUnitEventBJ( gg_trg_W4V3_AI_WarlockArcher, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddCondition( gg_trg_W4V3_AI_WarlockArcher, Condition( function Trig_W4V3_AI_WarlockArcher_Conditions ) )
call TriggerAddAction( gg_trg_W4V3_AI_WarlockArcher, function Trig_W4V3_AI_WarlockArcher_Actions )
endfunction
function Trig_W4V2_ArcherH_Actions takes nothing returns nothing
local unit u = udg_UnitSpawned
local real range = BlzGetUnitWeaponRealField(u, UNIT_WEAPON_RF_ATTACK_RANGE, 0) + 750.0
if GetUnitTypeId(u) == 'w423' and Difficulty.level > 2 then
call SetUnitAcquireRange(u, range)
call BlzSetUnitWeaponRealField(u, UNIT_WEAPON_RF_ATTACK_RANGE, 0, range)
call BlzSetUnitWeaponRealField(u, UNIT_WEAPON_RF_ATTACK_RANGE, 1, range)
endif
set u = null
endfunction
//===========================================================================
function InitTrig_W4V2_ArcherH takes nothing returns nothing
set gg_trg_W4V2_ArcherH = CreateTrigger( )
call DisableTrigger( gg_trg_W4V2_ArcherH )
call TriggerRegisterVariableEvent( gg_trg_W4V2_ArcherH, "udg_OnUnitSpawn", EQUAL, 1.00 )
call TriggerAddAction( gg_trg_W4V2_ArcherH, function Trig_W4V2_ArcherH_Actions )
endfunction
function Trig_W4ImpalingPreload_Actions takes nothing returns nothing
local unit u = PreloadUnit('H00T')
call IssuePointOrder(u, "blink", GetUnitX(u) + 100, GetUnitY(u))
set u = null
endfunction
//===========================================================================
function InitTrig_W4ImpalingPreload takes nothing returns nothing
set gg_trg_W4ImpalingPreload = CreateTrigger( )
call TriggerRegisterTimerEventSingle( gg_trg_W4ImpalingPreload, 5 )
call TriggerAddAction( gg_trg_W4ImpalingPreload, function Trig_W4ImpalingPreload_Actions )
endfunction
function Trig_W4V2_AI_Conditions takes nothing returns boolean
return GetUnitTypeId(GetAttacker()) == 'H00T' and BlzGetUnitAbilityCooldownRemaining(GetAttacker(), 'A02R') == 0.0 and GetUnitCurrentOrder(GetAttacker()) != OrderId("blink")
endfunction
function Trig_W4V2_AI_t takes nothing returns nothing
local timer t = GetExpiredTimer()
local location lc = LoadLocationHandle(udg_UtilMap, GetHandleId(t), 1)
local unit u = LoadUnitHandle(udg_UtilMap, GetHandleId(t), 0)
call IssuePointOrderLoc(u, "blink", lc)
call RemoveLocation(lc)
call PauseTimer(t)
call DestroyTimer(t)
set lc = null
set t = null
endfunction
function Trig_W4V2_AI_Actions takes nothing returns nothing
local unit farthest = null
local real distanceF = 0
local real distanceC = 0
local unit c
local group g = CreateGroup()
local unit u = GetAttacker()
local location l = GetUnitLoc(u)
local location lc
local player p = GetOwningPlayer(u)
local timer t
call GroupEnumUnitsInRangeOfLoc(g, l, 1000, function True_Filter)
loop
set c = FirstOfGroup(g)
exitwhen c == null
call GroupRemoveUnit(g, c)
if (IsUnitEnemy(c, p) and UnitAlive(c) and GetUnitAbilityLevel(c,'Avul') < 1 ) then
set lc = GetUnitLoc(c)
set distanceC = DistanceBetweenPoints(l, lc)
if (distanceC > distanceF) then
set distanceF = distanceC
set farthest = c
endif
call RemoveLocation(lc)
endif
endloop
if (farthest != null) then
set lc = GetUnitLoc(farthest)
else
set lc = PolarProjectionBJ(l, 25, GetRandomReal(0, 360))
endif
//call IssuePointOrderLoc(u, "blink", lc)
set t = CreateTimer() //need a timer \o/
call SaveUnitHandle(udg_UtilMap, GetHandleId(t), 0, u)
call SaveLocationHandle(udg_UtilMap, GetHandleId(t), 1, lc)
call TimerStart(t, 0.1, false, function Trig_W4V2_AI_t)
call DestroyGroup(g)
call RemoveLocation(l)
set lc = null
set l = null
set u = null
set c = null
set farthest = null
set g = null
set p = null
set t = null
endfunction
//===========================================================================
function InitTrig_W4V2_AI takes nothing returns nothing
set gg_trg_W4V2_AI = CreateTrigger( )
call DisableTrigger( gg_trg_W4V2_AI )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W4V2_AI, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddCondition( gg_trg_W4V2_AI, Condition( function Trig_W4V2_AI_Conditions ) )
call TriggerAddAction( gg_trg_W4V2_AI, function Trig_W4V2_AI_Actions )
endfunction
function Trig_W4CaptainImpaling_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A02R'
endfunction
function Trig_W4CaptainImpaling_Actions takes nothing returns nothing
call BossPrompt(GetTriggerUnit(), "IMPALING ARROW")
endfunction
//===========================================================================
function InitTrig_W4CaptainImpaling takes nothing returns nothing
set gg_trg_W4CaptainImpaling = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W4CaptainImpaling, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_W4CaptainImpaling, Condition( function Trig_W4CaptainImpaling_Conditions ) )
call TriggerAddAction( gg_trg_W4CaptainImpaling, function Trig_W4CaptainImpaling_Actions )
endfunction
function Trig_W4CaptainImpalingFinishCast_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A02R'
endfunction
function Trig_W4CaptainImpalingFinishCast_Actions takes nothing returns nothing
local unit u = GetTriggerUnit()
local real facing = GetUnitFacing(u)
call CaptainImpalingArrowEffect.create(u, facing, GetHeroStr(u, true)).startPeriodic()
if Difficulty.level > 2 then
call CaptainImpalingArrowEffect.create(u, facing + 10, GetHeroStr(u, true)).startPeriodic()
call CaptainImpalingArrowEffect.create(u, facing - 10, GetHeroStr(u, true)).startPeriodic()
endif
endfunction
//===========================================================================
function InitTrig_W4CaptainImpalingFinishCast takes nothing returns nothing
set gg_trg_W4CaptainImpalingFinishCast = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W4CaptainImpalingFinishCast, EVENT_PLAYER_UNIT_SPELL_FINISH )
call TriggerAddCondition( gg_trg_W4CaptainImpalingFinishCast, Condition( function Trig_W4CaptainImpalingFinishCast_Conditions ) )
call TriggerAddAction( gg_trg_W4CaptainImpalingFinishCast, function Trig_W4CaptainImpalingFinishCast_Actions )
endfunction
struct CaptainImpalingArrowEffect
private unit u
private unit dummy
private integer stat
private real angle
private boolean dirty
private group g
private integer endTick
private method periodic takes nothing returns nothing
local unit gu
local effect se
if dirty == false then
set dummy = CreateUnit(GetOwningPlayer(u), 'h00V', GetUnitX(u), GetUnitY(u), angle)
call UnitAddAbility(dummy, 'Amrf')
call UnitRemoveAbility(dummy, 'Amrf')
call SetUnitFlyHeight(dummy, 50, 5000 )
set g = CreateGroup()
set dirty = true
endif
//if nextTick == T32_Tick and UnitAlive(u) then
//set nextTick = nextTick + 1
call GroupEnumUnitsInRange(g, GetUnitX(dummy), GetUnitY(dummy), 60, function True_Filter)
loop
set gu = FirstOfGroup(g)
exitwhen gu == null
call GroupRemoveUnit(g, gu)
if IsUnitEnemy(gu, GetOwningPlayer(dummy)) and UnitAlive(gu) and GetUnitAbilityLevel(gu,'Avul') < 1 then
call PolarProjectionUU(gu, gu, 40, angle)
call UnitDamageTargetBJ( u, gu, stat * 0.1, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL )
set se = AddSpecialEffect("Abilities\\Weapons\\AncientProtectorMissile\\AncientProtectorMissile.mdl", GetUnitX(dummy), GetUnitY(dummy))
call BlzPlaySpecialEffect( se, ANIM_TYPE_DEATH )
call DestroyEffect(se)
set se = null
set gu = null
endif
endloop
call PolarProjectionUU(dummy, dummy, 40, angle)
//endif
if IsTerrainPathable(GetUnitX(dummy), GetUnitY(dummy), PATHING_TYPE_WALKABILITY) then
set endTick = T32_Tick
call GroupEnumUnitsInRange(g, GetUnitX(dummy), GetUnitY(dummy), 80, function True_Filter)
loop
set gu = FirstOfGroup(g)
exitwhen gu == null
call GroupRemoveUnit(g, gu)
if IsUnitEnemy(gu, GetOwningPlayer(dummy)) and UnitAlive(gu) and GetUnitAbilityLevel(gu,'Avul') < 1 then
call UnitDamageTargetBJ( u, gu, stat, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL )
endif
endloop
set se = AddSpecialEffect("Abilities\\Weapons\\BallistaMissile\\BallistaMissile.mdl", GetUnitX(dummy), GetUnitY(dummy))
call BlzPlaySpecialEffect( se, ANIM_TYPE_DEATH )
call DestroyEffect(se)
set se = null
endif
if this.endTick == T32_Tick then
call RemoveUnit(dummy)
set u = null
set gu = null
set dummy = null
call DestroyGroup(g)
set g = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes unit caster, real angle, integer stat returns thistype
local thistype this = thistype.allocate()
set this.u = caster
set this.stat = stat
set this.angle = angle
set this.dirty = false
set this.endTick = T32_Tick + R2I(2 / T32_PERIOD)
return this
endmethod
endstruct
function Trig_W4V1_AI_LizardH_Conditions takes nothing returns boolean
return Difficulty.level > 2 and GetUnitTypeId(GetAttacker()) == 'w412' and BlzGetUnitAbilityCooldownRemaining(GetAttacker(), 'A03H') == 0.0 and GetUnitCurrentOrder(GetAttacker()) != OrderId("forkedlightning")
endfunction
function Trig_W4V1_AI_LizardH_Actions takes nothing returns nothing
local unit u = GetTriggerUnit()
local unit t
if (GetRandomReal(0, 1) < 0.50) then
set t = highestAggroInRange(u, 700)
if t == null then
set t = randomEnemyInRange(u, 700)
endif
if t != null then
call IssueTargetOrder(GetTriggerUnit(), "forkedlightning", t)
set t = null
endif
endif
set u = null
endfunction
//===========================================================================
function InitTrig_W4V1_AI_LizardH takes nothing returns nothing
set gg_trg_W4V1_AI_LizardH = CreateTrigger( )
call DisableTrigger(gg_trg_W4V1_AI_LizardH)
call TriggerRegisterAnyUnitEventBJ( gg_trg_W4V1_AI_LizardH, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddCondition( gg_trg_W4V1_AI_LizardH, Condition( function Trig_W4V1_AI_LizardH_Conditions ) )
call TriggerAddAction( gg_trg_W4V1_AI_LizardH, function Trig_W4V1_AI_LizardH_Actions )
endfunction
function Trig_W4V1_CreepsForkedH_Actions takes nothing returns nothing
local unit u = udg_UnitSpawned
if GetUnitTypeId(u) == 'w412' and Difficulty.level > 2 then
call UnitAddAbility(u, 'A03H')
endif
set u = null
endfunction
//===========================================================================
function InitTrig_W4V1_CreepsForkedH takes nothing returns nothing
set gg_trg_W4V1_CreepsForkedH = CreateTrigger( )
call DisableTrigger( gg_trg_W4V1_CreepsForkedH )
call TriggerRegisterVariableEvent( gg_trg_W4V1_CreepsForkedH, "udg_OnUnitSpawn", EQUAL, 1.00 )
call TriggerAddAction( gg_trg_W4V1_CreepsForkedH, function Trig_W4V1_CreepsForkedH_Actions )
endfunction
function Trig_W4V1_AI_Conditions takes nothing returns boolean
return GetUnitTypeId(GetTriggerUnit()) == 'H00B'
endfunction
function Trig_W4V1_AI_Actions takes nothing returns nothing
local unit attacked
local unit u
local real x
local real y
local group g
set attacked = GetTriggerUnit()
set x = GetUnitX(attacked)
set y = GetUnitY(attacked)
set g = CreateGroup()
call GroupEnumUnitsInRange(g, x, y, 700, function EAnI_Filter)
set u = FirstOfGroup(g)
if (u != null) then
call IssueTargetOrder(attacked, "slow", u)
endif
call DestroyGroup(g)
set g = null
set u = null
set attacked = null
endfunction
//===========================================================================
function InitTrig_W4V1_AI takes nothing returns nothing
set gg_trg_W4V1_AI = CreateTrigger( )
call DisableTrigger( gg_trg_W4V1_AI )
call TriggerRegisterPlayerUnitEventSimple( gg_trg_W4V1_AI, Player(23), EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddCondition( gg_trg_W4V1_AI, Condition( function Trig_W4V1_AI_Conditions ) )
call TriggerAddAction( gg_trg_W4V1_AI, function Trig_W4V1_AI_Actions )
endfunction
function Trig_W4LizardThunderstorm_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A014'
endfunction
function Trig_W4LizardThunderstorm_Actions takes nothing returns nothing
local integer stat
local location l
local location lc
local unit u
set u = GetSpellTargetUnit()
set l = GetUnitLoc(u)
set stat = GetHeroStatBJ(bj_HEROSTAT_INT, GetTriggerUnit(), true)
call BossPrompt(GetTriggerUnit(), "THUNDERSTORM")
call LizardThunderStormEffect.create(7.5, GetTriggerUnit(), l, stat).startPeriodic()
set u = null
set l = null
endfunction
//===========================================================================
function InitTrig_W4LizardThunderstorm takes nothing returns nothing
set gg_trg_W4LizardThunderstorm = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W4LizardThunderstorm, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_W4LizardThunderstorm, Condition( function Trig_W4LizardThunderstorm_Conditions ) )
call TriggerAddAction( gg_trg_W4LizardThunderstorm, function Trig_W4LizardThunderstorm_Actions )
endfunction
struct LizardThunderStormEffect
private unit u
private location center
private integer stat
private real baseRange
// private integer iterations
private integer endTick
private integer nextTick
private integer increment
private integer nextIterationUpgrade
private method periodic takes nothing returns nothing
local location strikeLoc
local integer i = 0
local unit retarget = null
if nextTick == T32_Tick and UnitAlive(u) then
// loop
// exitwhen i == iterations
set strikeLoc = PolarProjectionBJ(center, GetRandomInt(17, 300), GetRandomInt(0, 359))
call LizardThunderStormStrike.create(GetRandomReal(1.5, 2.0), u, strikeLoc, stat).startPeriodic()
set strikeLoc = null
// set i = i + 1
set nextTick = nextTick + increment
// endloop
endif
if nextIterationUpgrade == T32_Tick then
// set iterations = iterations + 1
set increment = increment - 2
set nextIterationUpgrade = nextIterationUpgrade + 48
endif
//hard, retarget
if Difficulty.level > 2 then
set retarget = ClosestInRange(1000, center, GetOwningPlayer(u))
if retarget != null then
call RemoveLocation(center)
set center = GetUnitLoc(retarget)
set retarget = null
endif
endif
if this.endTick == T32_Tick then
call RemoveLocation(center)
set u = null
set center = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes real duration, unit lizard, location l, integer stat returns thistype
local thistype this = thistype.allocate()
set this.u = lizard
set this.nextTick = T32_Tick + 10
set this.stat = stat
set this.baseRange = 300
set this.increment = 10
// set this.iterations = 1
set this.nextIterationUpgrade = T32_Tick + 64
set this.center = l
set this.endTick = T32_Tick + R2I(duration / T32_PERIOD)
return this
endmethod
endstruct
struct LizardThunderStormStrike
private unit caster
private unit targetingDummy
private location l
private integer stat
private effect se
private integer endTick
private integer nextTick
private integer secondTick
private method periodic takes nothing returns nothing
local real x
local real y
local group g
local unit t
if secondTick == T32_Tick then
set targetingDummy = CreateUnitAtLoc(GetOwningPlayer(caster), 'h00F', l, bj_UNIT_FACING )
endif
if nextTick == T32_Tick then
call RemoveUnit(targetingDummy)
set targetingDummy = null
call AddSpecialEffectLocBJ( l, "Doodads\\Cinematic\\Lightningbolt\\Lightningbolt.mdl" )
set se = GetLastCreatedEffectBJ()
call AddSpecialEffectLocBJ( l, "Abilities\\Spells\\Orc\\WarStomp\\WarStompCaster.mdl" )
call DestroyEffect( GetLastCreatedEffectBJ() )
set x = GetLocationX(l)
set y = GetLocationY(l)
set g = CreateGroup()
call GroupEnumUnitsInRange(g, x, y, 85, function True_Filter)
loop
set t = FirstOfGroup(g)
exitwhen t == null
call GroupRemoveUnit(g, t)
if (IsUnitEnemy(t,GetOwningPlayer(caster)) and UnitAlive(t)) then
call UnitDamageTargetBJ( caster, t, 3.0 * stat, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_LIGHTNING )
endif
endloop
set t = null
call DestroyGroup(g)
set g = null
endif
if this.endTick == T32_Tick then
call DestroyEffect( se )
set se = null
call RemoveLocation(l)
set caster = null
set l = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes real duration, unit caster, location l, integer stat returns thistype
local thistype this = thistype.allocate()
set this.caster = caster
set this.l = l
set this.stat = stat
set this.endTick = T32_Tick + R2I(duration / T32_PERIOD)
set this.nextTick = T32_Tick + R2I(duration / T32_PERIOD) / 2
set this.secondTick = T32_Tick + 1
return this
endmethod
endstruct
function Trig_W4LizardBounce_Conditions takes nothing returns boolean
return GetUnitTypeId(udg_DamageEventSource) == 'H00B' and udg_IsDamageAttack
endfunction
function Trig_W4LizardBounce_Actions takes nothing returns nothing
local unit attacker
local unit lcu
local unit target
local unit u
local integer i
local group g
local real x
local real y
local player p
set attacker = udg_DamageEventSource
set target = udg_DamageEventTarget
set p = GetOwningPlayer(attacker)
set x = GetUnitX(target)
set y = GetUnitY(target)
set g = CreateGroup()
set i = 0
call GroupEnumUnitsInRange(g, x, y, 350, function True_Filter)
loop
set u = FirstOfGroup(g)
exitwhen u == null or i == 3
call GroupRemoveUnit(g, u)
if (IsUnitEnemy(u,p) and u != target and UnitAlive(u) and GetUnitAbilityLevel(u,'Avul') < 1 ) then
set lcu = CreateUnit(p, 'h00C', GetUnitX(target), GetUnitY(target), bj_UNIT_FACING)
call BlzSetUnitWeaponIntegerField( lcu, UNIT_WEAPON_IF_ATTACK_DAMAGE_BASE, 0, MathRound(1.5 * GetHeroStatBJ(bj_HEROSTAT_INT, attacker, true)) ) //1.5 str
call UnitApplyTimedLife(lcu, 'BTLF', 1.00)
call IssueTargetOrder(lcu, "attack", u)
set i = i + 1
endif
endloop
set target = null
set attacker = null
set lcu = null
endfunction
//===========================================================================
function InitTrig_W4LizardBounce takes nothing returns nothing
set gg_trg_W4LizardBounce = CreateTrigger( )
call TriggerRegisterVariableEvent( gg_trg_W4LizardBounce, "udg_OnDamageEvent", EQUAL, 1.00 )
call TriggerAddCondition( gg_trg_W4LizardBounce, Condition( function Trig_W4LizardBounce_Conditions ) )
call TriggerAddAction( gg_trg_W4LizardBounce, function Trig_W4LizardBounce_Actions )
endfunction
function Trig_W3V3_AI_Conditions takes nothing returns boolean
return (GetUnitTypeId(GetAttacker()) == 'H01A' or GetUnitTypeId(GetAttacker()) == 'H01C') and GetUnitLifePercent(GetAttacker()) < 90.00
endfunction
function Trig_W3V3_AI_Actions takes nothing returns nothing
local unit k = GetAttacker()
local unit u
local location l = GetUnitLoc(k)
local location lu
local group g = CreateGroup()
local real angleDiff
local real cos
local real roll = GetRandomReal(0, 1)
call GroupEnumUnitsInRangeOfLoc(g, l, 375, function EAnI_FilterAttacker)
loop
set u = FirstOfGroup(g)
exitwhen u == null
call GroupRemoveUnit(g, u)
set lu = GetUnitLoc(u)
set angleDiff = GetUnitFacing(k) - AngleBetweenPoints(l, lu)
set cos = Cos(angleDiff*bj_DEGTORAD)
//call DisplayTextToForce( GetPlayersAll(), R2S(cos) )
// cos 0.642 -> 50° angle --> 100 radius
if (cos > 0.642) then
if roll > 0.5 then
call IssueImmediateOrder(k, "roar")
elseif Difficulty.level > 2 then
call IssueImmediateOrder(k, "avatar")
else
call IssueImmediateOrder(k, "roar")
endif
call RemoveLocation(lu)
exitwhen true
endif
call RemoveLocation(lu)
endloop
call RemoveLocation(l)
call DestroyGroup(g)
set g = null
set l = null
set lu = null
set u = null
endfunction
//===========================================================================
function InitTrig_W3V3_AI takes nothing returns nothing
set gg_trg_W3V3_AI = CreateTrigger( )
call DisableTrigger( gg_trg_W3V3_AI )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W3V3_AI, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddCondition( gg_trg_W3V3_AI, Condition( function Trig_W3V3_AI_Conditions ) )
call TriggerAddAction( gg_trg_W3V3_AI, function Trig_W3V3_AI_Actions )
endfunction
function Trig_W3KodoChompFinishCast_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A03F'
endfunction
function Trig_W3KodoChompFinishCast_Actions takes nothing returns nothing
local unit k = GetTriggerUnit()
local unit u
local location l = GetUnitLoc(k)
local location lu
local group g = CreateGroup()
local real angleDiff
local real cos
local real multiplier = 5.0
local integer stat = GetHeroStr(k, true)
local effect se
call BossPrompt(k, "CHOMP")
call GroupEnumUnitsInRangeOfLoc(g, l, 375, function EAnI_Filter)
set lu = PolarProjectionBJ(l, 180, GetUnitFacing(k))
set se = AddSpecialEffectLoc("Abilities\\Weapons\\AncientProtectorMissile\\AncientProtectorMissile.mdl", lu)
call BlzPlaySpecialEffect(se, ANIM_TYPE_DEATH)
call DestroyEffect(se)
loop
set u = FirstOfGroup(g)
exitwhen u == null
call GroupRemoveUnit(g, u)
set lu = GetUnitLoc(u)
set angleDiff = GetUnitFacing(k) - AngleBetweenPoints(l, lu)
set cos = Cos(angleDiff*bj_DEGTORAD)
//call DisplayTextToForce( GetPlayersAll(), R2S(cos) )
// cos 0.642 -> 50° angle --> 100 radius
if (cos > 0.642) then
call UnitDamageTargetBJ(k, u, multiplier * stat, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_ENHANCED)
set se = AddSpecialEffectLoc("Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.md", lu)
call DestroyEffect(se)
endif
call RemoveLocation(lu)
endloop
call RemoveLocation(l)
call DestroyGroup(g)
set g = null
set l = null
set lu = null
set u = null
set se = null
endfunction
//===========================================================================
function InitTrig_W3KodoChompFinishCast takes nothing returns nothing
set gg_trg_W3KodoChompFinishCast = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W3KodoChompFinishCast, EVENT_PLAYER_UNIT_SPELL_FINISH )
call TriggerAddCondition( gg_trg_W3KodoChompFinishCast, Condition( function Trig_W3KodoChompFinishCast_Conditions ) )
call TriggerAddAction( gg_trg_W3KodoChompFinishCast, function Trig_W3KodoChompFinishCast_Actions )
endfunction
function Trig_W3KodoChomp_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A03F'
endfunction
function Trig_W3KodoChomp_Actions takes nothing returns nothing
call BossPrompt(GetTriggerUnit(), "CHOMP")
endfunction
//===========================================================================
function InitTrig_W3KodoChomp takes nothing returns nothing
set gg_trg_W3KodoChomp = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W3KodoChomp, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_W3KodoChomp, Condition( function Trig_W3KodoChomp_Conditions ) )
call TriggerAddAction( gg_trg_W3KodoChomp, function Trig_W3KodoChomp_Actions )
endfunction
function Trig_W3KodoStampede_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A03G'
endfunction
function Trig_W3KodoStampede_Actions takes nothing returns nothing
call BossPrompt(GetTriggerUnit(), "STAMPEDE!")
call SetUnitAnimationByIndex(GetTriggerUnit(), 6)
call KodoStampedeEffect.create(GetTriggerUnit(), GetHeroStr(GetTriggerUnit(), true)).startPeriodic()
endfunction
//===========================================================================
function InitTrig_W3KodoStampede takes nothing returns nothing
set gg_trg_W3KodoStampede = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W3KodoStampede, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_W3KodoStampede, Condition( function Trig_W3KodoStampede_Conditions ) )
call TriggerAddAction( gg_trg_W3KodoStampede, function Trig_W3KodoStampede_Actions )
endfunction
struct KodoStampedeEffect
private unit u
private integer stat
private real angle
private boolean dirty
private group g
private integer endTick
private method periodic takes nothing returns nothing
local unit gu
local effect se
local location l
if dirty == false then
set angle = GetUnitFacing(u)
set g = CreateGroup()
set dirty = true
endif
call GroupEnumUnitsInRange(g, GetUnitX(u), GetUnitY(u), 150, function True_Filter)
loop
set gu = FirstOfGroup(g)
exitwhen gu == null
call GroupRemoveUnit(g, gu)
if IsUnitEnemy(gu, GetOwningPlayer(u)) and UnitAlive(gu) and GetUnitAbilityLevel(gu,'Avul') < 1 then
call PolarProjectionUU(gu, gu, 50, AngleBetweenUnits(u, gu))
call UnitDamageTargetBJ(u, gu, stat * 0.2, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL )
set se = AddSpecialEffect("Abilities\\Weapons\\AncientProtectorMissile\\AncientProtectorMissile.mdl", GetUnitX(u), GetUnitY(u))
call BlzPlaySpecialEffect( se, ANIM_TYPE_DEATH )
call DestroyEffect(se)
set se = null
set gu = null
endif
endloop
call PolarProjectionUU(u, u, 15, angle)
if ModuloInteger(T32_Tick, 7) == 0 then
set se = AddSpecialEffect("Abilities\\Spells\\Orc\\WarStomp\\WarStompCaster.mdl", GetUnitX(u), GetUnitY(u))
call DestroyEffect(se)
set se = null
endif
set l = PolarProjectionU(u, 50, angle)
if IsTerrainPathableBJ(l, PATHING_TYPE_WALKABILITY) then
set endTick = T32_Tick
set se = AddSpecialEffect("Abilities\\Weapons\\BallistaMissile\\BallistaMissile.mdl", GetUnitX(u), GetUnitY(u))
call BlzPlaySpecialEffect( se, ANIM_TYPE_DEATH )
call DestroyEffect(se)
set se = null
endif
call RemoveLocation(l)
set l = null
if this.endTick == T32_Tick then
call SetUnitAnimation(u, "stand")
set u = null
set gu = null
call DestroyGroup(g)
set g = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes unit caster, integer stat returns thistype
local thistype this = thistype.allocate()
set this.u = caster
set this.stat = stat
set this.dirty = false
set this.endTick = T32_Tick + R2I(4 / T32_PERIOD)
return this
endmethod
endstruct
function Trig_W3V2_CreepsShieldH_Actions takes nothing returns nothing
local unit u = udg_UnitSpawned
if GetUnitTypeId(u) == 'w322' and Difficulty.level > 2 then
call UnitAddAbility(u, 'ACfa')
endif
set u = null
endfunction
//===========================================================================
function InitTrig_W3V2_CreepsShieldH takes nothing returns nothing
set gg_trg_W3V2_CreepsShieldH = CreateTrigger( )
call DisableTrigger( gg_trg_W3V2_CreepsShieldH )
call TriggerRegisterVariableEvent( gg_trg_W3V2_CreepsShieldH, "udg_OnUnitSpawn", EQUAL, 1.00 )
call TriggerAddAction( gg_trg_W3V2_CreepsShieldH, function Trig_W3V2_CreepsShieldH_Actions )
endfunction
function Trig_W3V2_AI_Initiate_Conditions takes nothing returns boolean
return GetUnitTypeId(GetAttacker()) == 'w321' and BlzGetUnitAbilityCooldownRemaining(GetAttacker(), 'A02O') == 0.0 and GetUnitCurrentOrder(GetAttacker()) != OrderId("firebolt")
endfunction
function Trig_W3V2_AI_Initiate_Actions takes nothing returns nothing
local unit u = GetTriggerUnit()
local unit t
if (GetRandomReal(0, 1) < 0.50) then
set t = highestAggroInRange(u, 700)
if t == null then
set t = randomEnemyInRange(u, 700)
endif
if t != null then
call IssueTargetOrder(GetTriggerUnit(), "firebolt", t)
set t = null
endif
endif
set u = null
endfunction
//===========================================================================
function InitTrig_W3V2_AI_Initiate takes nothing returns nothing
set gg_trg_W3V2_AI_Initiate = CreateTrigger( )
call DisableTrigger(gg_trg_W3V2_AI_Initiate)
call TriggerRegisterAnyUnitEventBJ( gg_trg_W3V2_AI_Initiate, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddCondition( gg_trg_W3V2_AI_Initiate, Condition( function Trig_W3V2_AI_Initiate_Conditions ) )
call TriggerAddAction( gg_trg_W3V2_AI_Initiate, function Trig_W3V2_AI_Initiate_Actions )
endfunction
function Trig_W3V2_Scaling_Conditions takes nothing returns boolean
return GetUnitTypeId(GetSpellAbilityUnit()) == 'H002' or GetUnitTypeId(GetSpellAbilityUnit()) == 'H01B'
endfunction
function Trig_W3V2_Scaling_Actions takes nothing returns nothing
call BlzSetAbilityIntegerLevelField(BlzGetUnitAbility(GetSpellAbilityUnit(), 'A02P'), ABILITY_ILF_NUMBER_OF_IMAGES, 0, IMinBJ(udg_PlayerCount, 9))
if Difficulty.level > 2 then
call BlzSetAbilityRealLevelField(BlzGetUnitAbility(GetSpellAbilityUnit(), 'A02P'), ABILITY_RLF_DAMAGE_DEALT_PERCENT_OMI2, 0, 0.3)
endif
call DisableTrigger(GetTriggeringTrigger())
endfunction
//===========================================================================
function InitTrig_W3V2_Scaling takes nothing returns nothing
set gg_trg_W3V2_Scaling = CreateTrigger( )
call DisableTrigger( gg_trg_W3V2_Scaling )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W3V2_Scaling, EVENT_PLAYER_UNIT_SPELL_CAST )
call TriggerAddCondition( gg_trg_W3V2_Scaling, Condition( function Trig_W3V2_Scaling_Conditions ) )
call TriggerAddAction( gg_trg_W3V2_Scaling, function Trig_W3V2_Scaling_Actions )
endfunction
function Trig_W3V1_CreepsPoisonH_Actions takes nothing returns nothing
local unit u = udg_UnitSpawned
if (GetUnitTypeId(u) == 'w311' or GetUnitTypeId(u) == 'w312') and Difficulty.level > 2 then
call UnitAddAbility(u, 'ACvs')
endif
set u = null
endfunction
//===========================================================================
function InitTrig_W3V1_CreepsPoisonH takes nothing returns nothing
set gg_trg_W3V1_CreepsPoisonH = CreateTrigger( )
call DisableTrigger( gg_trg_W3V1_CreepsPoisonH )
call TriggerRegisterVariableEvent( gg_trg_W3V1_CreepsPoisonH, "udg_OnUnitSpawn", EQUAL, 1.00 )
call TriggerAddAction( gg_trg_W3V1_CreepsPoisonH, function Trig_W3V1_CreepsPoisonH_Actions )
endfunction
struct BanditBOGAttacks
private unit u
private unit oldTarget
private integer endTick
private integer nextTick
private static method f takes nothing returns boolean
return true
endmethod
private method periodic takes nothing returns nothing
local location l
local unit lcu
local group g
local real x
local real y
local unit target
local player p
if nextTick == T32_Tick and UnitAlive(u) then
set l = GetUnitLoc(u)
set p = GetOwningPlayer(u)
set lcu = CreateUnitAtLoc(p, 'h004', l, bj_UNIT_FACING)
call UnitApplyTimedLifeBJ( 2.00, 'BTLF', lcu)
call UnitAddAbilityBJ( 'A00X', lcu )
call BlzSetAbilityRealLevelFieldBJ( BlzGetUnitAbility(lcu, 'A00X'), ABILITY_RLF_DAMAGE_HTB1, 0, GetHeroStatBJ(bj_HEROSTAT_INT, u, true) * 2.75)
set x = GetUnitX(u)
set y = GetUnitY(u)
set g = CreateGroup()
call GroupEnumUnitsInRange(g, x, y, 1000, function s__BanditBOGAttacks_f)
loop
set target = FirstOfGroup(g)
exitwhen target == null
call GroupRemoveUnit(g, target)
if (IsUnitEnemy(target, p) and UnitAlive(target) and GetUnitAbilityLevel(target, 'Avul') < 1 and target != oldTarget ) then
exitwhen true
endif
endloop
if (target != null) then
set oldTarget = target
call IssueTargetOrder( lcu, "thunderbolt", target)
endif
set nextTick = nextTick + 25
call RemoveLocation(l)
call DestroyGroup(g)
set lcu = null
set g = null
set target = null
set p = null
endif
if this.endTick == T32_Tick then
set u = null
set oldTarget = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes real duration, unit bandit returns thistype
local thistype this = thistype.allocate()
set this.u = bandit
set this.nextTick = T32_Tick + 25
set this.endTick = T32_Tick + R2I(duration / T32_PERIOD)
return this
endmethod
endstruct
function Trig_W3BanditBagOfGold_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A00W'
endfunction
function Trig_W3BanditBagOfGold_Actions takes nothing returns nothing
call BossPrompt(GetTriggerUnit(), "BAG OF GOLD")
call BanditBOGAttacks.create(3.8, GetTriggerUnit()).startPeriodic()
endfunction
//===========================================================================
function InitTrig_W3BanditBagOfGold takes nothing returns nothing
set gg_trg_W3BanditBagOfGold = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W3BanditBagOfGold, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_W3BanditBagOfGold, Condition( function Trig_W3BanditBagOfGold_Conditions ) )
call TriggerAddAction( gg_trg_W3BanditBagOfGold, function Trig_W3BanditBagOfGold_Actions )
endfunction
struct BanditAmbushEffect
private unit u
private integer nextTick
private integer endTick
private group g
private method periodic takes nothing returns nothing
local location lu
local location l
local integer count
local integer stat
local integer i
local real uf
local player p
local unit lcu
local unit gu
if (this.nextTick == T32_Tick) then
set stat = GetHeroStatBJ(bj_HEROSTAT_AGI, u, true)
set count = stat / 10
set i = 0
set g = CreateGroup()
set p = GetOwningPlayer(u)
set l = GetUnitLoc(u)
set uf = GetUnitFacing(u)
if Difficulty.level > 2 then
set count = count * 2
endif
loop
exitwhen i == count
set lu = PolarProjectionBJ(l, 300.00, GetUnitFacing(u) + 180 + (i + 1) * 20.0)
set lcu = CreateUnitAtLoc(p, 'n004', lu, uf)
call UnitApplyTimedLifeBJ( 15.00, 'BTLF', lcu)
call GroupAddUnit(g, lcu)
call RemoveLocation(lu)
set lu = PolarProjectionBJ(l, 300.00, GetUnitFacing(u) + 180 + (i + 1) * -20.0)
set lcu = CreateUnitAtLoc(p, 'n004', lu, uf)
call UnitApplyTimedLifeBJ( 15.00, 'BTLF', lcu)
call GroupAddUnit(g, lcu)
call RemoveLocation(lu)
set i = i + 1
endloop
call RemoveLocation(l)
set l = null
set lu = null
set p = null
set lcu = null
endif
if this.endTick == T32_Tick then
loop
set gu = FirstOfGroup(g)
exitwhen gu == null
call GroupRemoveUnit(g, gu)
call RemoveUnit(gu)
endloop
call DestroyGroup(g)
set gu = null
set g = null
set u = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes real duration, unit bandit returns thistype
local thistype this = thistype.allocate()
set this.u = bandit
set this.nextTick = T32_Tick + 25
set this.endTick = T32_Tick + R2I(duration / T32_PERIOD)
return this
endmethod
endstruct
function Trig_W3BanditAmbush_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A00Y'
endfunction
function Trig_W3BanditAmbush_Actions takes nothing returns nothing
local location l
set l = GetUnitLoc(GetTriggerUnit())
call BossPrompt(GetTriggerUnit(), "AMBUSH!")
call BanditAmbushEffect.create(5.0, GetTriggerUnit()).startPeriodic()
call RemoveLocation (l)
set l = null
endfunction
//===========================================================================
function InitTrig_W3BanditAmbush takes nothing returns nothing
set gg_trg_W3BanditAmbush = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W3BanditAmbush, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_W3BanditAmbush, Condition( function Trig_W3BanditAmbush_Conditions ) )
call TriggerAddAction( gg_trg_W3BanditAmbush, function Trig_W3BanditAmbush_Actions )
endfunction
function Trig_W2V3_PeonChampionH_Actions takes nothing returns nothing
local unit u = udg_UnitSpawned
if GetUnitTypeId(u) == 'w232' and Difficulty.level > 2 then
call UnitAddAbility(u, 'A03E')
endif
set u = null
endfunction
//===========================================================================
function InitTrig_W2V3_PeonChampionH takes nothing returns nothing
set gg_trg_W2V3_PeonChampionH = CreateTrigger( )
call DisableTrigger( gg_trg_W2V3_PeonChampionH )
call TriggerRegisterVariableEvent( gg_trg_W2V3_PeonChampionH, "udg_OnUnitSpawn", EQUAL, 1.00 )
call TriggerAddAction( gg_trg_W2V3_PeonChampionH, function Trig_W2V3_PeonChampionH_Actions )
endfunction
function Trig_W2SlaverLivingSpikes_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A03B'
endfunction
function Trig_W2SlaverLivingSpikes_Actions takes nothing returns nothing
local integer stat
local unit u = GetTriggerUnit()
local location l = GetUnitLoc(u)
local unit target = FarthestInRange(800, l, GetOwningPlayer(u))
local location lt
if target == null then
set lt = PolarProjectionU(u, 300, GetUnitFacing(u))
else
set lt = GetUnitLoc(target)
endif
set stat = GetHeroInt(u, true)
call BossPrompt(u, "Living Spikes")
call SlaverLivingSpikesEffect.create(7.5, u, lt, stat).startPeriodic()
set u = null
set target = null
call RemoveLocation(l)
set l = null
set lt = null
endfunction
//===========================================================================
function InitTrig_W2SlaverLivingSpikes takes nothing returns nothing
set gg_trg_W2SlaverLivingSpikes = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W2SlaverLivingSpikes, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_W2SlaverLivingSpikes, Condition( function Trig_W2SlaverLivingSpikes_Conditions ) )
call TriggerAddAction( gg_trg_W2SlaverLivingSpikes, function Trig_W2SlaverLivingSpikes_Actions )
endfunction
struct SlaverLivingSpikesEffect
private unit u
private location center
private integer stat
private integer endTick
private integer nextTick
private method periodic takes nothing returns nothing
local location strikeLoc
local integer i = 0
local unit retarget = null
if nextTick == T32_Tick and UnitAlive(u) then
loop
exitwhen i == 3
set strikeLoc = PolarProjectionBJ(center, GetRandomInt(75, 310), GetRandomInt(0, 359))
call SlaverLivingSpikesStrike.create(GetRandomReal(1.5, 6.0), u, strikeLoc, stat * 3).startPeriodic()
set strikeLoc = null
set i = i + 1
endloop
set nextTick = nextTick + 32
endif
//hard, retarget
if Difficulty.level > 2 then
set retarget = ClosestInRange(1000, center, GetOwningPlayer(u))
if retarget != null then
call RemoveLocation(center)
set center = GetUnitLoc(retarget)
set retarget = null
endif
endif
if this.endTick == T32_Tick then
call RemoveLocation(center)
set u = null
set center = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes real duration, unit lizard, location l, integer stat returns thistype
local thistype this = thistype.allocate()
set this.u = lizard
set this.nextTick = T32_Tick + 10
set this.stat = stat
set this.center = l
set this.endTick = T32_Tick + R2I(duration / T32_PERIOD)
return this
endmethod
endstruct
struct SlaverLivingSpikesStrike
private unit caster
private unit targetingDummy
private location l
private integer stat
private effect se
private integer endTick
private integer nextTick
private integer secondTick
private method periodic takes nothing returns nothing
local real x
local real y
local group g
local unit t
if secondTick == T32_Tick then
set targetingDummy = CreateUnitAtLoc(GetOwningPlayer(caster), 'h00F', l, bj_UNIT_FACING )
endif
if nextTick == T32_Tick then
if se == null then
call RemoveUnit(targetingDummy)
set targetingDummy = null
set se = AddSpecialEffectLoc("war3mapImported\\EntanglingSpikes.mdx", l)
else
set x = GetLocationX(l)
set y = GetLocationY(l)
set g = CreateGroup()
call GroupEnumUnitsInRange(g, x, y, 85, function True_Filter)
loop
set t = FirstOfGroup(g)
exitwhen t == null
call GroupRemoveUnit(g, t)
if (IsUnitEnemy(t,GetOwningPlayer(caster)) and UnitAlive(t)) then
call UnitDamageTargetBJ( caster, t, stat, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_LIGHTNING )
endif
endloop
set t = null
call DestroyGroup(g)
set g = null
endif
set nextTick = nextTick + 16
endif
if this.endTick == T32_Tick then
call DestroyEffect(se)
set se = null
call RemoveLocation(l)
set caster = null
set l = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes real duration, unit caster, location l, integer stat returns thistype
local thistype this = thistype.allocate()
set this.caster = caster
set this.l = l
set this.stat = stat
set this.endTick = T32_Tick + R2I(duration / T32_PERIOD)
set this.nextTick = T32_Tick + 32
set this.secondTick = T32_Tick + 1
return this
endmethod
endstruct
function Trig_W2V3_AI_UTW_Actions takes nothing returns nothing
local unit boss = FirstOfGroup(udg_BossesInPlay)
if (boss == null) then
return
endif
if DistanceBetweenUnits(GetAttacker(), boss) < 500 and IsUnitAlly(GetAttacker(), GetOwningPlayer(boss)) and boss != GetAttacker() then
call IssueTargetOrder(boss, "bloodlust", GetAttacker())
endif
set boss = null
endfunction
//===========================================================================
function InitTrig_W2V3_AI_UTW takes nothing returns nothing
set gg_trg_W2V3_AI_UTW = CreateTrigger( )
call DisableTrigger( gg_trg_W2V3_AI_UTW )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W2V3_AI_UTW, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddAction( gg_trg_W2V3_AI_UTW, function Trig_W2V3_AI_UTW_Actions )
endfunction
function Trig_W2SlaverUseTheWhip_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A03C'
endfunction
function Trig_W2SlaverUseTheWhip_Actions takes nothing returns nothing
local unit target = GetSpellTargetUnit()
local unit source = GetTriggerUnit()
local effect se = AddSpecialEffect("Objects\\Spawnmodels\\Human\\HumanBlood\\HumanBloodFootman.mdl", GetUnitX(target), GetUnitY(target))
call DestroyEffect(se)
set se = AddSpecialEffect("Objects\\Spawnmodels\\Human\\HumanBlood\\HumanBloodPeasant.mdl", GetUnitX(target), GetUnitY(target))
call DestroyEffect(se)
set se = AddSpecialEffect("Objects\\Spawnmodels\\Human\\HumanBlood\\HumanBloodSorceress.mdl", GetUnitX(target), GetUnitY(target))
call DestroyEffect(se)
call UnitDamageTargetBJ(source, target, BlzGetUnitMaxHP(target) * 0.20, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_ENHANCED)
call BossPrompt(source, "Use the Whip")
set target = null
set source = null
set se = null
endfunction
//===========================================================================
function InitTrig_W2SlaverUseTheWhip takes nothing returns nothing
set gg_trg_W2SlaverUseTheWhip = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W2SlaverUseTheWhip, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_W2SlaverUseTheWhip, Condition( function Trig_W2SlaverUseTheWhip_Conditions ) )
call TriggerAddAction( gg_trg_W2SlaverUseTheWhip, function Trig_W2SlaverUseTheWhip_Actions )
endfunction
function Trig_W2V2_MilitiaChargeDmg_Conditions takes nothing returns boolean
return UnitHasBuffBJ(udg_DamageEventSource, 'B00I')
endfunction
function Trig_W2V2_MilitiaChargeDmg_Actions takes nothing returns nothing
set udg_DamageEventAmount = udg_DamageEventAmount * 2.0
call UnitRemoveAbility(udg_DamageEventSource, 'B00I')
endfunction
//===========================================================================
function InitTrig_W2V2_MilitiaChargeDmg takes nothing returns nothing
set gg_trg_W2V2_MilitiaChargeDmg = CreateTrigger( )
call DisableTrigger(gg_trg_W2V2_MilitiaChargeDmg)
call TriggerAddCondition(gg_trg_W2V2_MilitiaChargeDmg, function Trig_W2V2_MilitiaChargeDmg_Conditions )
call TriggerRegisterVariableEvent( gg_trg_W2V2_MilitiaChargeDmg, "udg_PreDamageEvent", EQUAL, 1.00 )
call TriggerAddAction( gg_trg_W2V2_MilitiaChargeDmg, function Trig_W2V2_MilitiaChargeDmg_Actions )
endfunction
function Trig_W2V2_Militia_AIH_Actions takes nothing returns nothing
local group g = GetUnitsOfPlayerAndTypeId(Player(23), 'w221')
local unit u
loop
set u = FirstOfGroup(g)
exitwhen u == null
call GroupRemoveUnit(g, u)
if UnitAlive(u) then
call IssueImmediateOrderById(u, 852285)
endif
endloop
call DestroyGroup(g)
set g = null
set u = null
endfunction
//===========================================================================
function InitTrig_W2V2_Militia_AIH takes nothing returns nothing
set gg_trg_W2V2_Militia_AIH = CreateTrigger( )
call DisableTrigger(gg_trg_W2V2_Militia_AIH)
call TriggerRegisterTimerEventPeriodic( gg_trg_W2V2_Militia_AIH, 2 )
call TriggerAddAction( gg_trg_W2V2_Militia_AIH, function Trig_W2V2_Militia_AIH_Actions )
endfunction
function Trig_W2LeapPreload_Actions takes nothing returns nothing
local unit u = PreloadUnit('H00U')
call IssuePointOrder(u, "blink", GetUnitX(u) + 100, GetUnitY(u))
set u = null
endfunction
//===========================================================================
function InitTrig_W2LeapPreload takes nothing returns nothing
set gg_trg_W2LeapPreload = CreateTrigger( )
call TriggerRegisterTimerEventSingle( gg_trg_W2LeapPreload, 5 )
call TriggerAddAction( gg_trg_W2LeapPreload, function Trig_W2LeapPreload_Actions )
endfunction
function Trig_W2DEBUG_Conditions takes nothing returns boolean
if ( not ( 'H00U' == GetUnitTypeId(GetOrderedUnit()) ) ) then
return false
endif
return true
endfunction
function Trig_W2DEBUG_Actions takes nothing returns nothing
if GetIssuedOrderId() == OrderId("blink") then
call BJDebugMsg("blink!!")
else
call BJDebugMsg(OrderId2String(GetIssuedOrderId()))
endif
endfunction
//===========================================================================
function InitTrig_W2DEBUG takes nothing returns nothing
set gg_trg_W2DEBUG = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W2DEBUG, EVENT_PLAYER_UNIT_ISSUED_ORDER )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W2DEBUG, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W2DEBUG, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER )
call TriggerAddCondition( gg_trg_W2DEBUG, Condition( function Trig_W2DEBUG_Conditions ) )
call TriggerAddAction( gg_trg_W2DEBUG, function Trig_W2DEBUG_Actions )
endfunction
function Trig_W2V2_ScalingH_Actions takes nothing returns nothing
if Difficulty.level > 2 then
set udg_BFUStacksCap = 10
endif
call DisableTrigger( GetTriggeringTrigger() )
endfunction
//===========================================================================
function InitTrig_W2V2_ScalingH takes nothing returns nothing
set gg_trg_W2V2_ScalingH = CreateTrigger( )
call DisableTrigger( gg_trg_W2V2_ScalingH )
call TriggerRegisterTimerEventSingle( gg_trg_W2V2_ScalingH, 5 )
call TriggerAddAction( gg_trg_W2V2_ScalingH, function Trig_W2V2_ScalingH_Actions )
endfunction
function Trig_W2V2_AI_Leap_Conditions takes nothing returns boolean
return GetUnitTypeId(GetAttacker()) == 'H00U' and BlzGetUnitAbilityCooldownRemaining(GetAttacker(), 'A02M') < 0.1 and GetUnitCurrentOrder(GetAttacker()) == OrderId("attack")
endfunction
function Trig_W2V2_Leap_t takes nothing returns nothing
local timer t = GetExpiredTimer()
local location lc = LoadLocationHandle(udg_UtilMap, GetHandleId(t), 1)
local unit u = LoadUnitHandle(udg_UtilMap, GetHandleId(t), 0)
//call IssuePointOrderByIdLoc(u, 852525, lc)
//call RemoveGuardPosition(u)
call IssuePointOrderLoc(u, "blink", lc)
//call BJDebugMsg("aaaa")
call RemoveLocation(lc)
call PauseTimer(t)
call DestroyTimer(t)
set lc = null
set t = null
endfunction
function Trig_W2V2_AI_Leap_Actions takes nothing returns nothing
local unit farthest = null
local real distanceF = 0
local real distanceC
local unit c
local group g = CreateGroup()
local unit u = GetAttacker()
local location l = GetUnitLoc(u)
local location lc
local player p = GetOwningPlayer(u)
local timer t
call GroupEnumUnitsInRangeOfLoc(g, l, 550, function True_Filter)
loop
set c = FirstOfGroup(g)
exitwhen c == null
call GroupRemoveUnit(g, c)
if (IsUnitEnemy(c, p) and UnitAlive(c) and GetUnitAbilityLevel(c,'Avul') < 1 ) then
set lc = GetUnitLoc(c)
set distanceC = DistanceBetweenPoints(l, lc)
if (distanceC > distanceF) then
set distanceF = distanceC
set farthest = c
endif
call RemoveLocation(lc)
endif
endloop
if (farthest != null) then
set lc = GetUnitLoc(farthest)
else
set lc = PolarProjectionBJ(l, 200, GetRandomReal(0, 360))
endif
//call PauseUnit(u, true)
//call PolledWait(0.2)
//call IssuePointOrderLoc(u, "blink", lc)
//call PauseUnit(u, false)
set t = CreateTimer() //need a timer \o/
call SaveUnitHandle(udg_UtilMap, GetHandleId(t), 0, u)
call SaveLocationHandle(udg_UtilMap, GetHandleId(t), 1, lc)
call TimerStart(t, 0.1, true, function Trig_W2V2_Leap_t)
//call TriggerExecute(gg_trg_DIOBONO)
//call ExecuteFunc("Trig_DIOBONO_Actions")
call DestroyGroup(g)
call RemoveLocation(l)
set lc = null
set l = null
set u = null
set c = null
set farthest = null
set g = null
set p = null
set t = null
endfunction
//===========================================================================
function InitTrig_W2V2_AI_Leap takes nothing returns nothing
set gg_trg_W2V2_AI_Leap = CreateTrigger( )
call DisableTrigger( gg_trg_W2V2_AI_Leap )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W2V2_AI_Leap, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddCondition( gg_trg_W2V2_AI_Leap, Condition( function Trig_W2V2_AI_Leap_Conditions ) )
call TriggerAddAction( gg_trg_W2V2_AI_Leap, function Trig_W2V2_AI_Leap_Actions )
endfunction
function Trig_W2V2_AI_StrainBody_Conditions takes nothing returns boolean
return GetUnitTypeId(GetTriggerUnit()) == 'H00U' and GetUnitLifePercent(GetTriggerUnit()) < 85.00
endfunction
function Trig_W2V2_AI_StrainBody_Actions takes nothing returns nothing
if udg_BFUStacks < udg_BFUStacksCap then
call IssueImmediateOrder( GetTriggerUnit(), "berserk" )
endif
endfunction
//===========================================================================
function InitTrig_W2V2_AI_StrainBody takes nothing returns nothing
set gg_trg_W2V2_AI_StrainBody = CreateTrigger( )
call DisableTrigger( gg_trg_W2V2_AI_StrainBody )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W2V2_AI_StrainBody, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddCondition( gg_trg_W2V2_AI_StrainBody, Condition( function Trig_W2V2_AI_StrainBody_Conditions ) )
call TriggerAddAction( gg_trg_W2V2_AI_StrainBody, function Trig_W2V2_AI_StrainBody_Actions )
endfunction
function Trig_W2BFULeap_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A02M'
endfunction
function Trig_Leap_BFU_Callback takes nothing returns boolean
local unit u
local effect se
local group g = CreateGroup()
local unit c
local player p
//call BJDebugMsg("callback")
set u = LoadUnitHandle(udg_UtilMap, udg_CALLBACK_HANDLE, 0)
set p = GetOwningPlayer(u)
set se = AddSpecialEffect("Abilities\\Spells\\Orc\\WarStomp\\WarStompCaster.mdl", GetUnitX(u), GetUnitY(u))
call DestroyEffect(se)
call GroupEnumUnitsInRange(g, GetUnitX(u), GetUnitY(u), 200, function True_Filter)
loop
set c = FirstOfGroup(g)
call GroupRemoveUnit(g, c)
exitwhen c == null
if (IsUnitEnemy(c, p) and UnitAlive(c) and GetUnitAbilityLevel(c,'Avul') < 1 ) then
call UnitDamageTarget(u, c, GetHeroStr(u, true) * 2.5, true, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_ENHANCED, WEAPON_TYPE_WHOKNOWS)
endif
endloop
call DestroyGroup(g)
set g = null
set c = null
set se = null
set u = null
set p = null
return true
endfunction
function Trig_W2BFULeap_Actions takes nothing returns nothing
local unit u = GetTriggerUnit()
local location ls = GetUnitLoc(u)
local location lt = GetSpellTargetLoc()
call BossPrompt(u, "LEAP")
call LeapFlyGhoul.create(ls, lt, u, Condition(function Trig_Leap_BFU_Callback)).startPeriodic()
set ls = null
set lt = null
set u = null
endfunction
//===========================================================================
function InitTrig_W2BFULeap takes nothing returns nothing
set gg_trg_W2BFULeap = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W2BFULeap, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_W2BFULeap, Condition( function Trig_W2BFULeap_Conditions ) )
call TriggerAddAction( gg_trg_W2BFULeap, function Trig_W2BFULeap_Actions )
endfunction
function Trig_W2BFUStrainBody_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A02N'
endfunction
function Trig_W2BFUStrainBody_Actions takes nothing returns nothing
local unit u = GetTriggerUnit()
local effect se
call BossPrompt(u, "STRAIN BODY")
set udg_BFUScale = udg_BFUScale + 0.2
set udg_BFUStacks = udg_BFUStacks + 1
call SetUnitScale(u, udg_BFUScale, udg_BFUScale, udg_BFUScale)
call SetHeroStr(u, MathRound(GetHeroStr(u, true) * 1.15) + 1 , true)
call RestoreHealth(u, u, GetHeroStr(u, true) * 1)
set se = AddSpecialEffect("Abilities\\Spells\\Demon\\DarkPortal\\DarkPortalTarget.mdl", GetUnitX(u), GetUnitY(u))
call DestroyEffect(se)
set u = null
set se = null
endfunction
//===========================================================================
function InitTrig_W2BFUStrainBody takes nothing returns nothing
set gg_trg_W2BFUStrainBody = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W2BFUStrainBody, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_W2BFUStrainBody, Condition( function Trig_W2BFUStrainBody_Conditions ) )
call TriggerAddAction( gg_trg_W2BFUStrainBody, function Trig_W2BFUStrainBody_Actions )
endfunction
function Trig_W2V1_GnollAssasinH_Actions takes nothing returns nothing
local unit u = udg_UnitSpawned
local real range = BlzGetUnitWeaponRealField(u, UNIT_WEAPON_RF_ATTACK_RANGE, 0) + 750.0
if GetUnitTypeId(u) == 'w211' and Difficulty.level > 2 then
call SetUnitAcquireRange(u, range)
call BlzSetUnitWeaponRealField(u, UNIT_WEAPON_RF_ATTACK_RANGE, 0, range)
call BlzSetUnitWeaponRealField(u, UNIT_WEAPON_RF_ATTACK_RANGE, 1, range)
endif
set u = null
endfunction
//===========================================================================
function InitTrig_W2V1_GnollAssasinH takes nothing returns nothing
set gg_trg_W2V1_GnollAssasinH = CreateTrigger( )
call DisableTrigger( gg_trg_W2V1_GnollAssasinH )
call TriggerRegisterVariableEvent( gg_trg_W2V1_GnollAssasinH, "udg_OnUnitSpawn", EQUAL, 1.00 )
call TriggerAddAction( gg_trg_W2V1_GnollAssasinH, function Trig_W2V1_GnollAssasinH_Actions )
endfunction
function Trig_W2V1_Scaling_Conditions takes nothing returns boolean
return GetUnitTypeId(GetSpellAbilityUnit()) == 'H009'
endfunction
function Trig_W2V1_Scaling_Actions takes nothing returns nothing
call BlzSetAbilityIntegerLevelField(BlzGetUnitAbility(GetSpellAbilityUnit(), 'A00J'), ABILITY_ILF_NUMBER_OF_SWARM_UNITS, 0, 2 + MathRound(udg_PlayerCount * 1.5))
if Difficulty.level > 2 then //hard
call BlzSetAbilityRealLevelField(BlzGetUnitAbility(GetSpellAbilityUnit(), 'A00J'), ABILITY_RLF_DAMAGE_RETURN_FACTOR, 0, 0.2)
endif
call DisableTrigger(GetTriggeringTrigger())
endfunction
//===========================================================================
function InitTrig_W2V1_Scaling takes nothing returns nothing
set gg_trg_W2V1_Scaling = CreateTrigger( )
call DisableTrigger( gg_trg_W2V1_Scaling )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W2V1_Scaling, EVENT_PLAYER_UNIT_SPELL_CAST )
call TriggerAddCondition( gg_trg_W2V1_Scaling, Condition( function Trig_W2V1_Scaling_Conditions ) )
call TriggerAddAction( gg_trg_W2V1_Scaling, function Trig_W2V1_Scaling_Actions )
endfunction
function Trig_W2GnollFury_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A00K'
endfunction
function Trig_W2GnollFury_Actions takes nothing returns nothing
local unit gnoll
local unit u
local real x
local real y
local group g
local location lgnoll
local location l1
local location l2
local location l3
local effect se
set gnoll = GetTriggerUnit()
set x = GetUnitX(gnoll)
set y = GetUnitY(gnoll)
set lgnoll = GetUnitLoc(gnoll)
call BossPrompt(gnoll, "FURY!")
set g = CreateGroup()
call GroupEnumUnitsInRange(g, x, y, 350, function EAnI_Filter)
set u = FirstOfGroup(g)
if (u != null) then
set l1 = GetUnitLoc(u)
call GroupRemoveUnit(g, u)
else
set l1 = PolarProjectionBJ(lgnoll, 300.00, GetRandomReal(0, 360))
endif
set se = AddSpecialEffectLoc("Abilities\\Spells\\Other\\TalkToMe\\TalkToMe.mdl", l1)
call BlzSetSpecialEffectColor(se, 255, 20, 30)
call BlzSetSpecialEffectScale(se, 2.0)
call DestroyAfterSpecialEffect.create(2, se).startPeriodic()
set u = FirstOfGroup(g)
if (u != null) then
set l2 = GetUnitLoc(u)
call GroupRemoveUnit(g, u)
else
set l2 = PolarProjectionBJ(lgnoll, 300.00, GetRandomReal(0, 360))
endif
set se = AddSpecialEffectLoc("Abilities\\Spells\\Other\\TalkToMe\\TalkToMe.mdl", l2)
call BlzSetSpecialEffectColor(se, 255, 20, 30)
call BlzSetSpecialEffectScale(se, 2.0)
call DestroyAfterSpecialEffect.create(2, se).startPeriodic()
set u = FirstOfGroup(g)
if (u != null) then
set l3 = GetUnitLoc(u)
else
set l3 = PolarProjectionBJ(lgnoll, 300.00, GetRandomReal(0, 360))
endif
set se = AddSpecialEffectLoc("Abilities\\Spells\\Other\\TalkToMe\\TalkToMe.mdl", l3)
call BlzSetSpecialEffectColor(se, 255, 20, 30)
call BlzSetSpecialEffectScale(se, 2.0)
call DestroyAfterSpecialEffect.create(2, se).startPeriodic()
call SetUnitTimeScale(gnoll, 5.0)
call GnollFuryAttacks.create(3.0, gnoll, l1, l2, l3).startPeriodic()
call DestroyGroup(g)
call RemoveLocation(lgnoll)
set l1 = null
set l2 = null
set l3 = null
set lgnoll = null
set u = null
set gnoll = null
set g = null
set se = null
endfunction
//===========================================================================
function InitTrig_W2GnollFury takes nothing returns nothing
set gg_trg_W2GnollFury = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W2GnollFury, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_W2GnollFury, Condition( function Trig_W2GnollFury_Conditions ) )
call TriggerAddAction( gg_trg_W2GnollFury, function Trig_W2GnollFury_Actions )
endfunction
struct GnollFuryAttacks
private unit u
private real origAttackSpeed
private location l1
private location l2
private location l3
private integer endTick
private method periodic takes nothing returns nothing
local integer random = 0
if (ModuloInteger(T32_Tick, 6) == 0 and u != null) then
set random = GetRandomInt(0, 2)
if (random == 0) then
call IssuePointOrderLoc( u, "attackground", l1 )
endif
if (random == 1) then
call IssuePointOrderLoc( u, "attackground", l2 )
endif
if (random == 2) then
call IssuePointOrderLoc( u, "attackground", l3 )
endif
endif
if this.endTick == T32_Tick then
if (u != null) then
call IssueImmediateOrder( u, "stop" )
call BlzSetUnitWeaponRealField( this.u, UNIT_WEAPON_RF_ATTACK_BASE_COOLDOWN, 0, this.origAttackSpeed )
call SetUnitTimeScale( u, 1 )
endif
set u = null
call RemoveLocation(l1)
call RemoveLocation(l2)
call RemoveLocation(l3)
set l1 = null
set l2 = null
set l3 = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes real duration, unit gnoll, location l1, location l2, location l3 returns thistype
local thistype this = thistype.allocate()
set this.u = gnoll
call SetUnitTimeScale( this.u, 5 )
set this.origAttackSpeed = BlzGetUnitWeaponRealField(this.u, UNIT_WEAPON_RF_ATTACK_BASE_COOLDOWN, 0)
call BlzSetUnitWeaponRealField( this.u, UNIT_WEAPON_RF_ATTACK_BASE_COOLDOWN, 0, 0.01 )
set this.l1 = l1
set this.l2 = l2
set this.l3 = l3
set this.endTick = T32_Tick + R2I(duration / T32_PERIOD)
return this
endmethod
endstruct
function Trig_W1V3Razor_AIH_Conditions takes nothing returns boolean
return GetUnitTypeId(GetTriggerUnit()) == 'w132' and Difficulty.level > 2
endfunction
function Trig_W1V3Razor_AIH_Actions takes nothing returns nothing
if (GetRandomReal(0, 1) < 0.50) then
call IssueImmediateOrder(GetTriggerUnit(), "roar")
endif
endfunction
//===========================================================================
function InitTrig_W1V3Razor_AIH takes nothing returns nothing
set gg_trg_W1V3Razor_AIH = CreateTrigger( )
call DisableTrigger(gg_trg_W1V3Razor_AIH)
call TriggerRegisterAnyUnitEventBJ( gg_trg_W1V3Razor_AIH, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddCondition( gg_trg_W1V3Razor_AIH, Condition( function Trig_W1V3Razor_AIH_Conditions ) )
call TriggerAddAction( gg_trg_W1V3Razor_AIH, function Trig_W1V3Razor_AIH_Actions )
endfunction
function Trig_W1RazorFinishCast_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A037'
endfunction
function Trig_W1RazorFinishCast_Actions takes nothing returns nothing
call GenericSkillshotStop.create(GetTriggerUnit(), GetUnitFacing(GetTriggerUnit()), BlzGetUnitBaseDamage(GetTriggerUnit(), 0) * 5, 'h016').startPeriodic()
endfunction
//===========================================================================
function InitTrig_W1RazorFinishCast takes nothing returns nothing
set gg_trg_W1RazorFinishCast = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W1RazorFinishCast, EVENT_PLAYER_UNIT_SPELL_FINISH )
call TriggerAddCondition( gg_trg_W1RazorFinishCast, Condition( function Trig_W1RazorFinishCast_Conditions ) )
call TriggerAddAction( gg_trg_W1RazorFinishCast, function Trig_W1RazorFinishCast_Actions )
endfunction
function Trig_W1V3_AI_EarthquakeH_Conditions takes nothing returns boolean
return GetUnitTypeId(GetTriggerUnit()) == 'H017' and Difficulty.level > 2 and GetUnitLifePercent(GetTriggerUnit()) < 75.00
endfunction
function Trig_W1V3_AI_EarthquakeH_Actions takes nothing returns nothing
call IssueImmediateOrder(GetTriggerUnit(), "roar")
endfunction
//===========================================================================
function InitTrig_W1V3_AI_EarthquakeH takes nothing returns nothing
set gg_trg_W1V3_AI_EarthquakeH = CreateTrigger( )
call DisableTrigger( gg_trg_W1V3_AI_EarthquakeH )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W1V3_AI_EarthquakeH, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddCondition( gg_trg_W1V3_AI_EarthquakeH, Condition( function Trig_W1V3_AI_EarthquakeH_Conditions ) )
call TriggerAddAction( gg_trg_W1V3_AI_EarthquakeH, function Trig_W1V3_AI_EarthquakeH_Actions )
endfunction
function Trig_W1PigEarthquake_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A038'
endfunction
function Trig_W1PigEarthquake_Actions takes nothing returns nothing
local unit u = GetTriggerUnit()
local location l
local integer i = 0
local real angle = GetUnitFacing(u)
call BossPrompt(u, "Earthquake")
loop
exitwhen i == 4
set l = PolarProjectionU(u, GetRandomReal(200, 400), GetRandomReal(angle - 90, angle + 90))
call FatPigEarthquakeEffect.create(u, l, GetHeroStr(u, true)).startPeriodic()
set i = i + 1
endloop
set i = 0
loop
exitwhen i == 8
set l = PolarProjectionU(u, GetRandomReal(400, 600), GetRandomReal(0, 360))
call FatPigEarthquakeEffect.create(u, l, GetHeroStr(u, true)).startPeriodic()
set i = i + 1
endloop
set l = null
set u = null
endfunction
//===========================================================================
function InitTrig_W1PigEarthquake takes nothing returns nothing
set gg_trg_W1PigEarthquake = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W1PigEarthquake, EVENT_PLAYER_UNIT_SPELL_CHANNEL )
call TriggerAddCondition( gg_trg_W1PigEarthquake, Condition( function Trig_W1PigEarthquake_Conditions ) )
call TriggerAddAction( gg_trg_W1PigEarthquake, function Trig_W1PigEarthquake_Actions )
endfunction
struct FatPigEarthquakeEffect
private unit caster
private unit targetingDummy
private location l
private integer stat
private effect se
private integer endTick
private integer nextTick
private integer secondTick
private method periodic takes nothing returns nothing
local real x
local real y
local group g
local unit t
if secondTick == T32_Tick then
set targetingDummy = CreateUnitAtLoc(GetOwningPlayer(caster), 'h00D', l, bj_UNIT_FACING )
endif
if nextTick == T32_Tick then
if targetingDummy != null then
call RemoveUnit(targetingDummy)
set targetingDummy = null
set se = AddSpecialEffectLoc("Abilities\\Spells\\Orc\\EarthQuake\\EarthQuakeTarget.mdl", l)
call BlzSetSpecialEffectScale(se, 0.5)
endif
if UnitAlive(caster) then
set x = GetLocationX(l)
set y = GetLocationY(l)
set g = CreateGroup()
call GroupEnumUnitsInRange(g, x, y, 100, function True_Filter)
loop
set t = FirstOfGroup(g)
exitwhen t == null
call GroupRemoveUnit(g, t)
if (IsUnitEnemy(t,GetOwningPlayer(caster)) and UnitAlive(t)) then
call UnitDamageTargetBJ( caster, t, 3.0 * stat, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC )
endif
set t = null
endloop
call DestroyGroup(g)
set g = null
endif
set nextTick = nextTick + 32
endif
if this.endTick == T32_Tick then
call DestroyEffect(se)
set se = null
call RemoveLocation(l)
set caster = null
set l = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes unit caster, location l, integer stat returns thistype
local thistype this = thistype.allocate()
set this.caster = caster
set this.l = l
set this.stat = stat
set this.nextTick = T32_Tick + 32
set this.endTick = nextTick + 130
set this.secondTick = T32_Tick + 1
return this
endmethod
endstruct
function Trig_W1PigSeismicWave_Actions takes nothing returns nothing
local integer i = 0
local unit u = GetTriggerUnit()
local integer stat = GetHeroInt(u, true)
local real angle = GetUnitFacing(u)
local location l = GetUnitLoc(u)
local location l2
call BossPrompt(u, "Seismic Wave")
call SetUnitTimeScale(u, 1.25)
loop
exitwhen i == 8
set l2 = PolarProjectionBJ(l, 150 + i * 150, angle)
call FatPigSeismicWaveStrike.create(2 + i * 0.2, u, l2, stat).startPeriodic()
set i = i + 1
endloop
call RemoveLocation(l)
set u = null
set l = null
set l2 = null
endfunction
function Trig_W1PigSeismicWave_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A036'
endfunction
//===========================================================================
function InitTrig_W1PigSeismicWave takes nothing returns nothing
set gg_trg_W1PigSeismicWave = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ(gg_trg_W1PigSeismicWave, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition( gg_trg_W1PigSeismicWave, Condition( function Trig_W1PigSeismicWave_Conditions ) )
call TriggerAddAction( gg_trg_W1PigSeismicWave, function Trig_W1PigSeismicWave_Actions )
endfunction
function Trig_W1PigSeismicWaveFinish_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A036'
endfunction
function Trig_W1PigSeismicWaveFinish_Actions takes nothing returns nothing
call SetUnitTimeScale(GetTriggerUnit(), 1)
endfunction
//===========================================================================
function InitTrig_W1PigSeismicWaveFinish takes nothing returns nothing
set gg_trg_W1PigSeismicWaveFinish = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W1PigSeismicWaveFinish, EVENT_PLAYER_UNIT_SPELL_FINISH )
call TriggerAddCondition( gg_trg_W1PigSeismicWaveFinish, Condition( function Trig_W1PigSeismicWaveFinish_Conditions ) )
call TriggerAddAction( gg_trg_W1PigSeismicWaveFinish, function Trig_W1PigSeismicWaveFinish_Actions )
endfunction
struct FatPigSeismicWaveStrike
private unit caster
private unit targetingDummy
private location l
private integer stat
private integer endTick
private integer nextTick
private integer secondTick
private method periodic takes nothing returns nothing
local real x
local real y
local group g
local unit t
local effect se
if secondTick == T32_Tick then
set targetingDummy = CreateUnitAtLoc(GetOwningPlayer(caster), 'h00F', l, bj_UNIT_FACING )
endif
if nextTick == T32_Tick then
call RemoveUnit(targetingDummy)
set targetingDummy = null
if UnitAlive(caster) then
set se = AddSpecialEffectLoc("Abilities\\Spells\\Other\\Volcano\\VolcanoDeath.mdl", l)
//set se = AddSpecialEffectLoc("Doodads\\LordaeronSummer\\Terrain\\LoardaeronRockChunks\\LoardaeronRockChunks5.mdl", l)
call BlzSetSpecialEffectScale(se, 0.7)
call DestroyEffect(se)
set se = AddSpecialEffectLoc("Abilities\\Spells\\Orc\\WarStomp\\WarStompCaster.mdl", l)
call BlzSetSpecialEffectScale(se, 0.3)
call DestroyEffect(se)
set se = null
set x = GetLocationX(l)
set y = GetLocationY(l)
set g = CreateGroup()
call GroupEnumUnitsInRange(g, x, y, 85, function True_Filter)
loop
set t = FirstOfGroup(g)
exitwhen t == null
call GroupRemoveUnit(g, t)
if (IsUnitEnemy(t,GetOwningPlayer(caster)) and UnitAlive(t)) then
call UnitDamageTargetBJ( caster, t, 3.0 * stat, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC )
endif
set t = null
endloop
call DestroyGroup(g)
set g = null
endif
endif
if this.endTick == T32_Tick then
call RemoveLocation(l)
set caster = null
set l = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes real duration, unit caster, location l, integer stat returns thistype
local thistype this = thistype.allocate()
set this.caster = caster
set this.l = l
set this.stat = stat
set this.nextTick = T32_Tick + R2I(duration / T32_PERIOD)
set this.endTick = nextTick + 5
set this.secondTick = T32_Tick + 1
return this
endmethod
endstruct
struct GenericSkillshotStop
private unit u
private unit dummy
private integer stat
private integer dummycode
private real angle
private boolean dirty
private group g
private integer endTick
private method periodic takes nothing returns nothing
local unit gu
local effect se
if dirty == false then
set dummy = CreateUnit(GetOwningPlayer(u), dummycode, GetUnitX(u), GetUnitY(u), angle)
call UnitAddAbility(dummy, 'Amrf')
call UnitRemoveAbility(dummy, 'Amrf')
call SetUnitFlyHeight(dummy, 50, 5000 )
set g = CreateGroup()
set dirty = true
endif
call GroupEnumUnitsInRange(g, GetUnitX(dummy), GetUnitY(dummy), 60, function True_Filter)
loop
set gu = FirstOfGroup(g)
exitwhen gu == null
call GroupRemoveUnit(g, gu)
if IsUnitEnemy(gu, GetOwningPlayer(dummy)) and UnitAlive(gu) and GetUnitAbilityLevel(gu,'Avul') < 1 then
call UnitDamageTargetBJ( u, gu, stat, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL )
set se = AddSpecialEffect("Abilities\\Weapons\\BallistaMissile\\BallistaMissile.mdl", GetUnitX(dummy), GetUnitY(dummy))
call BlzPlaySpecialEffect( se, ANIM_TYPE_DEATH )
call DestroyEffect(se)
set se = null
set endTick = T32_Tick
endif
endloop
call PolarProjectionUU(dummy, dummy, 40, angle)
if IsTerrainPathable(GetUnitX(dummy), GetUnitY(dummy), PATHING_TYPE_WALKABILITY) then
set endTick = T32_Tick
set se = AddSpecialEffect("Abilities\\Weapons\\BallistaMissile\\BallistaMissile.mdl", GetUnitX(dummy), GetUnitY(dummy))
call BlzPlaySpecialEffect( se, ANIM_TYPE_DEATH )
call DestroyEffect(se)
set se = null
endif
if this.endTick == T32_Tick then
call RemoveUnit(dummy)
set u = null
set gu = null
set dummy = null
call DestroyGroup(g)
set g = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes unit caster, real angle, integer stat, integer dummycode returns thistype
local thistype this = thistype.allocate()
set this.u = caster
set this.stat = stat
set this.angle = angle
set this.dirty = false
set this.dummycode = dummycode
set this.endTick = T32_Tick + R2I(2 / T32_PERIOD)
return this
endmethod
endstruct
struct GenericSkillshotPierce
private unit u
private unit dummy
private integer stat
private integer dummycode
private real angle
private boolean dirty
private group g
private integer endTick
private method periodic takes nothing returns nothing
local unit gu
local effect se
if dirty == false then
set dummy = CreateUnit(GetOwningPlayer(u), dummycode, GetUnitX(u), GetUnitY(u), angle)
call UnitAddAbility(dummy, 'Amrf')
call UnitRemoveAbility(dummy, 'Amrf')
call SetUnitFlyHeight(dummy, 50, 5000 )
set g = CreateGroup()
set dirty = true
endif
call GroupEnumUnitsInRange(g, GetUnitX(dummy), GetUnitY(dummy), 60, function True_Filter)
loop
set gu = FirstOfGroup(g)
exitwhen gu == null
call GroupRemoveUnit(g, gu)
if IsUnitEnemy(gu, GetOwningPlayer(dummy)) and UnitAlive(gu) and GetUnitAbilityLevel(gu,'Avul') < 1 then
call UnitDamageTargetBJ( u, gu, stat, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL )
set se = AddSpecialEffect("Abilities\\Weapons\\BallistaMissile\\BallistaMissile.mdl", GetUnitX(dummy), GetUnitY(dummy))
call BlzPlaySpecialEffect( se, ANIM_TYPE_DEATH )
call DestroyEffect(se)
set se = null
endif
endloop
call PolarProjectionUU(dummy, dummy, 40, angle)
if IsTerrainPathable(GetUnitX(dummy), GetUnitY(dummy), PATHING_TYPE_WALKABILITY) then
set endTick = T32_Tick
set se = AddSpecialEffect("Abilities\\Weapons\\BallistaMissile\\BallistaMissile.mdl", GetUnitX(dummy), GetUnitY(dummy))
call BlzPlaySpecialEffect( se, ANIM_TYPE_DEATH )
call DestroyEffect(se)
set se = null
endif
if this.endTick == T32_Tick then
call RemoveUnit(dummy)
set u = null
set gu = null
set dummy = null
call DestroyGroup(g)
set g = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes unit caster, real angle, integer stat, integer dummycode returns thistype
local thistype this = thistype.allocate()
set this.u = caster
set this.stat = stat
set this.angle = angle
set this.dirty = false
set this.dummycode = dummycode
set this.endTick = T32_Tick + R2I(2 / T32_PERIOD)
return this
endmethod
endstruct
function Trig_W1MurlocGrenade_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A023'
endfunction
function Trig_W1MurlocGrenade_Filter takes nothing returns boolean
local boolean retval
local unit u = GetFilterUnit()
local player p = GetOwningPlayer(GetTriggerUnit())
set retval = IsUnitEnemy(u,p) and UnitAlive(u) and GetUnitAbilityLevel(u,'Avul') < 1
set u = null
set p = null
return retval
endfunction
function Trig_W1MurlocGrenade_Actions takes nothing returns nothing
local unit caster
local unit target
local location l
local location ltarget
local unit dummy
local unit lcu
local player p
local group g
set caster = GetTriggerUnit()
if Difficulty.level > 2 then
call BossPrompt(caster, "DUPLICATION GRENADE")
else
call BossPrompt(caster, "GRENADE!")
endif
set l = GetUnitLoc(caster)
set p = GetOwningPlayer(caster)
set dummy = CreateUnitAtLoc(p, 'h004', l, bj_UNIT_FACING)
call UnitApplyTimedLife(dummy, 'BTLF', 10.00)
call UnitAddAbility(dummy, 'A024')
call BlzSetAbilityRealLevelField( BlzGetUnitAbility(dummy, 'A024'), ConvertAbilityRealLevelField('Nab4'), 0, GetHeroInt(caster, true) * 5.0)
set g = CreateGroup()
call GroupEnumUnitsInRangeOfLoc(g, l, 1000, function Trig_W1MurlocGrenade_Filter)
set target = GroupPickRandomUnit(g)
call DestroyGroup(g)
if (target == null) then
set ltarget = PolarProjectionBJ(l, GetRandomReal(400, 500), GetRandomReal(0, 360))
else
set ltarget = GetUnitLoc(target)
endif
set lcu = CreateUnitAtLoc(Player(PLAYER_NEUTRAL_PASSIVE), 'h00Q', ltarget, bj_UNIT_FACING)
call IssueTargetOrder(dummy, "acidbomb", lcu)
call UnitApplyTimedLife(dummy, 'BTLF', 10.00)
call RemoveLocation(l)
call RemoveLocation(ltarget)
set l = null
set ltarget = null
set lcu = null
set dummy = null
set p = null
set g = null
set target = null
set caster = null
endfunction
//===========================================================================
function InitTrig_W1MurlocGrenade takes nothing returns nothing
set gg_trg_W1MurlocGrenade = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W1MurlocGrenade, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_W1MurlocGrenade, Condition( function Trig_W1MurlocGrenade_Conditions ) )
call TriggerAddAction( gg_trg_W1MurlocGrenade, function Trig_W1MurlocGrenade_Actions )
endfunction
function Trig_W1MurlocGrenadeProc_Actions takes nothing returns nothing
local unit t = udg_DamageEventTarget
local unit s = udg_DamageEventSource
local effect se
if (GetUnitAbilityLevel(t, 'B00A') < 1) then
return
endif
call UnitRemoveBuffBJ('B00A', t)
set se = AddSpecialEffect("Objects\\Spawnmodels\\NightElf\\NEDeathMedium\\NEDeath.mdl", GetUnitX(t), GetUnitY(t))
call DestroyEffect( se )
call MurlocGrenadeDmg.create(1.0, s, GetUnitLoc(t), udg_DamageEventAmount).startPeriodic()
set udg_DamageEventAmount = 0
call RemoveUnit(t)
set se = null
set t = null
set s = null
endfunction
//===========================================================================
function InitTrig_W1MurlocGrenadeProc takes nothing returns nothing
set gg_trg_W1MurlocGrenadeProc = CreateTrigger( )
call TriggerRegisterVariableEvent( gg_trg_W1MurlocGrenadeProc, "udg_PreDamageEvent", EQUAL, 1.00 )
call TriggerAddAction( gg_trg_W1MurlocGrenadeProc, function Trig_W1MurlocGrenadeProc_Actions )
endfunction
struct MurlocGrenadeDmg
private unit u
private integer nextTick
private integer endTick
private location l
private real dmg
private method periodic takes nothing returns nothing
local unit target
local player p
local group g
local unit duper
if (this.nextTick == T32_Tick) then
set g = CreateGroup()
set p = GetOwningPlayer(u)
call GroupEnumUnitsInRangeOfLoc(g, l, 300, function True_Filter)
loop
set target = FirstOfGroup(g)
exitwhen target == null
call GroupRemoveUnit(g, target)
if IsUnitEnemy(target, p) and UnitAlive(target) and GetUnitAbilityLevel(target, 'Avul') < 1 then
call UnitDamageTargetBJ( u, target, dmg, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_ENHANCED )
endif
if Difficulty.level > 2 and UnitAlive(target) and GetUnitAbilityLevel(target, 'Avul') < 1 then
set duper = CreateUnit(GetOwningPlayer(u), 'h018', GetUnitX(target), GetUnitY(target), bj_UNIT_FACING)
call UnitAddAbility(duper, 'A039')
call IssueTargetOrderById(duper, 852274, target)//wand of illu
call UnitApplyTimedLife(duper, 'BTLF', 2.00)
endif
endloop
call RemoveLocation(l)
call DestroyGroup(g)
set l = null
set p = null
set target = null
set g = null
endif
if this.endTick == T32_Tick then
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes real duration, unit caster, location l, real dmg returns thistype
local thistype this = thistype.allocate()
set this.u = caster
set this.l = l
set this.dmg = dmg
set this.nextTick = T32_Tick + 5
set this.endTick = T32_Tick + R2I(duration / T32_PERIOD)
return this
endmethod
endstruct
function Trig_W1MurlocDupeSummon_Conditions takes nothing returns boolean
return GetUnitTypeId(GetSummoningUnit()) == 'h018'
endfunction
function Trig_W1MurlocDupeSummon_Actions takes nothing returns nothing
local player p = GetOwningPlayer(GetSummoningUnit())
call SetUnitOwner(GetSummonedUnit(), p, true)
endfunction
//===========================================================================
function InitTrig_W1MurlocDupeSummon takes nothing returns nothing
set gg_trg_W1MurlocDupeSummon = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W1MurlocDupeSummon, EVENT_PLAYER_UNIT_SUMMON )
call TriggerAddCondition( gg_trg_W1MurlocDupeSummon, Condition( function Trig_W1MurlocDupeSummon_Conditions ) )
call TriggerAddAction( gg_trg_W1MurlocDupeSummon, function Trig_W1MurlocDupeSummon_Actions )
endfunction
function Trig_W1WavePreload_Actions takes nothing returns nothing
local unit u = PreloadUnit('h014')
call IssuePointOrder(u, "carrionswarm", GetUnitX(u) + 100, GetUnitY(u))
set u = null
endfunction
//===========================================================================
function InitTrig_W1WavePreload takes nothing returns nothing
set gg_trg_W1WavePreload = CreateTrigger( )
call TriggerRegisterTimerEventSingle( gg_trg_W1WavePreload, 5 )
call TriggerAddAction( gg_trg_W1WavePreload, function Trig_W1WavePreload_Actions )
endfunction
struct CrabWave
private unit u
private integer nextTick
private integer endTick
private location lu
private integer stat
private method periodic takes nothing returns nothing
local unit lcu
local location l
if this.endTick == T32_Tick then
if UnitAlive(u) then
set l = GetUnitLoc(u)
set lcu = CreateUnitAtLoc(GetOwningPlayer(u), 'h004', l, bj_UNIT_FACING)
call RemoveLocation(l)
set l = null
call RemoveGuardPosition( lcu )
call UnitAddAbilityBJ( 'A00H', lcu )
call BlzSetAbilityRealLevelField( BlzGetUnitAbility(lcu, 'A00H'), ABILITY_RLF_DAMAGE_UCS1, 0, stat)
call IssuePointOrderLoc(lcu, "carrionswarm", lu)
call UnitApplyTimedLifeBJ( 5.00, 'BTLF', lcu)
set lcu = null
endif
set u = null
call RemoveLocation(lu)
set lu = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes real duration, unit crab, location l, integer stat returns thistype
local thistype this = thistype.allocate()
set this.u = crab
set this.lu = l
set this.nextTick = T32_Tick + 25
set this.endTick = T32_Tick + R2I(duration / T32_PERIOD)
set this.stat = stat
return this
endmethod
endstruct
function Trig_W1V1_AI_Conditions takes nothing returns boolean
return GetUnitTypeId(GetTriggerUnit()) == 'H007'
endfunction
function Trig_W1V1_AI_Actions takes nothing returns nothing
local unit attacked
local unit u
local real x
local real y
local group g
set attacked = GetTriggerUnit()
set x = GetUnitX(attacked)
set y = GetUnitY(attacked)
set g = CreateGroup()
call GroupEnumUnitsInRange(g, x, y, 700, function EAnI_Filter)
set u = FirstOfGroup(g)
if (u != null) then
call IssueTargetOrder(attacked, "thunderbolt", u)
endif
call DestroyGroup(g)
set u = null
set attacked = null
set g = null
endfunction
//===========================================================================
function InitTrig_W1V1_AI takes nothing returns nothing
set gg_trg_W1V1_AI = CreateTrigger( )
call DisableTrigger( gg_trg_W1V1_AI )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W1V1_AI, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddCondition( gg_trg_W1V1_AI, Condition( function Trig_W1V1_AI_Conditions ) )
call TriggerAddAction( gg_trg_W1V1_AI, function Trig_W1V1_AI_Actions )
endfunction
function Trig_W1V1_AI_SummonH_Conditions takes nothing returns boolean
return GetUnitTypeId(GetAttacker()) == 'H007' and Difficulty.level > 2 and GetUnitLifePercent(GetAttacker()) < 75.00
endfunction
function Trig_W1V1_AI_SummonH_Actions takes nothing returns nothing
call IssueImmediateOrder(GetAttacker(), "roar")
endfunction
//===========================================================================
function InitTrig_W1V1_AI_SummonH takes nothing returns nothing
set gg_trg_W1V1_AI_SummonH = CreateTrigger( )
call DisableTrigger( gg_trg_W1V1_AI_SummonH )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W1V1_AI_SummonH, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddCondition( gg_trg_W1V1_AI_SummonH, Condition( function Trig_W1V1_AI_SummonH_Conditions ) )
call TriggerAddAction( gg_trg_W1V1_AI_SummonH, function Trig_W1V1_AI_SummonH_Actions )
endfunction
function Trig_W1MakruraSummon_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A03A'
endfunction
function Trig_W1MakruraSummon_Actions takes nothing returns nothing
local unit caster = GetTriggerUnit()
local unit lcu
local location l
local effect se
local integer count = 5// CountPlayersInForceBJ(udg_HumanPlayers)
local integer i = 0
call BossPrompt(caster, "Hatch crablings")
loop
exitwhen i == count
set l = PolarProjectionU(caster, GetRandomReal(150, 550), GetRandomReal(0, 360))
set lcu = CreateUnitAtLoc(GetOwningPlayer(caster), 'w114', l, bj_UNIT_FACING)
set se = AddSpecialEffectLoc("Objects\\Spawnmodels\\Naga\\NagaDeath\\NagaDeath.mdl", l)
call BlzSetSpecialEffectScale(se, 0.5)
call DestroyEffect(se)
call RegisterCreep(lcu)
set i = i + 1
endloop
set se = null
set l = null
set caster = null
set lcu = null
endfunction
//===========================================================================
function InitTrig_W1MakruraSummon takes nothing returns nothing
set gg_trg_W1MakruraSummon = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W1MakruraSummon, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_W1MakruraSummon, Condition( function Trig_W1MakruraSummon_Conditions ) )
call TriggerAddAction( gg_trg_W1MakruraSummon, function Trig_W1MakruraSummon_Actions )
endfunction
function Trig_W1MakruraWave_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A00I'
endfunction
function Trig_W1MakruraWave_Actions takes nothing returns nothing
local unit caster
local unit target
local location l
set caster = GetTriggerUnit()
set target = GetSpellTargetUnit()
call BossPrompt(caster, "CRUSHING WAVE")
set l = GetUnitLoc(target)
call CrabWave.create(2.0, caster, l, GetHeroInt(caster, true) * 5).startPeriodic()
set l = null
set caster = null
set target = null
endfunction
//===========================================================================
function InitTrig_W1MakruraWave takes nothing returns nothing
set gg_trg_W1MakruraWave = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_W1MakruraWave, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_W1MakruraWave, Condition( function Trig_W1MakruraWave_Conditions ) )
call TriggerAddAction( gg_trg_W1MakruraWave, function Trig_W1MakruraWave_Actions )
endfunction
function Trig_W1MakruraBounce_Conditions takes nothing returns boolean
return GetUnitTypeId(udg_DamageEventSource) == 'H007' and udg_DamageEventType == udg_DAMAGE_TYPE_UNKNOWN
endfunction
function Trig_W1MakruraBounce_Actions takes nothing returns nothing
local unit attacker
local unit lcu
local unit target
local unit u
local integer i
local location l
local group g
local real x
local real y
local player p
set attacker = udg_DamageEventSource
set target = udg_DamageEventTarget
set p = GetOwningPlayer(attacker)
set x = GetUnitX(target)
set y = GetUnitY(target)
set g = CreateGroup()
set i = 0
call GroupEnumUnitsInRange(g, x, y, 350, function True_Filter)
loop
set u = FirstOfGroup(g)
exitwhen u == null or i == 3
call GroupRemoveUnit(g, u)
if (IsUnitEnemy(u,p) and u != target and UnitAlive(u) and GetUnitAbilityLevel(u,'Avul') < 1 ) then
set l = GetUnitLoc(target)
set lcu = CreateUnitAtLoc(p, 'h008', l, bj_UNIT_FACING)
call RemoveLocation (l)
call BlzSetUnitWeaponIntegerField( lcu, UNIT_WEAPON_IF_ATTACK_DAMAGE_BASE, 0, MathRound(1.5 * GetHeroStatBJ(bj_HEROSTAT_STR, attacker, true)) ) //1.5 str
call UnitApplyTimedLifeBJ( 1.00, 'BTLF', lcu )
call IssueTargetOrder(lcu, "attack", u)
set i = i + 1
endif
endloop
set target = null
set attacker = null
set lcu = null
endfunction
//===========================================================================
function InitTrig_W1MakruraBounce takes nothing returns nothing
set gg_trg_W1MakruraBounce = CreateTrigger( )
call TriggerRegisterVariableEvent( gg_trg_W1MakruraBounce, "udg_OnDamageEvent", EQUAL, 1.00 )
call TriggerAddCondition( gg_trg_W1MakruraBounce, Condition( function Trig_W1MakruraBounce_Conditions ) )
call TriggerAddAction( gg_trg_W1MakruraBounce, function Trig_W1MakruraBounce_Actions )
endfunction
function Trig_Surge_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A02G'
endfunction
function SurgeEffect takes unit source, location lt returns nothing
local real distance
local real angle
local PlayableArea pa
local effect se
local group g = CreateGroup()
local integer stat
local integer level
local integer multiplier
local location ls
local unit lcu
local unit t
local integer i = 0
set stat = GetHeroInt(source, true)
set level = GetUnitAbilityLevel(source, 'A02G')
set multiplier = level * 2
set ls = GetUnitLoc(source)
//target loc withing bounds
set distance = DistanceBetweenPoints(ls, lt)
set angle = AngleBetweenPoints(ls, lt)
//IF CURRENT DISTANCE WOULD BE OUTSIDE, BIN SEARCH A SHORTER DISTANCE THAT'S INSIDE. but only if the unit started inside the playable are in the first place
set pa = udg_CURRENT_PLAYABLE_AREA
if (pa.containsLocation(ls)) then
loop
exitwhen pa.containsLocation(lt)
set distance = distance * 0.5
call RemoveLocation(lt)
set lt = PolarProjectionBJ(ls, distance, angle)
endloop
endif
call AddLightningLoc("CLPB", ls, lt)
call DestroyAfterLightning.create(0.30, bj_lastCreatedLightning).startPeriodic()
set se = AddSpecialEffectLoc("Abilities\\Weapons\\Bolt\\BoltImpact.mdl", lt)
call DestroyEffect(se)
call GroupEnumUnitsInRangeOfLoc(g, lt, level * 50 + 250, function EAnI_Filter)
loop
set t = FirstOfGroup(g)
exitwhen t == null
exitwhen i == level * 2
call GroupRemoveUnit(g, t)
set lcu = CreateUnitAtLoc(GetOwningPlayer(source), 'h004', ls, bj_UNIT_FACING)
call UnitAddAbility(lcu, 'A02K')
call UnitApplyTimedLife(lcu, 'BTLF', 2.00)
call BlzSetAbilityRealLevelField( BlzGetUnitAbility(lcu, 'A02K'), ConvertAbilityRealLevelField('Ocl1'), 0, stat * multiplier)
call IssueTargetOrder(lcu, "chainlightning", t)
set i = i + 1
//call UnitDamageTargetBJ( source, tu, multiplier * stat, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_LIGHTNING)
endloop
call BlzEndUnitAbilityCooldown( source, 'A02H' )
call SetUnitX(source, GetLocationX(lt))
call SetUnitY(source, GetLocationY(lt))
set lcu = null
call RemoveLocation(ls)
set ls = null
set lt = null
set source = null
endfunction
function Trig_Surge_Actions takes nothing returns nothing
local location lt = GetSpellTargetLoc()
local unit source = GetTriggerUnit()
local unit lcu = CreateUnit(GetOwningPlayer(source), 'h004', GetUnitX(source), GetUnitY(source), bj_UNIT_FACING)
call UnitAddAbility(lcu, 'A02L')
call IssueTargetOrder(lcu, "innerfire", source)
call UnitApplyTimedLife(lcu, 'BTLF', 2.00)
call SurgeEffect(source, lt)
set lcu = null
set source = null
call RemoveLocation(lt)
set lt = null
endfunction
//===========================================================================
function InitTrig_Surge takes nothing returns nothing
set gg_trg_Surge = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Surge, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Surge, Condition( function Trig_Surge_Conditions ) )
call TriggerAddAction( gg_trg_Surge, function Trig_Surge_Actions )
endfunction
function Trig_Surge_Movement_t takes nothing returns nothing
local timer t = GetExpiredTimer()
call SetUnitFacing(LoadUnitHandle(udg_UtilMap, GetHandleId(t), 0), LoadReal(udg_UtilMap, GetHandleId(t), 1))
call FlushChildHashtable(udg_UtilMap, GetHandleId(t))
call PauseTimer(t)
call DestroyTimer(t)
set t = null
endfunction
function Trig_Surge_Movement_Conditions takes nothing returns boolean
return UnitHasBuffBJ(GetOrderedUnit(), 'B00E')
endfunction
function Trig_Surge_Movement_Actions takes nothing returns nothing
local location lt
local location ls
local unit u
local timer t
//call BJDebugMsg(I2S(GetIssuedOrderId()))
//851986 explict m
//851971 right click
if (851986 != GetIssuedOrderId() and 851971 != GetIssuedOrderId()) then
return
endif
set u = GetOrderedUnit()
set lt = GetOrderPointLoc()
set ls = GetUnitLoc(u)
if (DistanceBetweenPoints(ls, lt) < 400) then
call UnitRemoveAbility(u, 'B00E')
call SurgeEffect(u, lt)
set t = CreateTimer()
call SaveUnitHandle(udg_UtilMap, GetHandleId(t), 0, u)
call SaveReal(udg_UtilMap, GetHandleId(t), 1, AngleBetweenPoints(ls, lt))
call TimerStart(t, 0.1, false, function Trig_Surge_Movement_t)
call RemoveLocation(ls)
set ls = null
call RemoveLocation(lt)
set lt = null
set t = null
endif
set u = null
endfunction
//===========================================================================
function InitTrig_Surge_Movement takes nothing returns nothing
set gg_trg_Surge_Movement = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Surge_Movement, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER )
call TriggerAddCondition( gg_trg_Surge_Movement, Condition( function Trig_Surge_Movement_Conditions ) )
call TriggerAddAction( gg_trg_Surge_Movement, function Trig_Surge_Movement_Actions )
endfunction
struct SnipeSpellLighting
private unit u
private unit target
private integer endTick
private integer nextTick1
private integer nextTick2
private lightning lg1
private lightning lg2
private lightning lg3
private lightning lg4
private real stat
private method periodic takes nothing returns nothing
local location l
local location ll
local unit lcu
if this.nextTick1 == T32_Tick and u != null and UnitAlive(u) then
set l = GetUnitLoc(u)
set ll = PolarProjectionBJ(l, 80, GetUnitFacing(u) + 70)
call AddLightningLoc("CLPB", l, ll)
set lg1 = bj_lastCreatedLightning
call RemoveLocation(ll)
set ll = PolarProjectionBJ(l, 80, GetUnitFacing(u) - 70)
call AddLightningLoc("CLPB", l, ll)
set lg2 = bj_lastCreatedLightning
call RemoveLocation(ll)
call RemoveLocation(l)
endif
if this.nextTick2 == T32_Tick and u != null and UnitAlive(u) then
set l = GetUnitLoc(u)
set ll = PolarProjectionBJ(l, 80, GetUnitFacing(u) + 35)
call AddLightningLoc("CLPB", l, ll)
set lg3 = bj_lastCreatedLightning
call RemoveLocation(ll)
set ll = PolarProjectionBJ(l, 80, GetUnitFacing(u) - 35)
call AddLightningLoc("CLPB", l, ll)
set lg4 = bj_lastCreatedLightning
call RemoveLocation(ll)
call RemoveLocation(l)
endif
if this.endTick == T32_Tick then
if (u != null and UnitAlive(u) and target != null) then
set lcu = CreateUnitAtLoc(GetOwningPlayer(u), 'h004', GetUnitLoc(u), bj_UNIT_FACING)
call UnitAddAbility(lcu, 'A02K')
call UnitApplyTimedLife(lcu, 'BTLF', 2.00)
call BlzSetAbilityRealLevelField( BlzGetUnitAbility(lcu, 'A02K'), ConvertAbilityRealLevelField('Ocl1'), 0, stat)
call IssueTargetOrder(lcu, "chainlightning", target)
set lcu = null
set target = null
endif
if (lg1 != null) then
call DestroyLightning(lg1)
set lg1 = null
endif
if (lg2 != null) then
call DestroyLightning(lg2)
set lg2 = null
endif
if (lg3 != null) then
call DestroyLightning(lg3)
set lg3 = null
endif
if (lg4 != null) then
call DestroyLightning(lg4)
set lg4 = null
endif
set u = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes unit u, unit target, real stat returns thistype
local thistype this = thistype.allocate()
set this.u = u
set this.target = target
set this.endTick = T32_Tick + 32
set this.nextTick1 = T32_Tick + 2 + 12
set this.nextTick2 = T32_Tick + 1 + 24
set this.stat = stat
return this
endmethod
endstruct
function Trig_Snipe_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A02I'
endfunction
function Trig_Snipe_Actions takes nothing returns nothing
local integer stat
local integer level
local real multiplier
local unit u
local location l
set u = GetTriggerUnit()
set stat = GetHeroStatBJ(bj_HEROSTAT_INT, u, true)
set level = GetUnitAbilityLevelSwapped('A02I', u)
set multiplier = level * 4 + 6
set l = GetUnitLoc(u)
call AddSpecialEffectLocBJ( l, "Abilities\\Spells\\Items\\TomeOfRetraining\\TomeOfRetrainingCaster.mdl" )
call DestroyEffect( GetLastCreatedEffectBJ() )
call SnipeSpellLighting.create(u, GetSpellTargetUnit(), multiplier * stat).startPeriodic()
set u = null
endfunction
//===========================================================================
function InitTrig_Snipe takes nothing returns nothing
set gg_trg_Snipe = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Snipe, EVENT_PLAYER_UNIT_SPELL_CAST )
call TriggerAddCondition( gg_trg_Snipe, Condition( function Trig_Snipe_Conditions ) )
call TriggerAddAction( gg_trg_Snipe, function Trig_Snipe_Actions )
endfunction
function Trig_Unit_Dead_Feast_groupFilter takes nothing returns boolean
local boolean retval
local unit u = GetFilterUnit()
local player p = GetOwningPlayer(GetDyingUnit())
set retval = IsUnitEnemy(u,p) and UnitAlive(u) and (GetUnitAbilityLevel(u,'A02F') > 0)
set u = null
set p = null
return retval
endfunction
function Trig_Unit_Dead_Feast_Conditions takes nothing returns boolean
return GetUnitAbilityLevel(GetDyingUnit(), 'Avul') < 1
endfunction
function Trig_Unit_Dead_Feast_Actions takes nothing returns nothing
local integer stat
local integer level
local location ls
local group g = CreateGroup()
local unit source = GetDyingUnit()
local unit t
set ls = GetUnitLoc(source)
call GroupEnumUnitsInRangeOfLoc(g, ls, 350, function Trig_Unit_Dead_Feast_groupFilter)
loop
set t = FirstOfGroup(g)
exitwhen t == null
call GroupRemoveUnit(g, t)
set level = GetUnitAbilityLevel(t, 'A02F')
set stat = level * 25 + 25
call RestoreHealth(t, t, stat)
call RestoreMana(t, t, stat)
endloop
call RemoveLocation(ls)
call DestroyGroup(g)
set g = null
set t = null
set source = null
set ls = null
endfunction
//===========================================================================
function InitTrig_Unit_Dead_Feast takes nothing returns nothing
set gg_trg_Unit_Dead_Feast = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Unit_Dead_Feast, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_Unit_Dead_Feast, Condition( function Trig_Unit_Dead_Feast_Conditions ) )
call TriggerAddAction( gg_trg_Unit_Dead_Feast, function Trig_Unit_Dead_Feast_Actions )
endfunction
function Trig_Whirlwind_Kill_Actions takes nothing returns nothing
local unit source = udg_DamageEventSource
local unit hero
local integer k
if (GetUnitTypeId(source) == 'h004' and GetUnitAbilityLevel(source, 'A02E') > 0) then
set k = GetHandleId(source)
set hero = LoadUnitHandle(udg_DummyToHeroMap, k, 0)
call FlushChildHashtable(udg_DummyToHeroMap, k)
call RestoreMana(hero, hero, 100)
endif
set source = null
set hero = null
endfunction
//===========================================================================
function InitTrig_Whirlwind_Kill takes nothing returns nothing
set gg_trg_Whirlwind_Kill = CreateTrigger( )
call TriggerRegisterVariableEvent( gg_trg_Whirlwind_Kill, "udg_LethalDamageEvent", EQUAL, 1.00 )
call TriggerAddAction( gg_trg_Whirlwind_Kill, function Trig_Whirlwind_Kill_Actions )
endfunction
function Trig_Whirlwind_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A02E'
endfunction
function Trig_Whirlwind_Actions takes nothing returns nothing
local integer stat
local integer level
local real multiplier
local location ls
local location lt
local group g = CreateGroup()
local unit source = GetTriggerUnit()
local unit t
local unit lcu
set stat = GetHeroAgi(source, true)
set level = GetUnitAbilityLevel(source, 'A02E')
set multiplier = level * 1.5 + 0.5
set ls = GetUnitLoc(source)
call GroupEnumUnitsInRangeOfLoc(g, ls, 275, function EAnI_Filter)
//ability tracking by dummy
set lcu = CreateUnitAtLoc(GetOwningPlayer(source), 'h004', ls, bj_UNIT_FACING)
call UnitAddAbility(lcu, 'A02E')
call SaveUnitHandle(udg_DummyToHeroMap, GetHandleId(lcu), 0, source)
call UnitApplyTimedLife(lcu, 'BTLF', 5.00)
//
loop
set t = FirstOfGroup(g)
exitwhen t == null
call GroupRemoveUnit(g, t)
set lt = GetUnitLoc(t)
call UnitDamageTargetBJ( lcu, t, multiplier * stat, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_ENHANCED)
call AddAggro(GetHandleId(t), source, multiplier * stat)
call AddSpecialEffectLocBJ( lt, "Objects\\Spawnmodels\\Human\\HumanBlood\\HumanBloodFootman.mdl" )
call DestroyEffect( GetLastCreatedEffectBJ() )
endloop
call RemoveLocation(ls)
call RemoveLocation(lt)
call DestroyGroup(g)
set t = null
set source = null
set ls = null
set lt = null
set g = null
endfunction
//===========================================================================
function InitTrig_Whirlwind takes nothing returns nothing
set gg_trg_Whirlwind = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Whirlwind, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Whirlwind, Condition( function Trig_Whirlwind_Conditions ) )
call TriggerAddAction( gg_trg_Whirlwind, function Trig_Whirlwind_Actions )
endfunction
function Trig_Overvoltage_groupFilter takes nothing returns boolean
local boolean retval
local unit u = GetFilterUnit()
local player p = GetOwningPlayer(GetTriggerUnit())
set retval = IsUnitEnemy(u,p) and UnitAlive(u) and GetUnitAbilityLevel(u,'Avul') < 1
set u = null
set p = null
return retval
endfunction
function Trig_Overvoltage_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A02H'
endfunction
function Trig_Overvoltage_Actions takes nothing returns nothing
local integer stat
local integer level
local real multiplier
local location ls
local location lt
local group g = CreateGroup()
local unit source = GetTriggerUnit()
local unit t
set stat = GetHeroAgi(source, true)
set level = GetUnitAbilityLevel(source, 'A02H')
set multiplier = level * 1.5 + 0.5
set ls = GetUnitLoc(source)
call GroupEnumUnitsInRangeOfLoc(g, ls, 275, function Trig_Overvoltage_groupFilter)
call AddSpecialEffectLocBJ( ls, "Abilities\\Spells\\Human\\ThunderClap\\ThunderClapCaster.mdl" )
call DestroyEffect( GetLastCreatedEffectBJ() )
loop
set t = FirstOfGroup(g)
exitwhen t == null
call GroupRemoveUnit(g, t)
set lt = GetUnitLoc(t)
call UnitDamageTargetBJ( source, t, multiplier * stat, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_LIGHTNING)
call AddSpecialEffectLocBJ( lt, "Abilities\\Spells\\Orc\\LightningShield\\LightningShieldBuff.mdl" )
call DestroyEffect( GetLastCreatedEffectBJ() )
endloop
call RemoveLocation(ls)
call RemoveLocation(lt)
call DestroyGroup(g)
set t = null
set source = null
set ls = null
set lt = null
set g = null
endfunction
//===========================================================================
function InitTrig_Overvoltage takes nothing returns nothing
set gg_trg_Overvoltage = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Overvoltage, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Overvoltage, Condition( function Trig_Overvoltage_Conditions ) )
call TriggerAddAction( gg_trg_Overvoltage, function Trig_Overvoltage_Actions )
endfunction
function Trig_Flurry_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A02A'
endfunction
function Trig_Flurry_Actions takes nothing returns nothing
local unit caster
set caster = GetTriggerUnit()
call BlzSetAbilityRealLevelField( BlzGetUnitAbility(caster, 'A02A'), ConvertAbilityRealLevelField('Efk1'), 0, GetHeroAgi(caster, true) * 30)
call BlzSetAbilityRealLevelField( BlzGetUnitAbility(caster, 'A02A'), ConvertAbilityRealLevelField('Efk2'), 0, GetHeroAgi(caster, true) * 30 * 3)
call SetUnitAbilityLevel( caster, 'A02A', 0 )
set caster = null
endfunction
//===========================================================================
function InitTrig_Flurry takes nothing returns nothing
set gg_trg_Flurry = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Flurry, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Flurry, Condition( function Trig_Flurry_Conditions ) )
call TriggerAddAction( gg_trg_Flurry, function Trig_Flurry_Actions )
endfunction
function Trig_AfterimageSummon_Conditions takes nothing returns boolean
return GetUnitTypeId(GetSummoningUnit()) == 'h00R'
endfunction
function Trig_AfterimageSummon_Actions takes nothing returns nothing
local group g = CreateGroup()
local unit s = GetSummonedUnit()
local player p = GetOwningPlayer(s)
local unit h = udg_MainHeroes[GetPlayerId(p)]
local unit u
local real threat = 0
call BlzSetUnitMaxHP( s, BlzGetUnitMaxHP(GetSummoningUnit()) )
call SetUnitLifePercentBJ(s, 100 )
call GroupEnumUnitsInRange(g, GetUnitX(s), GetUnitY(s), 500, function True_Filter)
loop
set u = FirstOfGroup(g)
exitwhen u == null
call GroupRemoveUnit(g, u)
set threat = GetAggro(GetHandleId(u), h)
call AddAggro(GetHandleId(u), h, -threat) //set to 0
call AddAggro(GetHandleId(u), s, threat + 200) //transfer + somemore
endloop
call DestroyGroup(g)
set g = null
set s = null
set u = null
set h = null
endfunction
//===========================================================================
function InitTrig_AfterimageSummon takes nothing returns nothing
set gg_trg_AfterimageSummon = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_AfterimageSummon, EVENT_PLAYER_UNIT_SUMMON )
call TriggerAddCondition( gg_trg_AfterimageSummon, Condition( function Trig_AfterimageSummon_Conditions ) )
call TriggerAddAction( gg_trg_AfterimageSummon, function Trig_AfterimageSummon_Actions )
endfunction
function Trig_Afterimage_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A029'
endfunction
function Trig_Afterimage_Actions takes nothing returns nothing
local integer stat
local integer level
local integer multiplier
local location ls
local location lt = GetSpellTargetLoc()
local unit source = GetTriggerUnit()
local unit lcu
local real distance
local real angle
local PlayableArea pa
set stat = GetHeroStr(source, true)
set level = GetUnitAbilityLevel(source, 'A029')
set multiplier = level * 10 + 10
set ls = GetUnitLoc(source)
//target loc withing bounds
set distance = DistanceBetweenPoints(ls, lt)
set angle = AngleBetweenPoints(ls, lt)
//IF CURRENT DISTANCE WOULD BE OUTSIDE, BIN SEARCH A SHORTER DISTANCE THAT'S INSIDE. but only if the unit started inside the playable are in the first place
set pa = udg_CURRENT_PLAYABLE_AREA
if (pa.containsLocation(ls)) then
loop
exitwhen pa.containsLocation(lt)
set distance = distance * 0.5
call RemoveLocation(lt)
set lt = PolarProjectionBJ(ls, distance, angle)
endloop
endif
set lcu = CreateUnitAtLoc(GetOwningPlayer(source), 'h00R', ls, bj_UNIT_FACING)
call UnitAddAbility(lcu, 'A02C')
call BlzSetUnitMaxHP( lcu, multiplier * stat )
call IssueTargetOrderById(lcu, 852274, source)//wand of illu
call UnitApplyTimedLife(lcu, 'BTLF', 2.00)
set lcu = CreateUnitAtLoc(GetOwningPlayer(source), 'h004', ls, bj_UNIT_FACING)
call UnitAddAbility(lcu, 'A02D')
call IssueTargetOrder(lcu, "invisibility", source)
call UnitApplyTimedLife(lcu, 'BTLF', 2.00)
call SetUnitX(source, GetLocationX(lt))
call SetUnitY(source, GetLocationY(lt))
call RemoveLocation(ls)
call RemoveLocation(lt)
set lcu = null
set source = null
set ls = null
set lt = null
endfunction
//===========================================================================
function InitTrig_Afterimage takes nothing returns nothing
set gg_trg_Afterimage = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Afterimage, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Afterimage, Condition( function Trig_Afterimage_Conditions ) )
call TriggerAddAction( gg_trg_Afterimage, function Trig_Afterimage_Actions )
endfunction
function Trig_Stab_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A028'
endfunction
function Trig_Stab_Actions takes nothing returns nothing
local integer stat
local integer level
local real multiplier
local location ls
local location lt
local unit source = GetTriggerUnit()
local unit target = GetSpellTargetUnit()
local real theta
local real diff
local real cos
set stat = GetHeroAgi(source, true)
set level = GetUnitAbilityLevelSwapped('A028', source)
set multiplier = level * 1.5 + 1.5
set ls = GetUnitLoc(source)
set lt = GetUnitLoc(target)
set theta = AngleBetweenPoints(ls, lt)
set diff = GetUnitFacing(target) - theta
set diff = Atan2(Sin(diff * bj_DEGTORAD), Cos(diff * bj_DEGTORAD))
if (RAbsBJ(diff) < bj_PI / 2) then
set multiplier = multiplier * 2
call AddSpecialEffectLocBJ( lt, "Objects\\Spawnmodels\\Human\\HumanBlood\\HumanBloodFootman.mdl" )
call DestroyEffect( GetLastCreatedEffectBJ() )
endif
//call DisplayTextToForce( GetPlayersAll(), R2S(diff) )
call UnitDamageTargetBJ( source, target, multiplier * stat, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_ENHANCED )
call RemoveLocation(ls)
call RemoveLocation(lt)
set target = null
set source = null
set ls = null
set lt = null
endfunction
//===========================================================================
function InitTrig_Stab takes nothing returns nothing
set gg_trg_Stab = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Stab, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Stab, Condition( function Trig_Stab_Conditions ) )
call TriggerAddAction( gg_trg_Stab, function Trig_Stab_Actions )
endfunction
function Trig_Scream_Necro_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A03V'
endfunction
function screamEach takes real dmg, unit u returns nothing
local group g = CreateGroup()
local effect se
local unit gu
call GroupEnumUnitsInRange(g, GetUnitX(u), GetUnitY(u), 600, function EAnI_Filter)
set se = AddSpecialEffect("Abilities\\Spells\\Other\\HowlOfTerror\\HowlCaster.mdl", GetUnitX(u), GetUnitY(u))
call DestroyEffect(se)
loop
set gu = FirstOfGroup(g)
exitwhen gu == null
call GroupRemoveUnit(g, gu)
call UnitDamageTargetBJ(u, gu, dmg, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_ENHANCED)
endloop
call DestroyGroup(g)
set gu = null
set g = null
set se = null
endfunction
function Trig_Scream_Necro_Filter takes nothing returns boolean
local boolean retval
local unit u = GetFilterUnit()
set retval = GetOwningPlayer(GetTriggerUnit()) == GetOwningPlayer(u) and UnitAlive(u) and (GetUnitTypeId(u) == 'h01J' or GetUnitTypeId(u) == 'h01I' or GetUnitTypeId(u) == 'h01K')
set u = null
return retval
endfunction
function Trig_Scream_Necro_Actions takes nothing returns nothing
local integer stat
local integer level
local unit caster = GetTriggerUnit()
local unit gu
local group g = CreateGroup()
local effect se
set stat = GetHeroInt(caster, true)
call screamEach(stat * 2.5, caster)
call GroupEnumUnitsInRange(g, GetUnitX(caster), GetUnitY(caster), 600, function Trig_Scream_Necro_Filter)
loop
set gu = FirstOfGroup(g)
exitwhen gu == null
call GroupRemoveUnit(g, gu)
call screamEach(stat * 2.5, gu)
endloop
call DestroyGroup(g)
set caster = null
set gu = null
set g = null
set se = null
endfunction
//===========================================================================
function InitTrig_Scream_Necro takes nothing returns nothing
set gg_trg_Scream_Necro = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Scream_Necro, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Scream_Necro, Condition( function Trig_Scream_Necro_Conditions ) )
call TriggerAddAction( gg_trg_Scream_Necro, function Trig_Scream_Necro_Actions )
endfunction
struct ManaDrainLink
private unit caster
private unit healed
private unit damaged
private lightning le
private real maxLeash
private real intensity
private integer endTick
private integer nextTick
private method periodic takes nothing returns nothing
if T32_Tick == nextTick then
if UnitDead(healed) or UnitDead(damaged) then
set endTick = T32_Tick
endif
if DistanceBetweenUnits(healed, damaged) > maxLeash then
set endTick = T32_Tick
endif
//TODO drain, and drain multiplier
//call UnitDamageTargetBJ(healed, damaged, 0.25 * intensity, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_ENHANCED)
call RestoreMana(caster, healed, 0.25 * intensity)
call MoveLightning(le, true, GetUnitX(damaged), GetUnitY(damaged), GetUnitX(healed), GetUnitY(healed))
set nextTick = nextTick + 8
endif
if T32_Tick == endTick then
call DestroyLightning(le)
set healed = null
set damaged = null
set caster = null
set le = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes unit caster, unit healed, unit damaged, real intensity, real duration returns thistype
local thistype this = thistype.allocate()
set this.caster = caster
set this.healed = healed
set this.damaged = damaged
set maxLeash = 700.0
set this.intensity = intensity
set nextTick = T32_Tick + 8
set endTick = T32_Tick + R2I(duration / T32_PERIOD)
set le = AddLightning("DRAM", true, GetUnitX(damaged), GetUnitY(damaged), GetUnitX(healed), GetUnitY(healed))
return this
endmethod
endstruct
struct HealthDrainLink
private unit caster
private unit healed
private unit damaged
private lightning le
private real maxLeash
private real intensity
private integer endTick
private integer nextTick
private method periodic takes nothing returns nothing
if T32_Tick == nextTick then
if UnitDead(healed) or UnitDead(damaged) then
set endTick = T32_Tick
endif
if DistanceBetweenUnits(healed, damaged) > maxLeash then
set endTick = T32_Tick
endif
call UnitDamageTargetBJ(healed, damaged, 0.25 * intensity, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_ENHANCED)
call RestoreHealth(caster, healed, 0.25 * intensity)
call MoveLightning(le, true, GetUnitX(damaged), GetUnitY(damaged), GetUnitX(healed), GetUnitY(healed))
set nextTick = nextTick + 8
endif
if T32_Tick == endTick then
call DestroyLightning(le)
set healed = null
set damaged = null
set caster = null
set le = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes unit caster, unit healed, unit damaged, real intensity, real duration returns thistype
local thistype this = thistype.allocate()
set this.caster = caster
set this.healed = healed
set this.damaged = damaged
set maxLeash = 700.0
set this.intensity = intensity
set nextTick = T32_Tick + 8
set endTick = T32_Tick + R2I(duration / T32_PERIOD)
set le = AddLightning("DRAL", true, GetUnitX(damaged), GetUnitY(damaged), GetUnitX(healed), GetUnitY(healed))
return this
endmethod
endstruct
function Trig_Spill_Essence_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A03Q'
endfunction
function Trig_Spill_Essence_Actions takes nothing returns nothing
local integer level
local real multiplier
local unit caster = GetTriggerUnit()
local unit target = GetSpellTargetUnit()
local group g = CreateGroup()
local unit gu
local real duration = 3.0
if GetUnitAbilityLevel(caster, 'A03Q') > 1 then
set duration = 5.0
endif
call HealthDrainLink.create(caster, caster, target, GetHeroInt(caster, true), duration).startPeriodic()
call GroupEnumUnitsInRange(g, GetUnitX(target), GetUnitY(target), 500, function AAnI_Filter)
loop
set gu = FirstOfGroup(g)
exitwhen gu == null
call GroupRemoveUnit(g, gu)
call ManaDrainLink.create(caster, gu, target, GetHeroInt(caster, true) * 0.5, duration).startPeriodic()
endloop
call DestroyGroup(g)
set g = null
set gu = null
set target = null
set caster = null
endfunction
//===========================================================================
function InitTrig_Spill_Essence takes nothing returns nothing
set gg_trg_Spill_Essence = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Spill_Essence, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Spill_Essence, Condition( function Trig_Spill_Essence_Conditions ) )
call TriggerAddAction( gg_trg_Spill_Essence, function Trig_Spill_Essence_Actions )
endfunction
function Trig_Vengeful_Death_Conditions takes nothing returns boolean
return GetUnitTypeId(GetTriggerUnit()) == 'h01J' or GetUnitTypeId(GetTriggerUnit()) == 'h01I' or GetUnitTypeId(GetTriggerUnit()) == 'h01K'
endfunction
function Trig_Vengeful_Death_Actions takes nothing returns nothing
call FlushChildHashtable(udg_DummyToHeroMap, GetHandleId(GetDyingUnit()))
endfunction
//===========================================================================
function InitTrig_Vengeful_Death takes nothing returns nothing
set gg_trg_Vengeful_Death = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Vengeful_Death, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_Vengeful_Death, Condition( function Trig_Vengeful_Death_Conditions ) )
call TriggerAddAction( gg_trg_Vengeful_Death, function Trig_Vengeful_Death_Actions )
endfunction
function Trig_Vengeance_V1_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A03T'
endfunction
function Trig_Vengeance_V1_Actions takes nothing returns nothing
local integer stat
local integer level
local real multiplier
local unit caster = GetTriggerUnit()
local unit hero = LoadUnitHandle(udg_DummyToHeroMap, GetHandleId(GetTriggerUnit()), 'A03R')
set stat = GetHeroInt(hero, true)
call UnitDamageTargetBJ(GetTriggerUnit(), GetSpellTargetUnit(), 3.0 * stat, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_ENHANCED)
set hero = null
set caster = null
endfunction
//===========================================================================
function InitTrig_Vengeance_V1 takes nothing returns nothing
set gg_trg_Vengeance_V1 = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Vengeance_V1, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Vengeance_V1, Condition( function Trig_Vengeance_V1_Conditions ) )
call TriggerAddAction( gg_trg_Vengeance_V1, function Trig_Vengeance_V1_Actions )
endfunction
function Trig_Vengeance_V2_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A03U'
endfunction
function Trig_Vengeance_V2_Actions takes nothing returns nothing
local integer stat
local integer level
local real multiplier
local unit caster = GetTriggerUnit()
local unit hero = LoadUnitHandle(udg_DummyToHeroMap, GetHandleId(GetTriggerUnit()), 'A03R')
local unit target = GetSpellTargetUnit()
local unit gu = null
local group g = CreateGroup()
local effect se
set stat = GetHeroInt(hero, true)
call UnitDamageTargetBJ(GetTriggerUnit(), target, 5.0 * stat, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_ENHANCED)
call GroupEnumUnitsInRange(g, GetUnitX(target), GetUnitY(target), 250, function EAnI_Filter)
call GroupRemoveUnit(g, target)
loop
set gu = FirstOfGroup(g)
exitwhen gu == null
call GroupRemoveUnit(g, gu)
//set se = AddSpecialEffect("Abilities\\Spells\\Undead\\UnholyFrenzyAOE\\UnholyFrenzyAOETarget.mdl", GetUnitX(gu), GetUnitY(gu))
set se = AddSpecialEffect("Abilities\\Spells\\Undead\\DeathPact\\DeathPactTarget.mdl", GetUnitX(gu), GetUnitY(gu))
call DestroyEffect(se)
call UnitDamageTargetBJ(GetTriggerUnit(), gu, 3.0 * stat, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_ENHANCED)
endloop
call DestroyGroup(g)
set caster = null
set hero = null
set target = null
set gu = null
set g = null
set se = null
endfunction
//===========================================================================
function InitTrig_Vengeance_V2 takes nothing returns nothing
set gg_trg_Vengeance_V2 = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Vengeance_V2, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Vengeance_V2, Condition( function Trig_Vengeance_V2_Conditions ) )
call TriggerAddAction( gg_trg_Vengeance_V2, function Trig_Vengeance_V2_Actions )
endfunction
function Trig_Vengeful_Spirit_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A03R'
endfunction
function Trig_Vengeful_Spirit_Actions takes nothing returns nothing
local integer level
local integer stat
local real multiplier
local unit caster
local unit created
local player p
set caster = GetTriggerUnit()
set stat = GetHeroInt(caster, true)
set level = GetUnitAbilityLevel(caster, 'A03R')
set multiplier = level * 0.1 + 0.6 //0.7 8 9
call AddSpecialEffectLocBJ( GetSpellTargetLoc(), "Abilities\\Spells\\Undead\\RaiseSkeletonWarrior\\RaiseSkeleton.mdl" )
call DestroyEffect( GetLastCreatedEffectBJ() )
set p = GetOwningPlayer(caster)
if level == 1 then
set created = CreateUnitAtLoc(p, 'h01J', GetSpellTargetLoc(), bj_UNIT_FACING)
elseif level == 2 then
set created = CreateUnitAtLoc(p, 'h01I', GetSpellTargetLoc(), bj_UNIT_FACING)
elseif level == 3 then
set created = CreateUnitAtLoc(p, 'h01K', GetSpellTargetLoc(), bj_UNIT_FACING)
endif
call UnitApplyTimedLife(created, 'BTLF', 25.00)
call SetUnitVertexColor(created, 255, 255, 255, 60)
call SaveUnitHandle(udg_DummyToHeroMap, GetHandleId(created), 'A03R', caster)
set created = null
set caster = null
endfunction
//===========================================================================
function InitTrig_Vengeful_Spirit takes nothing returns nothing
set gg_trg_Vengeful_Spirit = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Vengeful_Spirit , EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Vengeful_Spirit , Condition( function Trig_Vengeful_Spirit_Conditions) )
call TriggerAddAction( gg_trg_Vengeful_Spirit, function Trig_Vengeful_Spirit_Actions )
endfunction
function Trig_Carrion_Swarm_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A03P'
endfunction
function Trig_Carrion_Swarm_Actions takes nothing returns nothing
local integer stat
local integer level
local real multiplier
local unit u
set u = GetTriggerUnit()
set stat = GetHeroStatBJ(bj_HEROSTAT_INT, u, true)
set level = GetUnitAbilityLevel(u, 'A03P')
set multiplier = level * 0.5 + 3.5
call BlzSetAbilityRealLevelField( BlzGetUnitAbility(u, 'A03P'), ABILITY_RLF_DAMAGE_UCS1, level - 1, stat * multiplier)
call BlzSetAbilityRealLevelField( BlzGetUnitAbility(u, 'A03P'), ABILITY_RLF_MAX_DAMAGE_UCS2, level - 1, stat * multiplier * (2 + level))
set u = null
endfunction
//===========================================================================
function InitTrig_Carrion_Swarm takes nothing returns nothing
set gg_trg_Carrion_Swarm = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Carrion_Swarm, EVENT_PLAYER_UNIT_SPELL_CAST )
call TriggerAddCondition( gg_trg_Carrion_Swarm, Condition( function Trig_Carrion_Swarm_Conditions ) )
call TriggerAddAction( gg_trg_Carrion_Swarm, function Trig_Carrion_Swarm_Actions )
endfunction
struct SkeletonNames
public static integer size = 0
public static string array entries[100]
static method create takes integer utype, string prompt returns thistype
local thistype this = thistype.allocate()
return this
endmethod
static method push takes string s returns nothing
set entries[size] = s
set size = size + 1
endmethod
static method randomName takes nothing returns string s
return entries[GetRandomInt(0, size - 1)]
endmethod
endstruct
function Trig_Flesh_Shield_Struck_Actions takes nothing returns nothing
local unit u
local unit a
local real chance
local integer level
local location l
if udg_IsDamageMelee and udg_IsDamageAttack then
set u = udg_DamageEventTarget
set a = udg_DamageEventSource
set level = GetUnitAbilityLevel(u, 'A01D')
set chance = GetRandomReal(0, 1)
if (level > 0 and chance > (0.7 - 0.1 * level)) then
set l = GetUnitLoc(a)
call AddSpecialEffectLocBJ(l, "Objects\\Spawnmodels\\Orc\\OrcSmallDeathExplode\\OrcSmallDeathExplode.mdl" )
call DestroyEffect(GetLastCreatedEffectBJ())
call RemoveLocation(l)
call UnitDamageTargetBJ(u, a, level * GetHeroStr(u, true), ATTACK_TYPE_NORMAL, DAMAGE_TYPE_ENHANCED)
set l = null
endif
set u = null
set a = null
endif
endfunction
//===========================================================================
function InitTrig_Flesh_Shield_Struck takes nothing returns nothing
set gg_trg_Flesh_Shield_Struck = CreateTrigger( )
call TriggerRegisterVariableEvent( gg_trg_Flesh_Shield_Struck, "udg_OnDamageEvent", EQUAL, 1.00 )
call TriggerAddAction( gg_trg_Flesh_Shield_Struck, function Trig_Flesh_Shield_Struck_Actions )
endfunction
function Trig_Flesh_Shield_Pick_Conditions takes nothing returns boolean
return GetLearnedSkill() == 'A01D'
endfunction
function Trig_Flesh_Shield_Pick_Actions takes nothing returns nothing
local integer level
local unit u
set u = GetLearningUnit()
set level = GetUnitAbilityLevel(u, 'A01D')
call BlzSetAbilityIntegerLevelField( BlzGetUnitAbility(u, 'A019'), ABILITY_ILF_DEFENSE_BONUS_IDEF, 1, level * 3 )
call BlzSetAbilityIntegerLevelField( BlzGetUnitAbility(u, 'A019'), ABILITY_ILF_DEFENSE_BONUS_IDEF, 2, level * 3 )
call SetUnitAbilityLevelSwapped( 'A019', u, 1 )
call SetUnitAbilityLevelSwapped( 'A019', u, 2 )
set u = null
endfunction
//===========================================================================
function InitTrig_Flesh_Shield_Pick takes nothing returns nothing
set gg_trg_Flesh_Shield_Pick = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Flesh_Shield_Pick, EVENT_PLAYER_HERO_SKILL )
call TriggerAddCondition( gg_trg_Flesh_Shield_Pick, Condition( function Trig_Flesh_Shield_Pick_Conditions ) )
call TriggerAddAction( gg_trg_Flesh_Shield_Pick, function Trig_Flesh_Shield_Pick_Actions )
endfunction
function countItemCopies takes unit u, integer iType returns integer
local integer count = 0
local integer i = 0
local item itemAtSlot
loop
exitwhen i == 6
set itemAtSlot = UnitItemInSlot(u, i)
if (itemAtSlot != null and GetItemTypeId(itemAtSlot) == iType) then
set count = count + 1
endif
set i = i + 1
endloop
return count
endfunction
function Fill_Invetory takes unit summon, unit summoner returns nothing
local integer countOffense = countItemCopies(summoner, 'I004')
local integer countDefense = countItemCopies(summoner, 'I005')
local integer countSupport = countItemCopies(summoner, 'I006')
local integer i
//max 3 across
set countOffense = IMinBJ(countOffense, 3)
set countDefense = IMinBJ(countDefense, 3 - countOffense)
set countSupport = IMinBJ(countSupport, 3 - countOffense - countDefense)
set i = 0
loop
exitwhen i >= countOffense
call UnitAddItemByIdSwapped(udg_ItemListOffensePackage[i * 2], summon)
call SetItemDroppable (bj_lastCreatedItem,false)
call UnitAddItemByIdSwapped(udg_ItemListOffensePackage[i * 2 + 1], summon)
call SetItemDroppable (bj_lastCreatedItem,false)
set i = i + 1
endloop
set i = 0
loop
exitwhen i >= countDefense
call UnitAddItemByIdSwapped(udg_ItemListDefensePackage[i * 2], summon)
call SetItemDroppable (bj_lastCreatedItem,false)
call UnitAddItemByIdSwapped(udg_ItemListDefensePackage[i * 2 + 1], summon)
call SetItemDroppable (bj_lastCreatedItem,false)
set i = i + 1
endloop
set i = 0
loop
exitwhen i >= countSupport
call UnitAddItemByIdSwapped(udg_ItemListSupportPackage[i * 2], summon)
call SetItemDroppable (bj_lastCreatedItem,false)
call UnitAddItemByIdSwapped(udg_ItemListSupportPackage[i * 2 + 1], summon)
call SetItemDroppable (bj_lastCreatedItem,false)
set i = i + 1
endloop
set i = 0
loop
exitwhen i >= 3 - countOffense - countDefense - countSupport
call UnitAddItemByIdSwapped( 'I000', summon )
call SetItemDroppable (bj_lastCreatedItem,false)
call UnitAddItemByIdSwapped( 'I000', summon )
call SetItemDroppable (bj_lastCreatedItem,false)
set i = i + 1
endloop
endfunction
function Trig_No_Rest_groupFilter takes nothing returns boolean
local boolean retval
local unit u = GetFilterUnit()
set retval = UnitDead(u) and IsUnitInGroup(u, udg_Gladiators)
set u = null
return retval
endfunction
function Trig_No_Rest_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A00R'
endfunction
function Trig_No_Rest_Actions takes nothing returns nothing
local integer key
local integer level
local integer stat
local real multiplier
local unit caster
local unit u
local unit created
local unit alreadyInPlayWicked
local location lu
local group g
local player p
local boolean reviveHappened = false
set caster = GetTriggerUnit()
set stat = GetHeroStatBJ(bj_HEROSTAT_INT, caster, true)
set level = GetUnitAbilityLevelSwapped('A00R', caster)
set multiplier = level * 0.1 + 0.6 //0.7 8 9
//revive, if minions are already in play skip
set g = GetUnitsInRangeOfLocMatching(100 + 25, GetSpellTargetLoc(), function Trig_No_Rest_groupFilter )
loop
set u = FirstOfGroup(g)
exitwhen u == null
call GroupRemoveUnit(g, u)
set key = GetHandleId(u)
set alreadyInPlayWicked = LoadUnitHandleBJ('A00R', key, udg_UniqueEffectsMap)
if (alreadyInPlayWicked == null) then
set lu = GetUnitLoc(u)
call AddSpecialEffectLocBJ( lu, "Abilities\\Spells\\Undead\\RaiseSkeletonWarrior\\RaiseSkeleton.mdl" )
call DestroyEffect( GetLastCreatedEffectBJ() )
set p = GetOwningPlayer(u)
set created = CreateUnitAtLoc(p, 'U006', lu, bj_UNIT_FACING)
call ModifyHeroStat( bj_HEROSTAT_STR, created , bj_MODIFYMETHOD_SET, MathRound(multiplier * stat) )
call ModifyHeroStat( bj_HEROSTAT_AGI, created , bj_MODIFYMETHOD_SET, MathRound(multiplier * stat * 0.6) )
call ModifyHeroStat( bj_HEROSTAT_INT, created , bj_MODIFYMETHOD_SET, MathRound(multiplier * stat * 0.6) )
set reviveHappened = true
call RemoveLocation(lu)
call SaveUnitHandleBJ(created, 'A00R', key, udg_UniqueEffectsMap)
call ROUND_STATS.registerRevive(GetOwningPlayer(caster), p)
exitwhen true
endif
endloop
//remove then create new
if (reviveHappened == false) then
set key = GetHandleId(caster)
set alreadyInPlayWicked = LoadUnitHandleBJ('A00R', key, udg_UniqueEffectsMap)
if (alreadyInPlayWicked != null) then
call RemoveUnit(alreadyInPlayWicked )
set lu = GetUnitLoc(alreadyInPlayWicked)
call AddSpecialEffectLocBJ( lu, "Abilities\\Spells\\Undead\\RaiseSkeletonWarrior\\RaiseSkeleton.mdl" )
call DestroyEffect( GetLastCreatedEffectBJ() )
call RemoveLocation(lu)
endif
set multiplier = level * 0.2 + 0.1 //0. 3 5 7
call AddSpecialEffectLocBJ( GetSpellTargetLoc(), "Abilities\\Spells\\Undead\\RaiseSkeletonWarrior\\RaiseSkeleton.mdl" )
call DestroyEffect( GetLastCreatedEffectBJ() )
set p = GetOwningPlayer(caster)
set created = CreateUnitAtLoc(p, 'U006', GetSpellTargetLoc(), bj_UNIT_FACING)
call ModifyHeroStat( bj_HEROSTAT_STR, created , bj_MODIFYMETHOD_SET, MathRound(multiplier * stat) )
call ModifyHeroStat( bj_HEROSTAT_AGI, created , bj_MODIFYMETHOD_SET, MathRound(multiplier * stat * 0.6) )
call ModifyHeroStat( bj_HEROSTAT_INT, created , bj_MODIFYMETHOD_SET, MathRound(multiplier * stat * 0.6) )
call SaveUnitHandleBJ(created, 'A00R', key, udg_UniqueEffectsMap)
endif
call BlzSetHeroProperName(created, SkeletonNames.randomName())
call Fill_Invetory(created, caster)
if level > 1 then
call SetHeroLevel(created, level, false)
endif
call DestroyGroup(g)
set created = null
set u = null
set lu = null
set alreadyInPlayWicked = null
set p = null
set g = null
endfunction
//===========================================================================
function InitTrig_No_Rest takes nothing returns nothing
set gg_trg_No_Rest = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_No_Rest , EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_No_Rest , Condition( function Trig_No_Rest_Conditions) )
call TriggerAddAction( gg_trg_No_Rest, function Trig_No_Rest_Actions )
endfunction
function Trig_No_Rest_Mage_groupFilter takes nothing returns boolean
local boolean retval
local unit u = GetFilterUnit()
set retval = UnitDead(u) and IsUnitInGroup(u, udg_Gladiators)
set u = null
return retval
endfunction
function Trig_No_Rest_Mage_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A017'
endfunction
function Trig_No_Rest_Mage_Actions takes nothing returns nothing
local integer key
local integer level
local integer stat
local real multiplier
local unit caster
local unit u
local unit created
local unit alreadyInPlayWicked
local location lu
local group g
local player p
local boolean reviveHappened = false
set caster = GetTriggerUnit()
set stat = GetHeroStatBJ(bj_HEROSTAT_INT, caster, true)
set level = GetUnitAbilityLevelSwapped('A017', caster)
set multiplier = level * 0.1 + 0.6 //0.7 8 9
//revive, if minions are already in play skip
set g = GetUnitsInRangeOfLocMatching(100 + 25, GetSpellTargetLoc(), function Trig_No_Rest_Mage_groupFilter )
loop
set u = FirstOfGroup(g)
exitwhen u == null
call GroupRemoveUnit(g, u)
set key = GetHandleId(u)
set alreadyInPlayWicked = LoadUnitHandleBJ('A00R', key, udg_UniqueEffectsMap)
if (alreadyInPlayWicked == null) then
set lu = GetUnitLoc(u)
call AddSpecialEffectLocBJ( lu, "Abilities\\Spells\\Undead\\RaiseSkeletonWarrior\\RaiseSkeleton.mdl" )
call DestroyEffect( GetLastCreatedEffectBJ() )
set p = GetOwningPlayer(u)
set created = CreateUnitAtLoc(p, 'U008', lu, bj_UNIT_FACING)
call ModifyHeroStat( bj_HEROSTAT_STR, created , bj_MODIFYMETHOD_SET, MathRound(multiplier * stat) )
call ModifyHeroStat( bj_HEROSTAT_AGI, created , bj_MODIFYMETHOD_SET, MathRound(multiplier * stat * 0.6) )
call ModifyHeroStat( bj_HEROSTAT_INT, created , bj_MODIFYMETHOD_SET, MathRound(multiplier * stat * 0.6) )
set reviveHappened = true
call RemoveLocation(lu)
call SaveUnitHandleBJ(created, 'A00R', key, udg_UniqueEffectsMap)
call ROUND_STATS.registerRevive(GetOwningPlayer(caster), p)
exitwhen true
endif
endloop
//remove then create new
if (reviveHappened == false) then
set key = GetHandleId(caster)
set alreadyInPlayWicked = LoadUnitHandleBJ('A00R', key, udg_UniqueEffectsMap)
if (alreadyInPlayWicked != null) then
call RemoveUnit(alreadyInPlayWicked )
set lu = GetUnitLoc(alreadyInPlayWicked)
call AddSpecialEffectLocBJ( lu, "Abilities\\Spells\\Undead\\RaiseSkeletonWarrior\\RaiseSkeleton.mdl" )
call DestroyEffect( GetLastCreatedEffectBJ() )
call RemoveLocation(lu)
endif
set multiplier = level * 0.2 + 0.1 //0. 3 5 7
call AddSpecialEffectLocBJ( GetSpellTargetLoc(), "Abilities\\Spells\\Undead\\RaiseSkeletonWarrior\\RaiseSkeleton.mdl" )
call DestroyEffect( GetLastCreatedEffectBJ() )
set p = GetOwningPlayer(caster)
set created = CreateUnitAtLoc(p, 'U008', GetSpellTargetLoc(), bj_UNIT_FACING)
call ModifyHeroStat( bj_HEROSTAT_STR, created , bj_MODIFYMETHOD_SET, MathRound(multiplier * stat * 0.6) )
call ModifyHeroStat( bj_HEROSTAT_AGI, created , bj_MODIFYMETHOD_SET, MathRound(multiplier * stat * 0.6) )
call ModifyHeroStat( bj_HEROSTAT_INT, created , bj_MODIFYMETHOD_SET, MathRound(multiplier * stat) )
call SaveUnitHandleBJ(created, 'A00R', key, udg_UniqueEffectsMap)
endif
call BlzSetHeroProperName(created, SkeletonNames.randomName())
call Fill_Invetory(created, caster)
if level > 1 then
call SetHeroLevel(created, level, false)
endif
call DestroyGroup(g)
set created = null
set u = null
set lu = null
set alreadyInPlayWicked = null
set p = null
set g = null
endfunction
//===========================================================================
function InitTrig_No_Rest_Mage takes nothing returns nothing
set gg_trg_No_Rest_Mage = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_No_Rest_Mage , EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_No_Rest_Mage , Condition( function Trig_No_Rest_Mage_Conditions) )
call TriggerAddAction( gg_trg_No_Rest_Mage, function Trig_No_Rest_Mage_Actions )
endfunction
function Trig_Soul_Harvest_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A018'
endfunction
function Trig_Soul_Harvest_Actions takes nothing returns nothing
local integer stat
local integer level
local unit caster
local real multiplier
local location l
set caster = GetTriggerUnit()
set stat = GetHeroStatBJ(bj_HEROSTAT_INT, caster, true)
set level = GetUnitAbilityLevelSwapped('A018', caster)
set multiplier = level * 0.5 + 2.5
call UnitDamageTargetBJ( caster, GetSpellTargetUnit(), multiplier * stat, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_ENHANCED )
//set multiplier = level * 0.5 + 1.0
call RestoreHealth(caster, caster, multiplier * stat)
set l = GetUnitLoc(GetSpellTargetUnit())
call AddSpecialEffectLocBJ( l, "Abilities\\Spells\\Undead\\DeathPact\\DeathPactTarget.mdl" )
call DestroyEffect( GetLastCreatedEffectBJ() )
call RemoveLocation(l)
set l = GetUnitLoc(caster)
//call AddSpecialEffectLocBJ( l, "Abilities\\Spells\\Undead\\DeathPact\\DeathPactCaster.mdl" )
//call DestroyEffectBJ( GetLastCreatedEffectBJ() )
call RemoveLocation(l)
set l = null
set caster = null
endfunction
//===========================================================================
function InitTrig_Soul_Harvest takes nothing returns nothing
set gg_trg_Soul_Harvest = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Soul_Harvest, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Soul_Harvest, Condition( function Trig_Soul_Harvest_Conditions ) )
call TriggerAddAction( gg_trg_Soul_Harvest, function Trig_Soul_Harvest_Actions )
endfunction
function Trig_Discharge_groupFilter takes nothing returns boolean
local boolean retval
local unit u = GetFilterUnit()
local player p = GetOwningPlayer(GetTriggerUnit())
set retval = IsUnitAlly(u,p) and UnitAlive(u)
set u = null
set p = null
return retval
endfunction
function Trig_Discharge_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A012'
endfunction
function Trig_Discharge_Actions takes nothing returns nothing
local location l
local location lu
local group g
local unit u
local unit caster
set caster = GetTriggerUnit()
set l = GetUnitLoc(caster)
set g = GetUnitsInRangeOfLocMatching(500, l, function Trig_Discharge_groupFilter )
loop
set u = FirstOfGroup(g)
exitwhen u == null
call GroupRemoveUnit(g, u)
set lu = GetUnitLoc(u)
call AddSpecialEffectLocBJ( lu, "Abilities\\Spells\\Items\\TomeOfRetraining\\TomeOfRetrainingCaster.mdl" )
call DestroyEffect( GetLastCreatedEffectBJ() )
call UnitAddAbilityBJ( 'A013', u)
call DischargeDuration.create(10.0, u).startPeriodic()
endloop
call RemoveLocation(l)
call DestroyGroup(g)
set lu = null
set l = null
set g = null
set caster = null
endfunction
//===========================================================================
function InitTrig_Discharge takes nothing returns nothing
set gg_trg_Discharge = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Discharge, EVENT_PLAYER_UNIT_SPELL_CHANNEL )
call TriggerAddCondition( gg_trg_Discharge, Condition( function Trig_Discharge_Conditions ) )
call TriggerAddAction( gg_trg_Discharge, function Trig_Discharge_Actions )
endfunction
function Trig_Discharge_Effect_Conditions takes nothing returns boolean
return UnitHasBuffBJ(udg_DamageEventSource, 'B005') and udg_IsDamageAttack
endfunction
function Trig_Discharge_Effect_Actions takes nothing returns nothing
local location l
local unit target
local unit attacker
local real amount
set attacker = udg_DamageEventSource
set target = udg_DamageEventTarget
set amount = udg_DamageEventAmount
set l = GetUnitLoc(target)
call AddSpecialEffectLocBJ( l, "Abilities\\Spells\\Human\\Thunderclap\\ThunderClapCaster.mdl" )
call DestroyEffect( GetLastCreatedEffectBJ() )
call UnitDamageTargetBJ( attacker, target, amount, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_LIGHTNING )
call RemoveLocation(l)
set attacker = null
set target = null
set l = null
endfunction
//===========================================================================
function InitTrig_Discharge_Effect takes nothing returns nothing
set gg_trg_Discharge_Effect = CreateTrigger( )
call TriggerRegisterVariableEvent( gg_trg_Discharge_Effect, "udg_OnDamageEvent", EQUAL, 1.00 )
call TriggerAddCondition( gg_trg_Discharge_Effect, Condition( function Trig_Discharge_Effect_Conditions ) )
call TriggerAddAction( gg_trg_Discharge_Effect, function Trig_Discharge_Effect_Actions )
endfunction
struct DischargeDuration
private unit u
private integer endTick
private method periodic takes nothing returns nothing
if this.endTick == T32_Tick then
if (u != null) then
call UnitRemoveAbilityBJ( 'A013', u)
call UnitRemoveBuffBJ( 'B005', u)
endif
set u = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes real duration, unit u returns thistype
local thistype this = thistype.allocate()
set this.u = u
set this.endTick = T32_Tick + R2I(duration / T32_PERIOD)
return this
endmethod
endstruct
function Trig_Forked_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A011'
endfunction
function Trig_Forked_Actions takes nothing returns nothing
local integer stat
local integer level
local real multiplier
local unit u
set u = GetTriggerUnit()
set stat = GetHeroStatBJ(bj_HEROSTAT_INT, u, true)
set level = GetUnitAbilityLevel(u, 'A011')
set multiplier = level * 0.5 + 4
call BlzSetAbilityRealLevelField( BlzGetUnitAbility(u, 'A011'), ABILITY_RLF_DAMAGE_PER_TARGET_OCL1, level - 1, stat * multiplier)
set u = null
endfunction
//===========================================================================
function InitTrig_Forked takes nothing returns nothing
set gg_trg_Forked = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Forked, EVENT_PLAYER_UNIT_SPELL_CAST )
call TriggerAddCondition( gg_trg_Forked, Condition( function Trig_Forked_Conditions ) )
call TriggerAddAction( gg_trg_Forked, function Trig_Forked_Actions )
endfunction
function Trig_Reinvigorate_Flesh_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A010'
endfunction
function Trig_Reinvigorate_Flesh_Actions takes nothing returns nothing
local integer stat
local integer level
local real multiplier
local unit caster
local unit target
local location l
set caster = GetTriggerUnit()
set target = GetSpellTargetUnit()
set stat = GetHeroStatBJ(bj_HEROSTAT_INT, caster, true)
set level = GetUnitAbilityLevel(caster, 'A010')
set multiplier = level * 1.5 + 3
set l = GetUnitLoc(target)
call AddSpecialEffectLocBJ( l, "Doodads\\Cinematic\\Lightningbolt\\Lightningbolt.mdl" )
call DestroyAfterSpecialEffect.create(2.0, GetLastCreatedEffectBJ()).startPeriodic()
call AddSpecialEffectLocBJ( l, "Abilities\\Spells\\Orc\\WarStomp\\WarStompCaster.mdl" )
call DestroyEffect( GetLastCreatedEffectBJ() )
call RestoreHealth(caster, target, multiplier * stat)
call RemoveLocation(l)
set l = null
set target = null
set caster = null
endfunction
//===========================================================================
function InitTrig_Reinvigorate_Flesh takes nothing returns nothing
set gg_trg_Reinvigorate_Flesh = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Reinvigorate_Flesh, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Reinvigorate_Flesh, Condition( function Trig_Reinvigorate_Flesh_Conditions ) )
call TriggerAddAction( gg_trg_Reinvigorate_Flesh, function Trig_Reinvigorate_Flesh_Actions )
endfunction
function Trig_Wicked_Slash_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A00V'
endfunction
function Trig_Wicked_Slash_Actions takes nothing returns nothing
local integer stat
set stat = GetHeroStatBJ(bj_HEROSTAT_STR, GetTriggerUnit(), true)
call UnitDamageTargetBJ( GetTriggerUnit(), GetSpellTargetUnit(), 6.0 * stat, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_ENHANCED )
endfunction
//===========================================================================
function InitTrig_Wicked_Slash takes nothing returns nothing
set gg_trg_Wicked_Slash = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Wicked_Slash, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Wicked_Slash, Condition( function Trig_Wicked_Slash_Conditions ) )
call TriggerAddAction( gg_trg_Wicked_Slash, function Trig_Wicked_Slash_Actions )
endfunction
function Trig_Wicked_Coil_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A01B'
endfunction
function Trig_Wicked_Coil_Actions takes nothing returns nothing
local integer stat
set stat = GetHeroStatBJ(bj_HEROSTAT_INT, GetTriggerUnit(), true)
call BlzSetAbilityRealLevelField( BlzGetUnitAbility(GetTriggerUnit(), 'A01B'), ABILITY_RLF_AMOUNT_HEALED_DAMAGED_UDC1, 0, stat * 12.0)
endfunction
//===========================================================================
function InitTrig_Wicked_Coil takes nothing returns nothing
set gg_trg_Wicked_Coil = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Wicked_Coil, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Wicked_Coil, Condition( function Trig_Wicked_Coil_Conditions ) )
call TriggerAddAction( gg_trg_Wicked_Coil, function Trig_Wicked_Coil_Actions )
endfunction
function Trig_Death_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A00T'
endfunction
function Trig_Death_Actions takes nothing returns nothing
local integer stat
local location l
local unit u
set u = GetSpellTargetUnit()
set l = GetUnitLoc(u)
set stat = GetHeroStatBJ(bj_HEROSTAT_INT, GetTriggerUnit(), true)
if (UnitHasBuffBJ(u, 'B004')) then
call UnitDamageTargetBJ( GetTriggerUnit(), u, 12.0 * stat, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_DEATH )
call AddSpecialEffectLocBJ(l, "Abilities\\Spells\\Undead\\DeathandDecay\\DeathandDecayTarget.mdl" )
call DestroyEffect( GetLastCreatedEffectBJ() )
call AddSpecialEffectLocBJ(l, "Objects\\Spawnmodels\\Undead\\UndeadDissipate\\UndeadDissipate.mdl" )
call DestroyEffect( GetLastCreatedEffectBJ() )
else
call UnitDamageTargetBJ( GetTriggerUnit(), u, 8.0 * stat, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_DEATH )
call AddSpecialEffectLocBJ(l, "Abilities\\Spells\\Undead\\DeathandDecay\\DeathandDecayTarget.mdl" )
call DestroyEffect( GetLastCreatedEffectBJ() )
endif
call RemoveLocation( l )
set l = null
set u = null
endfunction
//===========================================================================
function InitTrig_Death takes nothing returns nothing
set gg_trg_Death = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Death, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Death, Condition( function Trig_Death_Conditions) )
call TriggerAddAction( gg_trg_Death, function Trig_Death_Actions )
endfunction
function Trig_Decay_groupFilter takes nothing returns boolean
local boolean retval
local unit u = GetFilterUnit()
local player p = GetOwningPlayer(GetTriggerUnit())
set retval = IsUnitEnemy(u,p) and UnitAlive(u) and GetUnitAbilityLevel(u,'Avul') < 1
set u = null
set p = null
return retval
endfunction
function Trig_Decay_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A00Q'
endfunction
function Trig_Decay_Actions takes nothing returns nothing
local integer level
local integer stat
local unit caster
local unit u
local unit dummyBuff
local location lu
local location lc
local group g
set caster = GetTriggerUnit()
set stat = GetHeroStatBJ(bj_HEROSTAT_INT, caster, true)
set level = GetUnitAbilityLevel(caster, 'A00Q')
set lc = GetUnitLoc(caster)
set g = GetUnitsInRangeOfLocMatching(25 + level * 75, GetSpellTargetLoc(), function Trig_Decay_groupFilter )
loop
set u = FirstOfGroup(g)
exitwhen u == null
call GroupRemoveUnit(g, u)
set lu = GetUnitLoc(u)
call AddSpecialEffectLocBJ( lu, "Abilities\\Spells\\Undead\\DeathandDecay\\DeathandDecayTarget.mdl" )
//call AddSpecialEffectLocBJ( lu, "Objects\\Spawnmodels\\Undead\\UndeadDissipate\\UndeadDissipate.mdl" )
call DestroyEffect( GetLastCreatedEffectBJ() )
call UnitDamageTargetBJ( caster, u, 3 * stat, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_DEATH )
set dummyBuff = CreateUnitAtLoc(GetOwningPlayer(caster), 'h004', lc, bj_UNIT_FACING )
call UnitAddAbilityBJ( 'A00U', dummyBuff)
call UnitApplyTimedLifeBJ( 2.00, 'BTLF', dummyBuff)
call IssueTargetOrder( dummyBuff, "curse", u)
call RemoveLocation(lu)
endloop
call DestroyGroup(g)
call RemoveLocation (lc)
set g = null
set u = null
set caster = null
set lu = null
set lc = null
endfunction
//===========================================================================
function InitTrig_Decay takes nothing returns nothing
set gg_trg_Decay = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Decay, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Decay, Condition( function Trig_Decay_Conditions) )
call TriggerAddAction( gg_trg_Decay, function Trig_Decay_Actions )
endfunction
function Trig_Mass_Cripple_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A01A'
endfunction
function Trig_Mass_Cripple_Actions takes nothing returns nothing
local integer level
local integer stat
local unit caster
local unit u
local unit dummyBuff
local location lc
local group g
local real manaToRestore = 0
local real startMana = 0
local real maxResto = 0
set caster = GetTriggerUnit()
set stat = GetHeroInt(caster, true)
set level = GetUnitAbilityLevel(caster, 'A01A')
set lc = GetUnitLoc(caster)
set g = CreateGroup()
call GroupEnumUnitsInRangeOfLoc(g, GetSpellTargetLoc(), 300, function EAnI_Filter)
loop
set u = FirstOfGroup(g)
exitwhen u == null
call GroupRemoveUnit(g, u)
set dummyBuff = CreateUnitAtLoc(GetOwningPlayer(caster), 'h004', lc, bj_UNIT_FACING )
call UnitAddAbility(dummyBuff, 'A01C')
call UnitApplyTimedLife(dummyBuff, 'BTLF', 2.00)
call IssueTargetOrder(dummyBuff, "cripple", u)
set manaToRestore = manaToRestore + 25.0
endloop
call DestroyGroup(g)
call RestoreManaTimed.create(0.3, caster, caster, manaToRestore).startPeriodic()
call RemoveLocation (lc)
set g = null
set u = null
set caster = null
set lc = null
endfunction
//===========================================================================
function InitTrig_Mass_Cripple takes nothing returns nothing
set gg_trg_Mass_Cripple = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Mass_Cripple, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Mass_Cripple, Condition( function Trig_Mass_Cripple_Conditions) )
call TriggerAddAction( gg_trg_Mass_Cripple, function Trig_Mass_Cripple_Actions )
endfunction
struct NecromanticPowerEffect
private unit u
private unit caster
private integer endTick
private real amount
private method periodic takes nothing returns nothing
if (ModuloInteger(this.endTick - T32_Tick, 16) == 0) then
if (u != null) then
call RestoreHealth(caster, u, amount)
endif
endif
if this.endTick == T32_Tick then
if (u != null) then
call SaveInteger(udg_UniqueEffectsMap, GetHandleId(u), 'A00P', 0)
endif
set u = null
set caster = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes real duration, unit u, unit caster, real healPower returns thistype
local thistype this = thistype.allocate()
set this.u = u
set this.caster = caster
set this.amount = healPower
set this.endTick = T32_Tick + R2I(duration / T32_PERIOD)
return this
endmethod
method addDuration takes real duration returns nothing
set this.endTick = T32_Tick + R2I(duration / T32_PERIOD)
endmethod
endstruct
function Trig_Necromantic_Power_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A00P'
endfunction
function Trig_Necromantic_Power_Actions takes nothing returns nothing
local NecromanticPowerEffect npe
local integer key
local integer level
local integer stat
local real multiplier
set stat = GetHeroStatBJ(bj_HEROSTAT_INT, GetTriggerUnit(), true)
set level = GetUnitAbilityLevel(GetTriggerUnit(), 'A00P')
set multiplier = (level - 1) * 0.2 + 0.2
set key = GetHandleId(GetSpellTargetUnit())
set npe = LoadInteger(udg_UniqueEffectsMap, key, 'A00P')
if (npe == null) then
set npe = NecromanticPowerEffect.create(20.0, GetSpellTargetUnit(), GetTriggerUnit(), multiplier * stat)
call npe.startPeriodic()
call SaveInteger(udg_UniqueEffectsMap, key, 'A00P', npe)
else
call npe.addDuration(20.0)
endif
endfunction
//===========================================================================
function InitTrig_Necromantic_Power takes nothing returns nothing
set gg_trg_Necromantic_Power = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Necromantic_Power, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Necromantic_Power, Condition( function Trig_Necromantic_Power_Conditions ) )
call TriggerAddAction( gg_trg_Necromantic_Power, function Trig_Necromantic_Power_Actions )
endfunction
function Trig_Razor_Slash_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A004'
endfunction
function Trig_Razor_Slash_Actions takes nothing returns nothing
local integer stat
local integer level
local real multiplier
set stat = GetHeroStr(GetTriggerUnit(), true)
set level = GetUnitAbilityLevel(GetTriggerUnit(), 'A004')
set multiplier = level * 2.5 + 2.0
call UnitDamageTargetBJ(GetTriggerUnit(), GetSpellTargetUnit(), multiplier * stat, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_ENHANCED)
endfunction
//===========================================================================
function InitTrig_Razor_Slash takes nothing returns nothing
set gg_trg_Razor_Slash = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Razor_Slash, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Razor_Slash, Condition( function Trig_Razor_Slash_Conditions ) )
call TriggerAddAction( gg_trg_Razor_Slash, function Trig_Razor_Slash_Actions )
endfunction
function Trig_Leap_Ghoul_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A01Y'
endfunction
function Trig_Leap_Ghoul_Callback takes nothing returns boolean
local unit u
local effect se
//call BJDebugMsg("callback")
set u = LoadUnitHandle(udg_UtilMap, udg_CALLBACK_HANDLE, 0)
set se = AddSpecialEffect("Objects\\Spawnmodels\\Undead\\ImpaleTargetDust\\ImpaleTargetDust.mdl", GetUnitX(u), GetUnitY(u))
call DestroyEffect(se)
set se = null
set u = null
return true
endfunction
function Trig_Leap_Ghoul_Actions takes nothing returns nothing
local unit u = GetTriggerUnit()
local location ls = GetUnitLoc(u)
local location lt = GetSpellTargetLoc()
local integer dmg = BlzGetUnitBaseDamage(u, 0)
call UnitAddAbility(u, 'A01Z')
call BlzSetAbilityIntegerLevelField( BlzGetUnitAbility(u, 'A01Z'), ABILITY_ILF_ATTACK_BONUS, 1, dmg / 2)
call BlzSetAbilityIntegerLevelField( BlzGetUnitAbility(u, 'A01Z'), ABILITY_ILF_ATTACK_BONUS, 2, dmg / 2)
call SetUnitAbilityLevel(u, 'A01Z', 1)
call SetUnitAbilityLevel(u, 'A01Z', 2)
call RemoveBuffAfter.create(5.0, u, 'A01Z').startPeriodic()
call LeapFlyGhoul.create(ls, lt, u, Condition(function Trig_Leap_Ghoul_Callback)).startPeriodic()
set ls = null
set lt = null
set u = null
endfunction
//===========================================================================
function InitTrig_Leap_Ghoul takes nothing returns nothing
set gg_trg_Leap_Ghoul = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Leap_Ghoul, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Leap_Ghoul, Condition( function Trig_Leap_Ghoul_Conditions ) )
call TriggerAddAction( gg_trg_Leap_Ghoul, function Trig_Leap_Ghoul_Actions )
endfunction
struct LeapFlyGhoul
private unit u
private location ls
private location lt
private boolean started
private integer firstTick
private boolexpr callback
private integer ticks
private real incrementX
private real incrementY
// min speedx 200 at 50 distance
// max speedx 700 at 550 distance
private real speedx
private real speedy
private method periodic takes nothing returns nothing
local real angle
local real distance
local PlayableArea pa
if (this.started == false) then
set started = true
call UnitAddAbility(u, 'Amrf')
call UnitRemoveAbility(u, 'Amrf')
//MIN DISTANCE 50
set distance = DistanceBetweenPoints(ls, lt)
set angle = AngleBetweenPoints(ls, lt)
if (distance < 50) then
set distance = 50
call RemoveLocation(lt)
set lt = PolarProjectionBJ(ls, distance, angle)
endif
//IF CURRENT DISTANCE WOULD BE OUTSIDE, BIN SEARCH A SHORTER DISTANCE THAT'S INSIDE. but only if the unit started inside the playable are in the first place
set pa = udg_CURRENT_PLAYABLE_AREA
if (pa.containsLocation(ls)) then
loop
exitwhen pa.containsLocation(lt)
set distance = distance * 0.5
call RemoveLocation(lt)
set lt = PolarProjectionBJ(ls, distance, angle)
endloop
endif
set this.speedx = RMinBJ(200 + (distance - 50) * 1.25, 700)
set this.speedy = speedx * 0.35
call SetUnitFlyHeight(u, 500, speedy)
//call BJDebugMsg(R2S(speedx))
set firstTick = T32_Tick
set ticks = MathRound(distance / speedx * 32)
set ticks = IMaxBJ(3, ticks)
//call BJDebugMsg(R2S(GetLocationX(ls)))
//call BJDebugMsg(R2S(GetLocationX(lt)))
set incrementX = (GetLocationX(lt) - GetLocationX(ls)) / ticks
set incrementY = (GetLocationY(lt) - GetLocationY(ls)) / ticks
endif
if (u != null) then
//call BJDebugMsg(R2S(incrementX))
call SetUnitX(u, GetUnitX(u) + incrementX)
call SetUnitY(u, GetUnitY(u) + incrementY)
endif
if this.firstTick + (ticks * 2 / 3) == T32_Tick then
if (u != null) then
call SetUnitFlyHeight(u, 0, speedy * 3 / 2 )
endif
endif
if this.firstTick + ticks == T32_Tick then
//call back params
call ExecuteBoolexpUnit(callback, u)
set u = null
call RemoveLocation(lt)
call RemoveLocation(ls)
set lt = null
set ls = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes location ls, location lt, unit u, boolexpr callback returns thistype
local thistype this = thistype.allocate()
set this.u = u
set this.ls = ls
set this.lt = lt
set this.started = false
set this.callback = callback
return this
endmethod
endstruct
function Trig_Snack_Ghoul_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A001'
endfunction
function Trig_Snack_Ghoul_Actions takes nothing returns nothing
local integer level
local integer stat
local integer key
local unit caster
set caster = GetSpellAbilityUnit()
call PauseUnit(caster, true)
set level = GetUnitAbilityLevel(caster, 'A001')
set stat = 200
call SnackGhoulPeriodic.create(2.5, caster, stat * level).startPeriodic()
set caster = null
endfunction
//===========================================================================
function InitTrig_Snack_Ghoul takes nothing returns nothing
set gg_trg_Snack_Ghoul = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Snack_Ghoul, EVENT_PLAYER_UNIT_SPELL_CHANNEL )
call TriggerAddCondition( gg_trg_Snack_Ghoul, Condition( function Trig_Snack_Ghoul_Conditions ) )
call TriggerAddAction( gg_trg_Snack_Ghoul, function Trig_Snack_Ghoul_Actions )
endfunction
function Trig_Snack_Ghoul_Effect_Filter takes nothing returns boolean
return UnitDead(GetFilterUnit()) and IsUnitAlly(GetFilterUnit(), Player(23))
endfunction
function Snack_Ghoul_Effect takes unit caster, real amount returns nothing
local location l
local location le
local effect e
local group g
local unit corpse
local real x
local real y
local player p
set l = GetUnitLoc(caster)
set x = GetUnitX(caster)
set y = GetUnitY(caster)
set p = GetOwningPlayer(caster)
set g = CreateGroup()
call GroupEnumUnitsInRange(g, x, y, 225, function Trig_Snack_Ghoul_Effect_Filter)
set corpse = FirstOfGroup(g)
if (corpse == null) then
set le = PolarProjectionU(caster, GetRandomReal(0, 125), GetRandomReal(0, 360))
set amount = amount * 0.25
set e = AddSpecialEffectLoc("Objects\\Spawnmodels\\Undead\\ImpaleTargetDust\\ImpaleTargetDust.mdl", le)
call DestroyEffect(e)
call RemoveLocation(le)
call RemoveLocation (l)
set le = null
elseif (IsUnitEnemy(corpse, p) ) then
call GroupRemoveUnit(g, corpse)
set e = AddSpecialEffectLoc("Abilities\\Spells\\Undead\\RaiseSkeletonWarrior\\RaiseSkeleton.mdl", l)
call RemoveLocation(l)
call DestroyEffect(e)
set l = GetUnitLoc(corpse)
set e = AddSpecialEffectLoc("Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.md", l)
call RemoveLocation(l)
call DestroyEffect(e)
call RemoveUnit(corpse)
call RestoreMana(caster, caster, 50)
endif
call RestoreHealth(caster, caster, amount)
set l = null
set e = null
set corpse = null
set p = null
call DestroyGroup(g)
set g = null
endfunction
struct SnackGhoulPeriodic
private unit caster
private integer endTick
private integer nextTick
private real amount
private method periodic takes nothing returns nothing
if (T32_Tick == nextTick and caster != null) then
call Snack_Ghoul_Effect(caster, amount)
set nextTick = nextTick + 32
endif
if this.endTick == T32_Tick and caster != null then
call PauseUnit(caster, false)
set caster = null
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes real duration, unit caster, real stat returns thistype
local thistype this = thistype.allocate()
set this.caster = caster
set this.amount = stat
set this.nextTick = T32_Tick + 2
set this.endTick = T32_Tick + R2I(duration / T32_PERIOD)
return this
endmethod
endstruct
function Trig_Sweep_Ghoul_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A007'
endfunction
function AvgDmg takes integer base, integer sides, integer dices returns integer
return base + dices * (sides + 1) / 2
endfunction
function Trig_Sweep_Ghoul_Actions takes nothing returns nothing
local integer stat
local integer level
local real multiplier
local integer base
local integer sides
local integer dices
local unit u
local unit t
local location l
local location lt
local real x
local real y
local real angleDiff
local real cos
local group g
local player p
set u = GetTriggerUnit()
set base = BlzGetUnitWeaponIntegerField(u, UNIT_WEAPON_IF_ATTACK_DAMAGE_BASE, 0)
set sides = BlzGetUnitWeaponIntegerField(u, UNIT_WEAPON_IF_ATTACK_DAMAGE_SIDES_PER_DIE, 0)
set dices = BlzGetUnitWeaponIntegerField(u, UNIT_WEAPON_IF_ATTACK_DAMAGE_NUMBER_OF_DICE, 0)
set l = GetUnitLoc(u)
set x = GetUnitX(u)
set y = GetUnitY(u)
set p = GetOwningPlayer(u)
set stat = AvgDmg(base, sides, dices)
set stat = stat + udg_BonusAttackFlat[GetPlayerId(p)]
set level = GetUnitAbilityLevel(u, 'A007')
set multiplier = (level - 1) * 0.5 + 1.0
set g = CreateGroup()
call GroupEnumUnitsInRange(g, x, y, 400, function True_Filter)
loop
set t = FirstOfGroup(g)
exitwhen t == null
call GroupRemoveUnit(g, t)
if (IsUnitEnemy(t,p) and UnitAlive(t)) then
set lt = GetUnitLoc(t)
set angleDiff = GetUnitFacing(u) - AngleBetweenPoints(l, lt)
set cos = Cos(angleDiff*bj_DEGTORAD)
//call DisplayTextToForce( GetPlayersAll(), R2S(cos) )
// cos 0.34 -> 70° angle --> 140 radius
if (cos > 0.342) then
call UnitDamageTargetBJ( u, t, multiplier * stat, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_ENHANCED )
call AddSpecialEffectLocBJ( lt, "Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.md" )
call DestroyEffect( GetLastCreatedEffectBJ() )
endif
call RemoveLocation (lt)
endif
endloop
set p = null
set u = null
call RemoveLocation (l)
call DestroyGroup(g)
endfunction
//===========================================================================
function InitTrig_Sweep_Ghoul takes nothing returns nothing
set gg_trg_Sweep_Ghoul = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Sweep_Ghoul, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Sweep_Ghoul, Condition( function Trig_Sweep_Ghoul_Conditions ) )
call TriggerAddAction( gg_trg_Sweep_Ghoul, function Trig_Sweep_Ghoul_Actions )
endfunction
function Trig_Warcry_Ghoul_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A008'
endfunction
function Trig_Warcry_Ghoul_Actions takes nothing returns nothing
local integer level
local integer stat
local unit caster
local unit lcu
local location l
local player p
local integer i
set caster = GetTriggerUnit()
set p = GetOwningPlayer(caster)
set level = GetUnitAbilityLevel(caster, 'A008')
set stat = 15 * level
set udg_BonusAttackFlat[GetPlayerId(p)] = stat
call BlzSetAbilityIntegerLevelField(BlzGetUnitAbility(caster, 'A009'), ABILITY_ILF_ATTACK_BONUS, 1, stat)
call BlzSetAbilityIntegerLevelField(BlzGetUnitAbility(caster, 'A009'), ABILITY_ILF_ATTACK_BONUS, 2, stat)
call SetUnitAbilityLevel(caster, 'A009', 1)
call SetUnitAbilityLevel(caster, 'A009', 2)
set l = GetUnitLoc(caster)
set lcu = CreateUnitAtLoc(GetOwningPlayer(caster), 'h003', l, bj_UNIT_FACING)
call RemoveLocation (l)
call UnitAddAbility(lcu, 'A000')
call IssueTargetOrder(lcu, "innerfire", caster)
call UnitApplyTimedLifeBJ(15.00, 'BTLF', lcu)
set lcu = null
set p = null
set caster = null
endfunction
//===========================================================================
function InitTrig_Warcry_Ghoul takes nothing returns nothing
set gg_trg_Warcry_Ghoul = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Warcry_Ghoul, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Warcry_Ghoul, Condition( function Trig_Warcry_Ghoul_Conditions ) )
call TriggerAddAction( gg_trg_Warcry_Ghoul, function Trig_Warcry_Ghoul_Actions )
endfunction
function Trig_Warcry_Ghoul_Over_Conditions takes nothing returns boolean
return GetUnitTypeId(GetDyingUnit()) == 'h003'
endfunction
function Trig_Warcry_Ghoul_Over_Actions takes nothing returns nothing
local unit caster
local player p
local integer i
set p = GetOwningPlayer(GetDyingUnit())
set i = GetPlayerId(p)
set caster = udg_MainHeroes[i]
call BlzSetAbilityIntegerLevelFieldBJ( BlzGetUnitAbility(caster, 'A009'), ABILITY_ILF_ATTACK_BONUS, 1, 0)
call BlzSetAbilityIntegerLevelFieldBJ( BlzGetUnitAbility(caster, 'A009'), ABILITY_ILF_ATTACK_BONUS, 2, 0)
call SetUnitAbilityLevelSwapped( 'A009', caster, 2 )
call SetUnitAbilityLevelSwapped( 'A009', caster, 1 )
set udg_BonusAttackFlat[i] = 0
set p = null
set caster = null
endfunction
//===========================================================================
function InitTrig_Warcry_Ghoul_Over takes nothing returns nothing
set gg_trg_Warcry_Ghoul_Over = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Warcry_Ghoul_Over, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_Warcry_Ghoul_Over, Condition( function Trig_Warcry_Ghoul_Over_Conditions ) )
call TriggerAddAction( gg_trg_Warcry_Ghoul_Over, function Trig_Warcry_Ghoul_Over_Actions )
endfunction
function Trig_Energize_Ghoul_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A00A'
endfunction
function Trig_Energize_Ghoul_Actions takes nothing returns nothing
local integer level
local unit caster
local unit target
local integer i
set caster = GetTriggerUnit()
set target = GetSpellTargetUnit()
set level = GetUnitAbilityLevel(caster, 'A00A')
call RestoreMana(caster, target , 5 + 12 * level)
set target = null
set caster = null
endfunction
//===========================================================================
function InitTrig_Energize_Ghoul takes nothing returns nothing
set gg_trg_Energize_Ghoul = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Energize_Ghoul, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Energize_Ghoul, Condition( function Trig_Energize_Ghoul_Conditions ) )
call TriggerAddAction( gg_trg_Energize_Ghoul, function Trig_Energize_Ghoul_Actions )
endfunction
//! zinc
/*
* Zap
* ------------
*******************************************************************************/
library Zap requires xecollider, xedamage {
constant integer SPELL_ID = 'A00B';
constant real NOISE = 50.0;
constant real MISSILE_SPEED = 700.0;
function configMissile(xecollider m, integer level) {
m.z = 60.0;
m.expirationTime = 50.0;
m.fxpath = "Abilities\\Weapons\\WitchDoctorMissile\\WitchDoctorMissile.mdl";
m.collisionSize = 50.0;
m.acceleration = 1200.0;
m.angleSpeed = bj_PI * 4;
}
function setupDamage(xedamage xd, integer level ) {
xd.damageAllies = false;
xd.damageEnemies = true; // Hit enemies exclusively
xd.damageNeutral = false;
xd.exception = UNIT_TYPE_STRUCTURE;
xd.dtype = DAMAGE_TYPE_LIGHTNING;
xd.atype = ATTACK_TYPE_MAGIC;
}
xedamage xdam[];
function catalist_Strike(unit caster, unit target, integer stat) {
//dummy stuff
}
struct zapMissile extends xecollider {
integer level;
integer stat;
unit owner;
static method create(real x, real y, real dir)->thistype {
zapMissile this = allocate(x,y,dir);
return this;
}
method onUnitHit(unit hitUnit) {
if( hitUnit == targetUnit ) {
stat = GetHeroStatBJ(bj_HEROSTAT_INT, owner, true);
xdam[level].damageTarget(owner, hitUnit, stat * ((level - 1) * 2.0 + 4.0) );
flash("Abilities\\Weapons\\GryphonRiderMissile\\GryphonRiderMissileTarget.mdl");
terminate();
catalist_Strike(owner, hitUnit, stat);
}
}
}
function onSpell() {
unit u = GetTriggerUnit();
integer level = GetUnitAbilityLevel(u, SPELL_ID );
real tx = GetSpellTargetX(), ty=GetSpellTargetY();
real x = GetUnitX(u), y=GetUnitY(u);
real f = Atan2( ty-y, tx-x );
zapMissile m;
if(xdam[level]==0) {
//all array elements start at 0
xdam[level] = xedamage.create();
setupDamage(xdam[level], level);
}
//create a new missile:
m = zapMissile.create(x + GetRandomReal(-NOISE, NOISE), y + GetRandomReal(-NOISE, NOISE), f);
m.owner = u;
m.targetUnit = GetSpellTargetUnit();
m.level = level;
configMissile(m,level);
m.maxSpeed = MISSILE_SPEED;
m.speed = MISSILE_SPEED/4;
u=null;
}
function onInit() {
trigger t = CreateTrigger();
TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT);
TriggerAddAction(t, function onSpell);
TriggerAddCondition(t, function()->boolean{
return GetSpellAbilityId() == SPELL_ID;
});
}
}
//! endzinc
function catalistItemEffect_Filter takes nothing returns boolean
local player p = GetOwningPlayer(udg_DamageEventSource)
local boolean ret = IsUnitEnemy(GetFilterUnit(), p) and UnitAlive(GetFilterUnit()) and GetUnitAbilityLevel(GetFilterUnit(),'Avul') < 1
set p = null
return ret
endfunction
function catalistItemEffect takes unit caster, unit primaryTarget returns nothing
local group g
local real x = GetUnitX(primaryTarget)
local real y = GetUnitY(primaryTarget)
local unit t
local unit dummy
local integer i = 0
set g = CreateGroup()
call GroupEnumUnitsInRange(g, x, y, 600, function catalistItemEffect_Filter)
call GroupRemoveUnit(g, primaryTarget)
loop
set t = FirstOfGroup(g)
exitwhen t == null or i == 2
set dummy = CreateUnit(GetOwningPlayer(caster), 'h004', x, y, bj_UNIT_FACING)
call UnitApplyTimedLife(dummy, 'BTLF', 5.00)
call UnitAddAbility(dummy, 'A00B')
call BlzSetAbilityRealLevelField( BlzGetUnitAbility(dummy, 'A00B'), ConvertAbilityRealLevelField('Nab4'), 0, GetHeroInt(caster, true) * 4.0)
call GroupRemoveUnit(g, t)
call IssueTargetOrder( dummy, "acidbomb", t)
set i = i + 1
endloop
set dummy = null
call DestroyGroup(g)
set g = null
endfunction
function Trig_Zap_Hit_Actions takes nothing returns nothing
local unit t = udg_DamageEventTarget
local unit s = udg_DamageEventSource
local effect se
if (GetUnitAbilityLevel(t, 'B006') < 1) then
return
endif
call UnitRemoveBuffBJ('B006', t)
set se = AddSpecialEffect("Abilities\\Weapons\\BallistaMissile\\BallistaMissileTarget.mdl", GetUnitX(t), GetUnitY(t))
call DestroyEffect( se )
set udg_DamageEventAmount = GetHeroInt(s, true) * (2.0 + 2.0 * GetUnitAbilityLevel(s, 'A01Q' ))
set udg_DamageEventType = udg_DAMAGE_TYPE_LIGHTNING
if (UnitHasItemOfTypeBJ(s, 'I003')) then
call catalistItemEffect(s, t)
endif
set se = null
set t = null
set s = null
endfunction
//===========================================================================
function InitTrig_Zap_Hit takes nothing returns nothing
set gg_trg_Zap_Hit = CreateTrigger( )
call TriggerRegisterVariableEvent( gg_trg_Zap_Hit, "udg_PreDamageEvent", EQUAL, 1.00 )
call TriggerAddAction( gg_trg_Zap_Hit, function Trig_Zap_Hit_Actions )
endfunction
function Trig_Zap_Hit_Catalyst_Actions takes nothing returns nothing
local unit t = udg_DamageEventTarget
local unit s = udg_DamageEventSource
local effect se
if (GetUnitAbilityLevel(t, 'B007') < 1) then
return
endif
call UnitRemoveBuffBJ('B007', t)
set se = AddSpecialEffect("Abilities\\Weapons\\BallistaMissile\\BallistaMissileTarget.mdl", GetUnitX(t), GetUnitY(t))
call DestroyEffect( se )
// DMG SET IN ZAP
set udg_DamageEventType = udg_DAMAGE_TYPE_LIGHTNING
set se = null
set t = null
set s = null
endfunction
//===========================================================================
function InitTrig_Zap_Hit_Catalyst takes nothing returns nothing
set gg_trg_Zap_Hit_Catalyst = CreateTrigger( )
call TriggerRegisterVariableEvent( gg_trg_Zap_Hit_Catalyst, "udg_PreDamageEvent", EQUAL, 1.00 )
call TriggerAddAction( gg_trg_Zap_Hit_Catalyst, function Trig_Zap_Hit_Catalyst_Actions )
endfunction
function Ls_Ghoul_Effect takes integer key returns nothing
local integer stat
local unit target
local unit caster
local unit u
local player p
local location l
local group g
local real x
local real y
set stat = LoadIntegerBJ( 1, key, udg_LightningSMap )
set target = LoadUnitHandleBJ( 2, key, udg_LightningSMap )
set caster = LoadUnitHandleBJ( 3, key, udg_LightningSMap )
set x = GetUnitX(target)
set y = GetUnitY(target)
set p = GetOwningPlayer(caster)
set g = CreateGroup()
call GroupEnumUnitsInRange(g, x, y, 200, function True_Filter)
loop
set u = FirstOfGroup(g)
exitwhen u == null
call GroupRemoveUnit(g, u)
if (IsUnitEnemy(u,p) and u != target and UnitAlive(u) and GetUnitAbilityLevel(u,'Avul') < 1 ) then
set l = GetUnitLoc(u)
call UnitDamageTargetBJ( caster, u, stat, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_LIGHTNING )
call AddSpecialEffectLocBJ( l, "Abilities\\Spells\\Orc\\LightningShield\\LightningShieldBuff.mdl" )
call DestroyEffect( GetLastCreatedEffectBJ() )
call RemoveLocation (l)
endif
endloop
set p = null
call DestroyGroup(g)
endfunction
function Trig_LightningS_Ghoul_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A00C'
endfunction
function Trig_LightningS_Ghoul_Actions takes nothing returns nothing
local integer level
local unit caster
local unit target
local unit dummy
local integer key
local integer stat
local location l
set caster = GetTriggerUnit()
set target = GetSpellTargetUnit()
set level = GetUnitAbilityLevel(caster, 'A00C')
set stat = GetHeroInt(caster, true)
set l = GetUnitLoc(caster)
set dummy = CreateUnitAtLoc(GetOwningPlayer(caster), 'h006', l, bj_UNIT_FACING)
call RemoveLocation (l)
call UnitAddAbility(dummy, 'A00E')
call IssueTargetOrder(dummy, "lightningshield", target)
call UnitApplyTimedLifeBJ(1.00, 'BTLF', dummy)
set key = GetHandleId(dummy)
call SaveIntegerBJ( 5, 0, key, udg_LightningSMap )
call SaveIntegerBJ( stat * level, 1, key, udg_LightningSMap )
call SaveUnitHandleBJ( target, 2, key, udg_LightningSMap )
call SaveUnitHandleBJ( caster, 3, key, udg_LightningSMap )
call Ls_Ghoul_Effect(key)
set dummy = null
set target = null
set caster = null
endfunction
//===========================================================================
function InitTrig_LightningS_Ghoul takes nothing returns nothing
set gg_trg_LightningS_Ghoul = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_LightningS_Ghoul, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_LightningS_Ghoul, Condition( function Trig_LightningS_Ghoul_Conditions ) )
call TriggerAddAction( gg_trg_LightningS_Ghoul, function Trig_LightningS_Ghoul_Actions )
endfunction
function Trig_LighntingS_Ghoul_Periodic_Conditions takes nothing returns boolean
return GetUnitTypeId(GetDyingUnit()) == 'h006'
endfunction
function Trig_LighntingS_Ghoul_Periodic_Actions takes nothing returns nothing
local unit caster
local unit target
local unit dummy
local integer i
local integer stat
local integer key
local location l
set key = GetHandleId(GetDyingUnit())
set i = LoadIntegerBJ(0, key, udg_LightningSMap )
set stat = LoadIntegerBJ( 1, key, udg_LightningSMap )
set target = LoadUnitHandleBJ( 2, key, udg_LightningSMap )
set caster = LoadUnitHandleBJ( 3, key, udg_LightningSMap )
call FlushChildHashtable(udg_LightningSMap, key)
set i = i - 1
if (i > 0 and UnitAlive(target)) then
set l = GetUnitLoc(caster)
set dummy = CreateUnitAtLoc(GetOwningPlayer(caster), 'h006', l, bj_UNIT_FACING)
call RemoveLocation (l)
set key = GetHandleId(dummy)
call UnitApplyTimedLifeBJ(1.00, 'BTLF', dummy)
call SaveIntegerBJ( i, 0, key, udg_LightningSMap )
call SaveIntegerBJ( stat, 1, key, udg_LightningSMap )
call SaveUnitHandleBJ( target, 2, key, udg_LightningSMap )
call SaveUnitHandleBJ( caster, 3, key, udg_LightningSMap )
call Ls_Ghoul_Effect(key)
endif
set caster = null
set dummy = null
set target = null
endfunction
//===========================================================================
function InitTrig_LighntingS_Ghoul_Periodic takes nothing returns nothing
set gg_trg_LighntingS_Ghoul_Periodic = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_LighntingS_Ghoul_Periodic, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_LighntingS_Ghoul_Periodic, Condition( function Trig_LighntingS_Ghoul_Periodic_Conditions ) )
call TriggerAddAction( gg_trg_LighntingS_Ghoul_Periodic, function Trig_LighntingS_Ghoul_Periodic_Actions )
endfunction
function Trig_Overcharge_Ghoul_Attack_Conditions takes nothing returns boolean
return UnitHasBuffBJ(GetAttacker(), 'B003')
endfunction
function Trig_Overcharge_Ghoul_Attack_Actions takes nothing returns nothing
local unit attacker
local unit lcu
local integer stat
if (GetRandomReal(0, 1) > 0.66) then
set attacker = GetAttacker()
set stat = GetHeroInt(attacker, true)
set lcu = CreateUnit(GetOwningPlayer(attacker), 'h004', GetUnitX(attacker), GetUnitY(attacker), bj_UNIT_FACING)
call UnitAddAbility(lcu, 'A00G')
call BlzSetAbilityRealLevelField( BlzGetUnitAbility(lcu, 'A00G'), ABILITY_RLF_DAMAGE_PER_TARGET_OCL1, 0, 2.0 * stat)
call UnitApplyTimedLifeBJ( 3.00, 'BTLF', lcu )
call IssueTargetOrder(lcu, "chainlightning", GetTriggerUnit())
endif
set attacker = null
set lcu = null
endfunction
//===========================================================================
function InitTrig_Overcharge_Ghoul_Attack takes nothing returns nothing
set gg_trg_Overcharge_Ghoul_Attack = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Overcharge_Ghoul_Attack, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddCondition( gg_trg_Overcharge_Ghoul_Attack, Condition( function Trig_Overcharge_Ghoul_Attack_Conditions ) )
call TriggerAddAction( gg_trg_Overcharge_Ghoul_Attack, function Trig_Overcharge_Ghoul_Attack_Actions )
endfunction
function Trig_Overcharge_Ghoul_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A00D'
endfunction
function Trig_Overcharge_Ghoul_Actions takes nothing returns nothing
local integer level
local unit caster
local unit dummy
local integer stat
local location l
set caster = GetTriggerUnit()
set l = GetUnitLoc(caster)
set dummy = CreateUnitAtLoc(GetOwningPlayer(caster), 'h004', l, bj_UNIT_FACING)
call RemoveLocation (l)
call UnitAddAbility(dummy, 'A00F')
call IssueTargetOrder(dummy, "innerfire", caster)
call UnitApplyTimedLifeBJ(3.00, 'BTLF', dummy)
set dummy = null
set caster = null
endfunction
//===========================================================================
function InitTrig_Overcharge_Ghoul takes nothing returns nothing
set gg_trg_Overcharge_Ghoul = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Overcharge_Ghoul, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Overcharge_Ghoul, Condition( function Trig_Overcharge_Ghoul_Conditions ) )
call TriggerAddAction( gg_trg_Overcharge_Ghoul, function Trig_Overcharge_Ghoul_Actions )
endfunction
function Trig_HERO_Actions takes nothing returns nothing
endfunction
//===========================================================================
function InitTrig_HERO takes nothing returns nothing
set gg_trg_HERO = CreateTrigger( )
call TriggerAddAction( gg_trg_HERO, function Trig_HERO_Actions )
endfunction
function Trig_WhitelistItems_Actions takes nothing returns nothing
set udg_ClassItemWhitelist = InitHashtable()
set udg_WHITELIST_KEY_CONST = 'n005'
//GHOUL MAGE
call SaveBoolean(udg_ClassItemWhitelist, udg_WHITELIST_KEY_CONST, 'I003', true)
call SaveBoolean(udg_ClassItemWhitelist, 'U002', 'I003', true)
//GOHUL OTHER
call SaveBoolean(udg_ClassItemWhitelist, udg_WHITELIST_KEY_CONST, 'I001', true)
call SaveBoolean(udg_ClassItemWhitelist, 'U001', 'I001', true)
call SaveBoolean(udg_ClassItemWhitelist, 'U003', 'I001', true)
call SaveBoolean(udg_ClassItemWhitelist, udg_WHITELIST_KEY_CONST, 'I002', true)
call SaveBoolean(udg_ClassItemWhitelist, 'U001', 'I002', true)
call SaveBoolean(udg_ClassItemWhitelist, 'U003', 'I002', true)
//assassin
call SaveBoolean(udg_ClassItemWhitelist, udg_WHITELIST_KEY_CONST, 'I007', true)
call SaveBoolean(udg_ClassItemWhitelist, 'U00B', 'I007', true)
call SaveBoolean(udg_ClassItemWhitelist, 'U00C', 'I007', true)
call SaveBoolean(udg_ClassItemWhitelist, 'U00D', 'I007', true)
//necromancer
call SaveBoolean(udg_ClassItemWhitelist, udg_WHITELIST_KEY_CONST, 'I004', true)
call SaveBoolean(udg_ClassItemWhitelist, 'U000', 'I004', true)
call SaveBoolean(udg_ClassItemWhitelist, 'U005', 'I004', true)
call SaveBoolean(udg_ClassItemWhitelist, 'U007', 'I004', true)
call SaveBoolean(udg_ClassItemWhitelist, udg_WHITELIST_KEY_CONST, 'I005', true)
call SaveBoolean(udg_ClassItemWhitelist, 'U000', 'I005', true)
call SaveBoolean(udg_ClassItemWhitelist, 'U005', 'I005', true)
call SaveBoolean(udg_ClassItemWhitelist, 'U007', 'I005', true)
call SaveBoolean(udg_ClassItemWhitelist, udg_WHITELIST_KEY_CONST, 'I006', true)
call SaveBoolean(udg_ClassItemWhitelist, 'U000', 'I006', true)
call SaveBoolean(udg_ClassItemWhitelist, 'U005', 'I006', true)
call SaveBoolean(udg_ClassItemWhitelist, 'U007', 'I006', true)
endfunction
//===========================================================================
function InitTrig_WhitelistItems takes nothing returns nothing
set gg_trg_WhitelistItems = CreateTrigger( )
call TriggerRegisterTimerEventSingle( gg_trg_WhitelistItems, 0.00 )
call TriggerAddAction( gg_trg_WhitelistItems, function Trig_WhitelistItems_Actions )
endfunction
function Trig_Class_Lock_Actions takes nothing returns nothing
local unit u = GetTriggerUnit()
local integer ucode = GetUnitTypeId(u)
local integer icode = GetItemTypeId(GetManipulatedItem())
//call BJDebugMsg(I2S(icode) + " " + I2S(ucode))
//call BJDebugMsg(I2S('I003') + " " + I2S('U002'))
//call BJDebugMsg(B2S(LoadBoolean(udg_ClassItemWhitelist, udg_WHITELIST_KEY_CONST, icode)) + " " + B2S(LoadBoolean(udg_ClassItemWhitelist, ucode, icode)))
// item is in whitelist
if LoadBoolean(udg_ClassItemWhitelist, udg_WHITELIST_KEY_CONST, icode) then
// allowed to pick
if LoadBoolean(udg_ClassItemWhitelist, ucode, icode) then
//ok
else
call DisplayTextToPlayer(GetOwningPlayer(u), 0, 0, "That item belongs to a different class!")
call UnitRemoveItem(u, GetManipulatedItem())
endif
endif
endfunction
//===========================================================================
function InitTrig_Class_Lock takes nothing returns nothing
set gg_trg_Class_Lock = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Class_Lock, EVENT_PLAYER_UNIT_PICKUP_ITEM )
call TriggerAddAction( gg_trg_Class_Lock, function Trig_Class_Lock_Actions )
endfunction
function Trig_CorpseExplosionWand_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A02V'
endfunction
function Trig_CorpseExplosionWand_f takes nothing returns boolean
return UnitDead(GetFilterUnit()) and IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(GetTriggerUnit())) and not IsUnitType(GetFilterUnit(), UNIT_TYPE_HERO)
endfunction
function Trig_CorpseExplosionWand_Actions takes nothing returns nothing
local unit u = GetTriggerUnit()
local location l = GetSpellTargetLoc()
local location lc
local group g = CreateGroup()
local unit corpse
local unit gu
local effect se
local integer stat = GetHeroInt(u, true)
call GroupEnumUnitsInRangeOfLoc(g, l, 150, function Trig_CorpseExplosionWand_f)
set corpse = FirstOfGroup(g)
if (corpse != null) then
call DestroyGroup(g)
set g = CreateGroup()
call GroupEnumUnitsInRange(g, GetUnitX(corpse), GetUnitY(corpse), 150, function EAnI_Filter)
loop
set gu = FirstOfGroup(g)
exitwhen gu == null
call GroupRemoveUnit(g, gu)
call UnitDamageTargetBJ(u, gu, 6.0 * stat, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_ENHANCED)
endloop
set se = AddSpecialEffect("Objects\\Spawnmodels\\Undead\\UndeadLargeDeathExplode\\UndeadLargeDeathExplode.mdl", GetUnitX(corpse), GetUnitY(corpse))
call RemoveUnit(corpse)
set corpse = null
else
set se = AddSpecialEffectLoc("Abilities\\Spells\\Undead\\DeathandDecay\\DeathandDecayTarget.mdl", l)
endif
set u = null
call DestroyGroup(g)
call RemoveLocation(l)
call DestroyEffect(se)
set l = null
set g = null
set gu = null
set se = null
endfunction
//===========================================================================
function InitTrig_CorpseExplosionWand takes nothing returns nothing
set gg_trg_CorpseExplosionWand = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ(gg_trg_CorpseExplosionWand, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(gg_trg_CorpseExplosionWand, function Trig_CorpseExplosionWand_Conditions)
call TriggerAddAction(gg_trg_CorpseExplosionWand, function Trig_CorpseExplosionWand_Actions)
endfunction
function InitOffensePackageItemList takes nothing returns nothing
set udg_ItemListOffensePackage[0] = 'rat9' //claws +9
set udg_ItemListOffensePackage[1] = 'cnob' //nobility
set udg_ItemListOffensePackage[2] = 'ofir' //fire
set udg_ItemListOffensePackage[3] = 'gcel' //haste
set udg_ItemListOffensePackage[4] = 'ratf' //claws +15
set udg_ItemListOffensePackage[5] = 'ckng' //kings
endfunction
function InitDefensePackageItemList takes nothing returns nothing
set udg_ItemListDefensePackage[0] = 'prvt' //vitality
set udg_ItemListDefensePackage[1] = 'rde2' //ring3
set udg_ItemListDefensePackage[2] = 'rlif' //regen
set udg_ItemListDefensePackage[3] = 'rhth' //khadgar
set udg_ItemListDefensePackage[4] = 'rde3' //ring4
set udg_ItemListDefensePackage[5] = 'rde3' //ring4
endfunction
function InitSupportPackageItemList takes nothing returns nothing
set udg_ItemListSupportPackage[0] = 'penr' //energy
set udg_ItemListSupportPackage[1] = 'lhst' //devotion
set udg_ItemListSupportPackage[2] = 'sres' //restoration
set udg_ItemListSupportPackage[3] = 'sbch' //vamp
set udg_ItemListSupportPackage[4] = 'rwiz' //sobi
set udg_ItemListSupportPackage[5] = 'sror' //roar
endfunction
function Trig_InitItemLists_Actions takes nothing returns nothing
call InitDefensePackageItemList()
call InitSupportPackageItemList()
call InitOffensePackageItemList()
endfunction
//===========================================================================
function InitTrig_InitItemLists takes nothing returns nothing
set gg_trg_InitItemLists = CreateTrigger( )
call TriggerAddAction( gg_trg_InitItemLists, function Trig_InitItemLists_Actions )
endfunction
function Trig_LunchBox_Cast_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A001' and UnitHasItemOfTypeBJ(GetSpellAbilityUnit(), 'I002')
endfunction
function Trig_LunchBox_Cast_Actions takes nothing returns nothing
local unit u = CreateCorpse(Player(PLAYER_NEUTRAL_AGGRESSIVE), 'hfoo', GetUnitX(GetSpellAbilityUnit()), GetUnitY(GetSpellAbilityUnit()), GetRandomReal(0, 360))
call UnitSuspendDecay(u, true)
call SetUnitBlendTime(u, 0)
call SetUnitAnimation(u, "decay bone")
set u = null
endfunction
//===========================================================================
function InitTrig_LunchBox_Cast takes nothing returns nothing
set gg_trg_LunchBox_Cast = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_LunchBox_Cast, EVENT_PLAYER_UNIT_SPELL_CHANNEL )
call TriggerAddCondition( gg_trg_LunchBox_Cast, function Trig_LunchBox_Cast_Conditions )
call TriggerAddAction( gg_trg_LunchBox_Cast, function Trig_LunchBox_Cast_Actions )
endfunction
function Trig_Nail_Polish_PreDmg_Actions takes nothing returns nothing
local integer agi
if (udg_DamageEventAmount == 0.001 and udg_DAMAGE_TYPE_SLOW_POISON == udg_DamageEventDamageT) then
set agi = GetHeroStatBJ(bj_HEROSTAT_AGI, udg_DamageEventSource, true)
set udg_DamageEventAmount = agi * 0.4
endif
endfunction
//===========================================================================
function InitTrig_Nail_Polish_PreDmg takes nothing returns nothing
set gg_trg_Nail_Polish_PreDmg = CreateTrigger( )
call TriggerRegisterVariableEvent( gg_trg_Nail_Polish_PreDmg, "udg_PreDamageEvent", EQUAL, 1.00 )
call TriggerAddAction( gg_trg_Nail_Polish_PreDmg, function Trig_Nail_Polish_PreDmg_Actions )
endfunction
//look at zap
function Trig_HERO_DIE_Func011A takes nothing returns nothing
call CustomDefeatBJ( GetEnumPlayer(), "TRIGSTR_064" )
endfunction
function Trig_HERO_DIE_Actions takes nothing returns nothing
local integer i = 0
local player owner
local unit ownerHero
local unit u
local location lu
local integer key
set owner = GetOwningPlayer(GetDyingUnit())
set ownerHero = udg_MainHeroes[GetPlayerId(owner)]
set key = GetHandleId(ownerHero)
set u = LoadUnitHandleBJ('A00R', key, udg_UniqueEffectsMap)
if (u == GetDyingUnit()) then
call SaveUnitHandleBJ(null, 'A00R', key, udg_UniqueEffectsMap)
set lu = GetUnitLoc(u)
call AddSpecialEffectLocBJ( lu, "Objects\\Spawnmodels\\Undead\\UndeadDissipate\\UndeadDissipate.mdl" )
call DestroyEffect( GetLastCreatedEffectBJ() )
call RemoveUnit(u)
call RemoveLocation(lu)
set u = null
endif
call GroupRemoveUnitSimple( GetDyingUnit(), udg_GladiatorsInPlay )
loop
exitwhen i > 9
if ( UnitAlive(udg_MainHeroes[i]) ) then
return
endif
set i = i + 1
endloop
call QuestMessageBJ( GetPlayersAll(), bj_QUESTMESSAGE_MISSIONFAILED, "TRIGSTR_063" )
call TriggerSleepAction( 2 )
call ForForce( udg_HumanPlayers, function Trig_HERO_DIE_Func011A )
endfunction
//===========================================================================
function InitTrig_HERO_DIE takes nothing returns nothing
set gg_trg_HERO_DIE = CreateTrigger( )
call TriggerRegisterPlayerUnitEventSimple( gg_trg_HERO_DIE, Player(0), EVENT_PLAYER_UNIT_DEATH )
call TriggerRegisterPlayerUnitEventSimple( gg_trg_HERO_DIE, Player(1), EVENT_PLAYER_UNIT_DEATH )
call TriggerRegisterPlayerUnitEventSimple( gg_trg_HERO_DIE, Player(2), EVENT_PLAYER_UNIT_DEATH )
call TriggerRegisterPlayerUnitEventSimple( gg_trg_HERO_DIE, Player(3), EVENT_PLAYER_UNIT_DEATH )
call TriggerRegisterPlayerUnitEventSimple( gg_trg_HERO_DIE, Player(4), EVENT_PLAYER_UNIT_DEATH )
call TriggerRegisterPlayerUnitEventSimple( gg_trg_HERO_DIE, Player(5), EVENT_PLAYER_UNIT_DEATH )
call TriggerRegisterPlayerUnitEventSimple( gg_trg_HERO_DIE, Player(6), EVENT_PLAYER_UNIT_DEATH )
call TriggerRegisterPlayerUnitEventSimple( gg_trg_HERO_DIE, Player(7), EVENT_PLAYER_UNIT_DEATH )
call TriggerRegisterPlayerUnitEventSimple( gg_trg_HERO_DIE, Player(8), EVENT_PLAYER_UNIT_DEATH )
call TriggerRegisterPlayerUnitEventSimple( gg_trg_HERO_DIE, Player(9), EVENT_PLAYER_UNIT_DEATH )
call TriggerAddAction( gg_trg_HERO_DIE, function Trig_HERO_DIE_Actions )
endfunction
function Trig_VICTORY_Actions takes nothing returns nothing
local string s = "|cffB22222After the final boss of the undead gladiator games is vanquished, the once-enslaved undead gladiators are finally set free from their cursed servitude. The atmosphere shifts dramatically as the oppressive hold of the games dissolves, allowing the undead warriors to reclaim their autonomy and rest in peace."
set s = "The arena that once echoed with the sounds of combat now falls silent, a testament to their hard-fought liberation.|r"
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, s)
call PolledWait(5.00)
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "|cffB22222The map will end in 10 seconds. Thank you for playing|r")
call DisplayRoundStats(udg_WaveIndex)
call PolledWait(10.00)
call CustomVictoryBJ( Player(0), true, true )
call CustomVictoryBJ( Player(1), true, true )
call CustomVictoryBJ( Player(2), true, true )
call CustomVictoryBJ( Player(3), true, true )
call CustomVictoryBJ( Player(4), true, true )
call CustomVictoryBJ( Player(5), true, true )
call CustomVictoryBJ( Player(6), true, true )
call CustomVictoryBJ( Player(7), true, true )
call CustomVictoryBJ( Player(8), true, true )
call CustomVictoryBJ( Player(9), true, true )
endfunction
//===========================================================================
function InitTrig_VICTORY takes nothing returns nothing
set gg_trg_VICTORY = CreateTrigger( )
call TriggerAddAction( gg_trg_VICTORY, function Trig_VICTORY_Actions )
endfunction