function EnableScriptUsage takes nothing returns nothing
endfunction
function MoveUnitFast takes unit u, real speed, real direction returns nothing
call SetUnitX(u, GetUnitX(u) + speed * Cos(direction) )
call SetUnitY(u, GetUnitY(u) + speed * Sin(direction) )
set u = null
endfunction
//===========================================================================
// Counts key structures owned by a player and his or her allies, including
// structures currently upgrading or under construction.
//
// Key structures: Town Hall, Great Hall, Tree of Life, Necropolis
//
function LivingPlayerHallsFilter takes nothing returns boolean
return (IsUnitAliveBJ(GetFilterUnit()) and IsUnitType(GetFilterUnit(),UNIT_TYPE_TOWNHALL))
endfunction
function CountLivingPlayerTownHalls takes player whichPlayer returns integer
local group g
local integer matchedCount
local boolexpr b=Filter(function LivingPlayerHallsFilter)
set g = CreateGroup()
call GroupEnumUnitsOfPlayer(g, whichPlayer, b)
set matchedCount = CountUnitsInGroup(g)
call DestroyGroup(g)
call DestroyBoolExpr(b)
set b=null
set g=null
return matchedCount
endfunction
function Custom_MeleeGetAllyKeyStructureCount takes player whichPlayer returns integer
local integer playerIndex
local player indexPlayer
local integer keyStructs
// Count the number of buildings controlled by all not-yet-defeated co-allies.
set keyStructs = 0
set playerIndex = 0
loop
set indexPlayer = Player(playerIndex)
if (PlayersAreCoAllied(whichPlayer, indexPlayer)) then
set keyStructs = keyStructs + CountLivingPlayerTownHalls(indexPlayer)
// set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "townhall", true, true)
// set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "greathall", true, true)
// set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "treeoflife", true, true)
// set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "necropolis", true, true)
// set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "custom_h030", true, true)
// set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "custom_h01C", true, true)
// set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "custom_h012", true, true)
// set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "custom_h013", true, true)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h013',indexPlayer)//Never use group functions for this, just count living units for player. Much better idea.
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h014',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h015',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h01C',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h01E',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h01F',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h012',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h02F',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h02J',indexPlayer)
// set keyStructs = keySructs + CountLivingPlayerUnitsOfTypeId('h030',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h000',indexPlayer)//Non-modded human custom ids
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h00D',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h00E',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('o00C',indexPlayer)//Non-modded orc custom ids
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('o00D',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('o00E',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('e00M',indexPlayer)//Non-modded night elf custom ids
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('e00N',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('e00O',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('u00C',indexPlayer)//Non-modded undead custom ids
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('u00D',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('u00E',indexPlayer)
endif
set playerIndex = playerIndex + 1
exitwhen playerIndex == bj_MAX_PLAYERS
endloop
return keyStructs
endfunction
//===========================================================================
function Custom_MeleePlayerIsCrippled takes player whichPlayer returns boolean
local integer allyStructures = MeleeGetAllyStructureCount(whichPlayer)
local integer allyKeyStructures = Custom_MeleeGetAllyKeyStructureCount(whichPlayer)
// Dead teams are not considered to be crippled.
return (allyStructures > 0) and (allyKeyStructures <= 0)
endfunction
//===========================================================================
// Test each player to determine if anyone has become crippled.
//
function Custom_MeleeCheckForCrippledPlayers takes nothing returns nothing
local integer playerIndex
local player indexPlayer
local force crippledPlayers = CreateForce()
local boolean isNowCrippled
local race indexRace
// The "finish soon" exposure of all players overrides any "crippled" exposure
if bj_finishSoonAllExposed then
return
endif
// Check each player to see if he or she has been crippled or uncrippled.
set playerIndex = 0
loop
set indexPlayer = Player(playerIndex)
set isNowCrippled = Custom_MeleePlayerIsCrippled(indexPlayer)
if (not bj_playerIsCrippled[playerIndex] and isNowCrippled) then
// Player became crippled; start their cripple timer.
set bj_playerIsCrippled[playerIndex] = true
call TimerStart(bj_crippledTimer[playerIndex], bj_MELEE_CRIPPLE_TIMEOUT, false, function MeleeCrippledPlayerTimeout)
if (GetLocalPlayer() == indexPlayer) then
// Use only local code (no net traffic) within this block to avoid desyncs.
// Show the timer window.
call TimerDialogDisplay(bj_crippledTimerWindows[playerIndex], true)
// Display a warning message.
call DisplayTimedTextToPlayer(indexPlayer, 0, 0, bj_MELEE_CRIPPLE_MSG_DURATION, "|cffffcc00"+udg_RevealWarning+"|r")
endif
elseif (bj_playerIsCrippled[playerIndex] and not isNowCrippled) then
// Player became uncrippled; stop their cripple timer.
set bj_playerIsCrippled[playerIndex] = false
call PauseTimer(bj_crippledTimer[playerIndex])
if (GetLocalPlayer() == indexPlayer) then
// Use only local code (no net traffic) within this block to avoid desyncs.
// Hide the timer window for this player.
call TimerDialogDisplay(bj_crippledTimerWindows[playerIndex], false)
// Display a confirmation message if the player's team is still alive.
if (MeleeGetAllyStructureCount(indexPlayer) > 0) then
if (bj_playerIsExposed[playerIndex]) then
call DisplayTimedTextToPlayer(indexPlayer, 0, 0, bj_MELEE_CRIPPLE_MSG_DURATION, GetLocalizedString("CRIPPLE_UNREVEALED"))
else
call DisplayTimedTextToPlayer(indexPlayer, 0, 0, bj_MELEE_CRIPPLE_MSG_DURATION, GetLocalizedString("CRIPPLE_UNCRIPPLED"))
endif
endif
endif
// If the player granted shared vision, deny that vision now.
call MeleeExposePlayer(indexPlayer, false)
endif
set playerIndex = playerIndex + 1
exitwhen playerIndex == bj_MAX_PLAYERS
endloop
endfunction
//===========================================================================
// Determine if the lost unit should result in any defeats or victories.
//
function Custom_MeleeCheckLostUnit takes unit lostUnit returns nothing
local player lostUnitOwner = GetOwningPlayer(lostUnit)
// We only need to check for mortality if this was the last building.
if (GetPlayerStructureCount(lostUnitOwner, true) <= 0) then
call MeleeCheckForLosersAndVictors()
endif
// Check if the lost unit has crippled or uncrippled the player.
// (A team with 0 units is dead, and thus considered uncrippled.)
call Custom_MeleeCheckForCrippledPlayers()
endfunction
//===========================================================================
// Determine if the gained unit should result in any defeats, victories,
// or cripple-status changes.
//
function Custom_MeleeCheckAddedUnit takes unit addedUnit returns nothing
local player addedUnitOwner = GetOwningPlayer(addedUnit)
// If the player was crippled, this unit may have uncrippled him/her.
if (bj_playerIsCrippled[GetPlayerId(addedUnitOwner)]) then
call Custom_MeleeCheckForCrippledPlayers()
endif
endfunction
//===========================================================================
function Custom_MeleeTriggerActionConstructCancel takes nothing returns nothing
call Custom_MeleeCheckLostUnit(GetCancelledStructure())
endfunction
//===========================================================================
function Custom_MeleeTriggerActionUnitDeath takes nothing returns nothing
if (IsUnitType(GetDyingUnit(), UNIT_TYPE_STRUCTURE)) then
call Custom_MeleeCheckLostUnit(GetDyingUnit())
endif
endfunction
//===========================================================================
function Custom_MeleeTriggerActionUnitConstructionStart takes nothing returns nothing
call Custom_MeleeCheckAddedUnit(GetConstructingStructure())
endfunction
//===========================================================================
function Custom_MeleeTriggerActionAllianceChange takes nothing returns nothing
call MeleeCheckForLosersAndVictors()
call Custom_MeleeCheckForCrippledPlayers()
endfunction
//===========================================================================
function MeleeInitVictoryDefeatCustomized takes nothing returns nothing
local trigger trig
local integer index
local player indexPlayer
// Create a timer window for the "finish soon" timeout period, it has no timer
// because it is driven by real time (outside of the game state to avoid desyncs)
set bj_finishSoonTimerDialog = CreateTimerDialog(null)
// Set a trigger to fire when we receive a "finish soon" game event
set trig = CreateTrigger()
call TriggerRegisterGameEvent(trig , EVENT_GAME_TOURNAMENT_FINISH_SOON)
call TriggerAddAction(trig , function MeleeTriggerTournamentFinishSoon)
// Set a trigger to fire when we receive a "finish now" game event
set trig = CreateTrigger()
call TriggerRegisterGameEvent(trig , EVENT_GAME_TOURNAMENT_FINISH_NOW)
call TriggerAddAction(trig , function MeleeTriggerTournamentFinishNow)
// Set up each player's mortality code.
set index = 0
loop
set indexPlayer = Player(index)
// Make sure this player slot is playing.
if ( GetPlayerSlotState(indexPlayer) == PLAYER_SLOT_STATE_PLAYING ) then
set bj_meleeDefeated[index]=false
set bj_meleeVictoried[index]=false
// Create a timer and timer window in case the player is crippled.
set bj_playerIsCrippled[index]=false
set bj_playerIsExposed[index]=false
set bj_crippledTimer[index]=CreateTimer()
set bj_crippledTimerWindows[index]=CreateTimerDialog(bj_crippledTimer[index])
call TimerDialogSetTitle(bj_crippledTimerWindows[index] , MeleeGetCrippledTimerMessage(indexPlayer))
// Set a trigger to fire whenever a building is cancelled for this player.
set trig = CreateTrigger()
call TriggerRegisterPlayerUnitEvent(trig , indexPlayer , EVENT_PLAYER_UNIT_CONSTRUCT_CANCEL , null)
call TriggerAddAction(trig , function Custom_MeleeTriggerActionConstructCancel)
// Set a trigger to fire whenever a unit dies for this player.
set trig = CreateTrigger()
call TriggerRegisterPlayerUnitEvent(trig , indexPlayer , EVENT_PLAYER_UNIT_DEATH , null)
call TriggerAddAction(trig , function Custom_MeleeTriggerActionUnitDeath)
// Set a trigger to fire whenever a unit begins construction for this player
set trig = CreateTrigger()
call TriggerRegisterPlayerUnitEvent(trig , indexPlayer , EVENT_PLAYER_UNIT_CONSTRUCT_START , null)
call TriggerAddAction(trig , function Custom_MeleeTriggerActionUnitConstructionStart)
// Set a trigger to fire whenever this player defeats-out
set trig = CreateTrigger()
call TriggerRegisterPlayerEvent(trig , indexPlayer , EVENT_PLAYER_DEFEAT)
call TriggerAddAction(trig , function MeleeTriggerActionPlayerDefeated)
// Set a trigger to fire whenever this player leaves
set trig = CreateTrigger()
call TriggerRegisterPlayerEvent(trig , indexPlayer , EVENT_PLAYER_LEAVE)
call TriggerAddAction(trig , function MeleeTriggerActionPlayerLeft)
// Set a trigger to fire whenever this player changes his/her alliances.
set trig = CreateTrigger()
call TriggerRegisterPlayerAllianceChange(trig , indexPlayer , ALLIANCE_PASSIVE)
call TriggerRegisterPlayerStateEvent(trig , indexPlayer , PLAYER_STATE_ALLIED_VICTORY , EQUAL , 1)
call TriggerAddAction(trig , function Custom_MeleeTriggerActionAllianceChange)
else
set bj_meleeDefeated[index]=true
set bj_meleeVictoried[index]=false
// Handle leave events for observers
if ( IsPlayerObserver(indexPlayer) ) then
// Set a trigger to fire whenever this player leaves
set trig = CreateTrigger()
call TriggerRegisterPlayerEvent(trig , indexPlayer , EVENT_PLAYER_LEAVE)
call TriggerAddAction(trig , function MeleeTriggerActionPlayerLeft)
endif
endif
set index = index + 1
exitwhen index == bj_MAX_PLAYERS
endloop
// Test for victory / defeat at startup, in case the user has already won / lost.
// Allow for a short time to pass first, so that the map can finish loading.
call TimerStart(CreateTimer() , 2.0 , false , function Custom_MeleeTriggerActionAllianceChange)
endfunction
Name | Type | is_array | initial_value |
AB_Ammo | integer | Yes | |
AB_AOE | real | Yes | |
AB_CCount | integer | No | |
AB_Duration | real | Yes | |
AB_Effect | effect | Yes | |
AB_FireAngle | real | Yes | |
AB_FireHeight | real | Yes | |
AB_FirePower | real | Yes | |
AB_FireRate | real | Yes | |
AB_FireTimer | real | Yes | |
AB_LastNode | integer | No | |
AB_NextNode | integer | Yes | |
AB_NodeNumber | integer | No | |
AB_PrevNode | integer | Yes | |
AB_RecyclableNodes | integer | No | |
AB_RecycleNodes | integer | Yes | |
AB_Target | unit | Yes | |
AB_Timer | timer | No | |
AB_Unit | unit | Yes | |
Angle | real | No | |
areaofeffect | real | Yes | |
AscentHeight | real | No | |
AscentSpeed | real | No | |
Assa_Ability | abilcode | No | |
Assa_Area | real | Yes | |
Assa_Attacks | integer | Yes | |
Assa_Caster | unit | Yes | |
Assa_DamageE | real | Yes | |
Assa_DamageS | real | Yes | |
Assa_GroupDMG | group | No | |
Assa_Loop | integervar | No | |
Assa_Lvl | integer | Yes | |
Assa_Max | integer | No | |
Assa_PointR | location | No | |
Assa_PointT | location | No | |
Assa_Random | real | No | |
Assa_Target | unit | Yes | |
AT_AddDistanceLoop | real | Yes | |
AT_AllowBuildings | boolean | Yes | |
AT_AllowBuildingsLoop | boolean | Yes | |
AT_AllowCliffs | boolean | Yes | |
AT_AllowCliffsLoop | boolean | Yes | |
AT_AllowWater | boolean | Yes | |
AT_AllowWaterLoop | boolean | Yes | |
AT_AngleMove | real | Yes | |
AT_AngleMoveLoop | real | Yes | |
AT_AoE1Axe | real | Yes | |
AT_AoE1AxeLoop | real | Yes | |
AT_AoE2Axe | real | Yes | |
AT_AoE2AxeLoop | real | Yes | |
AT_AoE3Axe | real | Yes | |
AT_AoE3AxeLoop | real | Yes | |
AT_AxeLoop | unit | Yes | |
AT_AxePointLoop | unit | Yes | |
AT_AxeSpeedCurrent | real | Yes | |
AT_AxeSpeedCurrentLoop | real | Yes | |
AT_AxeSpeedDecreasement | real | Yes | |
AT_AxeSpeedDecreasementLoop | real | Yes | |
AT_AxeSpeedDefault | real | Yes | |
AT_AxeSpeedDefaultLoop | real | Yes | |
AT_BloodEffect | string | Yes | |
AT_BloodEffectLoop | string | Yes | |
AT_BumpEffect | string | Yes | |
AT_BumpEffectLoop | string | Yes | |
AT_Caster | unit | Yes | |
AT_CasterLoop | unit | Yes | |
AT_Damages | real | Yes | |
AT_DamagesLoop | real | Yes | |
AT_DestroyTrees | boolean | Yes | |
AT_DestroyTreesLoop | boolean | Yes | |
AT_DistanceAxe | real | Yes | |
AT_DistanceAxeLoop | real | Yes | |
AT_Group | group | No | |
AT_GroupAxeLoop | group | No | |
AT_GroupLoop | group | Yes | |
AT_IntegerCasting1 | integer | No | |
AT_IntegerCasting2 | integer | No | |
AT_IntegerCasting3 | integervar | No | |
AT_IntegerThrowingLoop1 | integer | No | |
AT_IntegerThrowingLoop2 | integer | No | |
AT_IntegerThrowingLoop3 | integervar | No | |
AT_Level | integer | Yes | |
AT_NumberAxesRemaining | integer | Yes | |
AT_NumberAxesThrown | integer | Yes | |
AT_RandomIntegerForBlood | integer | No | |
AT_Return | boolean | Yes | |
AT_TempGroupLoop | group | No | |
AT_TempPoint | location | No | |
AT_TempPoint2 | location | No | |
AT_TempPoint3 | location | No | |
AT_TimerCasting | real | Yes | |
AT_TimerElapsedCasting | real | Yes | |
attachmentpoint | string | No | |
boolean | boolean | No | |
BUS_Loc | location | No | |
BUS_MapMaxX | real | No | |
BUS_MapMaxY | real | No | |
BUS_MapMinX | real | No | |
BUS_MapMinY | real | No | |
BUS_Rect | rect | No | |
BUS_Stunner | unit | No | |
BUS_Target | unit | No | |
BUS_TreeChecker | unit | No | |
BUS_Unit | unit | No | |
BUS_X | real | No | |
BUS_Y | real | No | |
BUSC_Ability | real | Yes | |
BUSC_Cancel | boolean | Yes | |
BUSC_CChangeHueDelay | real | Yes | |
BUSC_CCount | integer | No | |
BUSC_CDelay | real | Yes | |
BUSC_CDuration | real | Yes | |
BUSC_ChangeHueDelay | real | Yes | |
BUSC_ChannelId | integer | Yes | |
BUSC_CHueAlpha | integer | Yes | |
BUSC_CHueBlue | integer | Yes | |
BUSC_CHueGreen | integer | Yes | |
BUSC_CHueRed | integer | Yes | |
BUSC_Delay | real | Yes | |
BUSC_Event | real | No | |
BUSC_HueChange | boolean | Yes | |
BUSC_HueChangeAlpha | integer | Yes | |
BUSC_HueChangeBlue | integer | Yes | |
BUSC_HueChangeGreen | integer | Yes | |
BUSC_HueChangeRed | integer | Yes | |
BUSC_LastNode | integer | No | |
BUSC_NextNode | integer | Yes | |
BUSC_NodeNumber | integer | No | |
BUSC_Order | ordercode | Yes | |
BUSC_PCaster | unit | Yes | |
BUSC_PCount | integer | No | |
BUSC_PCurrentEffect | effect | Yes | |
BUSC_PCurrentZ | real | Yes | |
BUSC_PLastNode | integer | No | |
BUSC_PNextNode | integer | Yes | |
BUSC_PNodeNumber | integer | No | |
BUSC_PPrevNode | integer | Yes | |
BUSC_PRecyclableNodes | integer | No | |
BUSC_PRecycleNodes | integer | Yes | |
BUSC_PrevNode | integer | Yes | |
BUSC_PUnit | unit | Yes | |
BUSC_PXVelocity | real | Yes | |
BUSC_PYVelocity | real | Yes | |
BUSC_PZVelocity | real | Yes | |
BUSC_RecyclableNodes | integer | No | |
BUSC_RecycleNodes | integer | Yes | |
BUSC_Running | boolean | Yes | |
BUSC_Target | unit | Yes | |
BUSC_TargetX | real | Yes | |
BUSC_TargetY | real | Yes | |
BUSC_Timer | timer | No | |
BUSC_Unit | unit | Yes | |
BUSCR_AbsorbAOE | real | Yes | |
BUSCR_Counter | integer | No | |
BUSCR_Effect | string | Yes | |
BUSCR_HueAlpha | real | Yes | |
BUSCR_HueBlue | real | Yes | |
BUSCR_HueGreen | real | Yes | |
BUSCR_HueRed | real | Yes | |
BUSCR_HueSpeed | real | Yes | |
BUSCR_MaxAOE | real | Yes | |
BUSCR_MaxSize | real | Yes | |
BUSCR_MinAOE | real | Yes | |
BUSCR_MinSize | real | Yes | |
BUSCR_Name | string | Yes | |
BUSCR_Power | real | Yes | |
BUSCR_SpawnCount | integer | Yes | |
BUSCR_SpawnRate | real | Yes | |
BUSE_Cancel | boolean | Yes | |
BUSE_NextNode | integer | Yes | |
BUSE_NodeNumber | integer | No | |
BUSE_PAOE | real | Yes | |
BUSE_PCaster | unit | Yes | |
BUSE_PCurrentEffect | effect | Yes | |
BUSE_PCurrentSize | real | Yes | |
BUSE_PDoesPan | boolean | Yes | |
BUSE_PDX | real | Yes | |
BUSE_PDY | real | Yes | |
BUSE_PDZ | real | Yes | |
BUSE_PGrowing | boolean | Yes | |
BUSE_PGrowthTime | real | Yes | |
BUSE_PHealthDamage | real | Yes | |
BUSE_PManaDamage | real | Yes | |
BUSE_PNextNode | integer | Yes | |
BUSE_PNodeNumber | integer | No | |
BUSE_POwner | player | Yes | |
BUSE_PPan | real | Yes | |
BUSE_PPanningTime | real | Yes | |
BUSE_PPrevNode | integer | Yes | |
BUSE_PRange | real | Yes | |
BUSE_PRecyclableNodes | integer | No | |
BUSE_PRecycleNodes | integer | Yes | |
BUSE_PRemove | boolean | Yes | |
BUSE_PrevNode | integer | Yes | |
BUSE_PScaleSpeed | real | Yes | |
BUSE_PTimer | real | Yes | |
BUSE_PUnit | unit | Yes | |
BUSE_RecyclableNodes | integer | No | |
BUSE_RecycleNodes | integer | Yes | |
BUSE_Timer | timer | No | |
BUSE_Unit | unit | Yes | |
BUSE_UnitGroup | group | No | |
BUSF_CurrentEffect | effect | Yes | |
BUSF_CurrentSize | real | Yes | |
BUSF_GrowthTime | real | Yes | |
BUSF_NextNode | integer | Yes | |
BUSF_NodeNumber | integer | No | |
BUSF_PrevNode | integer | Yes | |
BUSF_RecyclableNodes | integer | No | |
BUSF_RecycleNodes | integer | Yes | |
BUSF_Remove | boolean | Yes | |
BUSF_RemoveTimer | real | Yes | |
BUSF_ScaleSpeed | real | Yes | |
BUSF_Timer | timer | No | |
BUSF_Unit | unit | Yes | |
BUSF_UnitGroup | group | No | |
BUSK_CurrentEffect | effect | Yes | |
BUSK_CurrentHeight | real | Yes | |
BUSK_KnockbackX | real | Yes | |
BUSK_KnockbackY | real | Yes | |
BUSK_KnockbackZ | real | Yes | |
BUSK_NextNode | integer | Yes | |
BUSK_NodeNumber | integer | No | |
BUSK_PrevNode | integer | Yes | |
BUSK_RecyclableNodes | integer | No | |
BUSK_RecycleNodes | integer | Yes | |
BUSK_ReturnHeight | real | Yes | |
BUSK_Timer | timer | No | |
BUSK_TreeCounter | integer | No | |
BUSK_Unit | unit | Yes | |
BUSK_UnitType | boolean | Yes | |
BUSR_NextNode | integer | Yes | |
BUSR_NodeNumber | integer | No | |
BUSR_PAlphaReduction | integer | Yes | |
BUSR_PCurrentAlpha | integer | Yes | |
BUSR_PNextNode | integer | Yes | |
BUSR_PNodeNumber | integer | No | |
BUSR_PPrevNode | integer | Yes | |
BUSR_PRecyclableNodes | integer | No | |
BUSR_PRecycleNodes | integer | Yes | |
BUSR_PrevNode | integer | Yes | |
BUSR_PSpeed | real | Yes | |
BUSR_PUnit | unit | Yes | |
BUSR_RecyclableNodes | integer | No | |
BUSR_RecycleNodes | integer | Yes | |
BUSR_Time | real | Yes | |
BUSR_Timer | timer | No | |
BUSR_Unit | unit | Yes | |
BUSR_UnitGroup | group | No | |
BUSS_Activate | boolean | Yes | |
BUSS_Angle | real | Yes | |
BUSS_AOE | real | Yes | |
BUSS_Cancel | boolean | Yes | |
BUSS_DX | real | Yes | |
BUSS_DY | real | Yes | |
BUSS_DZ | real | Yes | |
BUSS_EffectMade | boolean | Yes | |
BUSS_EndChannelTime | real | Yes | |
BUSS_EndDelay | real | Yes | |
BUSS_Force | real | Yes | |
BUSS_HealthDamage | real | Yes | |
BUSS_LaserScale | real | Yes | |
BUSS_ManaDamage | real | Yes | |
BUSS_NextNode | integer | Yes | |
BUSS_NodeNumber | integer | No | |
BUSS_Owner | player | Yes | |
BUSS_PAnimationIndex | integer | Yes | |
BUSS_PCaster | unit | Yes | |
BUSS_PCurrentEffect | effect | Yes | |
BUSS_PNextNode | integer | Yes | |
BUSS_PNodeNumber | integer | No | |
BUSS_PPrevNode | integer | Yes | |
BUSS_PRecyclableNodes | integer | No | |
BUSS_PRecycleNodes | integer | Yes | |
BUSS_PRemove | boolean | Yes | |
BUSS_PrevNode | integer | Yes | |
BUSS_PScale | real | Yes | |
BUSS_PTimer | real | Yes | |
BUSS_PUnit | unit | Yes | |
BUSS_PX | real | Yes | |
BUSS_PY | real | Yes | |
BUSS_PZ | real | Yes | |
BUSS_Range | real | Yes | |
BUSS_RecyclableNodes | integer | No | |
BUSS_RecycleNodes | integer | Yes | |
BUSS_Timer | timer | No | |
BUSS_Unit | unit | Yes | |
BUSS_UnitGroup | group | No | |
caster | unit | No | |
CentaurResistance | force | No | Force09 |
CenterPoint | location | No | |
CfO__Aura | unit | Yes | |
CfO__AuraFx | effect | Yes | |
CfO__Caster | unit | Yes | |
CfO__Count | integer | No | |
CfO__Damage | real | Yes | |
CfO__Duration | real | Yes | |
CfO__Hashtable | hashtable | No | |
CfO__Level | integer | Yes | |
CfO__MCount | integer | Yes | |
CfO__Missile__Angle | real | Yes | |
CfO__Missile__AngleX | real | Yes | |
CfO__Missile__Count | integer | No | |
CfO__Missile__Distance | real | Yes | |
CfO__Missile__Dummy | unit | Yes | |
CfO__Missile__Fx | effect | Yes | |
CfO__Missile__Source | integer | Yes | |
CfO__Missile__Target | unit | Yes | |
CfO__Missile__Targets | group | Yes | |
CfO__Missile__Timer | timer | No | |
CfO__Missile__TurnDelay | real | Yes | |
CfO__Missile__X | real | Yes | |
CfO__Missile__Y | real | Yes | |
CfO__Orb | unit | Yes | |
CfO__OrbFx | effect | Yes | |
CfO__Owner | player | Yes | |
CfO__ReleaseCount | integer | Yes | |
CfO__ReleaseDelay | real | Yes | |
CfO__ReleaseDelayX | real | Yes | |
CfO__Slow__Caster | unit | No | |
CfO__Slow__Count | integer | No | |
CfO__Slow__Duration | real | Yes | |
CfO__Slow__Target | unit | Yes | |
CfO__Slow__Timer | timer | No | |
CfO__StrikeDelay | real | Yes | |
CfO__StrikeDelayX | real | Yes | |
CfO__TempGroup | group | No | |
CfO__TempInt | integer | No | |
CfO__Timer | timer | No | |
CfO__Velocity | real | Yes | |
CfO__WorldBounds | real | Yes | |
CfO__X | real | Yes | |
CfO__Y | real | Yes | |
Circle_Position_setter | real | No | |
Config | integer | Yes | |
CP_HiddenItems | item | Yes | |
CP_HiddenItemsIndex | integer | No | |
CP_Item | item | No | |
CP_Point | location | No | |
CP_PointIsWalkable | boolean | No | |
CP_Rect | rect | No | |
damage | real | Yes | |
Debug | integervar | No | |
Distance | real | No | |
EFB_Hash | hashtable | No | |
EFB_Moving_Units | group | No | |
ExplosionLayersBase | integer | No | |
ExplosionLayersPerlevel | integer | No | |
ExplosionProjectileHeightMutli | real | No | |
ExplosionRadius | real | No | |
ExplosionRadiusCurrent | real | No | |
ExplosionSidesBase | integer | No | |
ExplosionSidesPerLevel | integer | No | |
FBurst_ABILITY | abilcode | No | |
FBurst_ABILITY_MOVE_SPEED | abilcode | No | |
FBurst_ABILITY_SECOND_DEBUFF | abilcode | No | |
FBurst_AbilityLvl | integer | No | |
FBurst_AbilityLvlWave | integer | Yes | |
FBurst_Angle | real | No | |
FBurst_ATTACK_TYPE | attacktype | No | |
FBurst_Caster | unit | No | |
FBurst_CasterWave | unit | Yes | |
FBurst_Cos | real | Yes | |
FBurst_DAMAGE_TYPE | damagetype | No | |
FBurst_DEBUFF_PRIMARY | buffcode | No | |
FBurst_DEBUFF_SECONDARY | buffcode | No | |
FBurst_DistanceTraveled | real | Yes | |
FBurst_DOT_PRIMARY_DAMAGE | real | Yes | |
FBurst_DOT_PRIMARY_DURATION | real | Yes | |
FBurst_DOT_SECONDARY_DAMAGE | real | Yes | |
FBurst_DOT_SECONDARY_DURATION | real | Yes | |
FBurst_DummyCaster | unit | No | |
FBurst_Duration | real | No | |
FBurst_ERROR_MSG | string | No | |
FBurst_ErrorSound | sound | No | |
FBurst_EXPLOSION_DAMAGE | real | Yes | |
FBurst_EXPLOSION_RADIUS | real | Yes | |
FBurst_Hash | hashtable | No | |
FBurst_InRangeGroup | group | No | |
FBurst_LoopInt | integervar | No | |
FBurst_MAX_LEVEL | integer | No | |
FBurst_MaxIndex | integer | No | |
FBurst_NodeNext | integer | Yes | |
FBurst_NodePrev | integer | Yes | |
FBurst_ORDER_ID | string | No | |
FBurst_Owner | player | No | |
FBurst_OwnerWave | player | Yes | |
FBurst_PERIODIC_TIMER | real | No | |
FBurst_PrimaryGroup | group | No | |
FBurst_PrimaryGroupCount | integer | No | |
FBurst_RecycledSize | integer | No | |
FBurst_RecycledStack | integer | Yes | |
FBurst_SecondaryGroupCount | integer | No | |
FBurst_SeondaryGroup | group | No | |
FBurst_SFX_EXPLOSION | string | No | |
FBurst_SFX_EXPLOSION_AP | string | No | |
FBurst_SFX_PRIMARY_DEBUFF | string | No | |
FBurst_SFX_PRIMARY_DEBUFF_AP | string | No | |
FBurst_SFX_SECOND_DEBUFF | string | No | |
FBurst_SFX_SECOND_DEBUFF_AP | string | No | |
FBurst_SFX_WAVE | string | No | |
FBurst_SFX_WAVE_AP | string | No | |
FBurst_SFX_WAVE_INDICATOR | string | No | |
FBurst_SFX_WAVE_INDICATOR_AP | string | No | |
FBurst_Sin | real | Yes | |
FBurst_SourceUnit | unit | Yes | |
FBurst_SpawnAngle | real | Yes | |
FBurst_SPELL_DUMMY_OWNER | player | No | |
FBurst_SPELL_DUMMY_UNIT_TYPE | unitcode | No | |
FBurst_Target | unit | No | |
FBurst_TempInt | integer | No | |
FBurst_TempLoc | location | No | |
FBurst_TempUnit | unit | No | |
FBurst_TRAVEL_DISTANCE | real | Yes | |
FBurst_TRAVEL_DURATION | real | Yes | |
FBurst_TravelSpeed | real | Yes | |
FBurst_TRIGGER_APPLY_DOT | trigger | No | |
FBurst_TRIGGER_CREATE_WAVE | trigger | No | |
FBurst_TRIGGER_DOT_DEATH | trigger | No | |
FBurst_TRIGGER_PATHING_CHECK | trigger | No | |
FBurst_TRIGGER_PRIMARY_LOOP | trigger | No | |
FBurst_TRIGGER_SECONDARY_LOOP | trigger | No | |
FBurst_TRIGGER_WAVE_LOOP | trigger | No | |
FBurst_UnitId | integer | No | |
FBurst_WAVE_COUNT | integer | Yes | |
FBurst_WAVE_INTERVAL | real | Yes | |
FBurst_WAVE_RADIUS | real | Yes | |
FBurst_WaveCount | integer | No | |
FBurst_WaveCounter | real | No | |
FBurst_WaveId | integer | No | |
FBurst_WaveSfx | effect | Yes | |
FBurst_WaveUnit | unit | Yes | |
FBurst_X | real | No | |
FBurst_Y | real | No | |
FlareSegmentGroup | group | No | |
FlareStarHash | hashtable | No | |
handle | integer | No | |
hashtable | hashtable | No | |
HC_Angle | real | No | |
HC_Aoe | real | Yes | |
HC_AoeBase | real | No | |
HC_AoePerLevel | real | No | |
HC_BlastCap | real | No | |
HC_BlastDistance | real | Yes | |
HC_BlastDistanceBase | real | No | |
HC_BlastDistanceMultiplyer | real | No | |
HC_BlastSpeed | real | No | |
HC_BurnSFX | string | No | |
HC_Caster | unit | No | |
HC_ConditionConfig | boolean | Yes | |
HC_Core | unit | Yes | |
HC_CurrentAngle | real | Yes | |
HC_CurrentBlastDistance | real | Yes | |
HC_CurrentHeight | real | Yes | |
HC_CurrentMagnetism | real | No | |
HC_CurrentSunDistance | real | Yes | |
HC_Distance | real | Yes | |
HC_DummyExpirationTimers | real | No | |
HC_DummyType | unitcode | No | |
HC_EffectScalingBlast | real | No | |
HC_EffectScalingOrbs | real | No | |
HC_EffectScalingSun | real | No | |
HC_EffectScalingWind | real | No | |
HC_EffectZBlast | real | No | |
HC_EffectZOrbs | real | No | |
HC_EffectZSun | real | No | |
HC_EffectZWind | real | No | |
HC_ExplosionAOE | real | No | |
HC_ExplosionDamage | real | Yes | |
HC_ExplosionDamageBase | real | No | |
HC_ExplosionDamagePerLevel | real | No | |
HC_ExplosionSFX | string | No | |
HC_FireOrbSFX | string | No | |
HC_FireOrbSpinSpeed | real | No | |
HC_HeightMultiplyer | real | No | |
HC_Index | integervar | No | |
HC_MagnetismCap | real | No | |
HC_MagnetismDistanceMultiplyer | real | No | |
HC_MagnetismStrength | real | Yes | |
HC_MagnetismStrengthBase | real | No | |
HC_MagnetismStrengthPerLevel | real | No | |
HC_MaxHeight | real | Yes | |
HC_MaxIndex | integer | No | |
HC_OrbCountBase | integer | No | |
HC_OrbCountPerLevel | integer | No | |
HC_OrbDistance | real | No | |
HC_OriginalCaster | unit | Yes | |
HC_OwningPlayer | player | Yes | |
HC_SecondaryIndex | integervar | No | |
HC_SpecialEffect | effect | Yes | |
HC_Spell | abilcode | No | |
HC_StageID | integer | Yes | |
HC_SunSFX | string | No | |
HC_SunSpeed | real | No | |
HC_TempGroup | group | No | |
HC_TempInteger | integer | No | |
HC_TempInteger2 | integer | No | |
HC_TempPoint | location | No | |
HC_TempPoint2 | location | No | |
HC_TempReal | real | No | |
HC_TempUnit | unit | No | |
HC_TempUnit2 | unit | No | |
HC_TempX | real | No | |
HC_TempY | real | No | |
HC_TempZ | real | No | |
HC_UnitIndex | unit | Yes | |
HC_WindCountBase | integer | No | |
HC_WindCountPerLevel | integer | No | |
HC_WindDistance | real | No | |
HC_WindSFX | string | No | |
HC_WindSpinSpeed | real | No | |
ICol__AoE | real | Yes | |
ICol__Caster | unit | Yes | |
ICol__Count | integer | No | |
ICol__Damage | real | Yes | |
ICol__Delay | real | Yes | |
ICol__DelayMax | real | Yes | |
ICol__DelayMin | real | Yes | |
ICol__Dispose | boolean | Yes | |
ICol__DistanceMax | real | Yes | |
ICol__DistanceMin | real | Yes | |
ICol__Duration | real | Yes | |
ICol__Hashtable | hashtable | No | |
ICol__HeightMax | real | Yes | |
ICol__HeightMin | real | Yes | |
ICol__Level | integer | Yes | |
ICol__Lifespan | real | Yes | |
ICol__OCount | integer | Yes | |
ICol__Orb__CoreFx | effect | Yes | |
ICol__Orb__Count | integer | No | |
ICol__Orb__Dummy | unit | Yes | |
ICol__Orb__GlowFx | effect | Yes | |
ICol__Orb__Scale | real | Yes | |
ICol__Orb__ScaleRate | real | Yes | |
ICol__Orb__Source | integer | Yes | |
ICol__Orb__SwirlFx | effect | Yes | |
ICol__Orb__Timer | timer | No | |
ICol__Orb__X | real | Yes | |
ICol__Orb__Y | real | Yes | |
ICol__Orb__Z | real | Yes | |
ICol__Owner | player | Yes | |
ICol__SpawnCount | integer | Yes | |
ICol__TempGroup | group | No | |
ICol__TempLoc | location | No | |
ICol__Timer | timer | No | |
ICol__X | real | Yes | |
ICol__Y | real | Yes | |
IsUnitBeingKnockedBack | boolean | Yes | |
K2DAmphibious | boolean | Yes | |
K2DAngle | real | Yes | |
K2DBounce | boolean | Yes | |
K2DCollision | real | Yes | |
K2DCos | real | Yes | |
K2DCosD1 | real | Yes | |
K2DCosD2 | real | Yes | |
K2DCosH | real | Yes | |
K2DDebrisKiller | unit | No | |
K2DDestRadius | real | Yes | |
K2DDistanceLeft | real | Yes | |
K2DFlying | boolean | Yes | |
K2DFreeze | boolean | Yes | |
K2DFriction | real | Yes | |
K2DFXModel | string | Yes | |
K2DFXRate | real | Yes | |
K2DFXTimeLeft | real | Yes | |
K2DHeight | real | Yes | |
K2DHeightThreshold | real | Yes | |
K2DImpact | trigger | Yes | |
K2DItem | item | No | |
K2DItemOffset | boolean | No | |
K2DItemsFound | boolean | No | |
K2DKillTrees | boolean | Yes | |
K2DLastX | real | Yes | |
K2DLastY | real | Yes | |
K2DMaxDestRadius | real | No | |
K2DMaxX | real | No | |
K2DMaxY | real | No | |
K2DMinX | real | No | |
K2DMinY | real | No | |
K2DNext | integer | Yes | |
K2DOverride | boolean | Yes | |
K2DPause | boolean | Yes | |
K2DPrev | integer | Yes | |
K2DRadius | integer | Yes | |
K2DRegion | rect | No | |
K2DSimple | boolean | Yes | |
K2DSin | real | Yes | |
K2DSinD1 | real | Yes | |
K2DSinD2 | real | Yes | |
K2DSinH | real | Yes | |
K2DSource | unit | Yes | |
K2DTimeLeft | real | Yes | |
K2DTimeout | real | No | |
K2DTimer | timer | No | |
K2DUnbiasedCollision | boolean | Yes | |
K2DVelocity | real | Yes | |
K2DX | real | No | |
K2DY | real | No | |
Kh_ability | abilcode | No | |
Kh_angle | real | Yes | |
Kh_attachedEffect | effect | Yes | |
Kh_attackType | attacktype | No | |
Kh_caster | unit | Yes | |
Kh_channelDuration | real | Yes | |
Kh_channelEffect | string | No | |
Kh_channelEffectAttachment | string | No | |
Kh_channelSound | sound | No | |
Kh_curTransparency | real | Yes | |
Kh_damagedGroup | group | Yes | |
Kh_damageExplosion | real | Yes | |
Kh_damageExplosionRadius | real | Yes | |
Kh_damageMEffectAttachment | string | No | |
Kh_damageMissile | real | Yes | |
Kh_damageMissileEffect | string | No | |
Kh_damageMissileRadius | real | Yes | |
Kh_damageType | damagetype | No | |
Kh_distance | real | Yes | |
Kh_dummy | unit | No | |
Kh_dustEffectAnimSpeed | real | No | |
Kh_dustEffectDummy | unitcode | No | |
Kh_dustEffectScale | real | Yes | |
Kh_dustEffectTime | real | No | |
Kh_explosionEffect1Scale | real | Yes | |
Kh_explosionEffect2Scale | real | Yes | |
Kh_explosionEffectDummy | unitcode | Yes | |
Kh_explosionEffectTime | real | Yes | |
Kh_harvester | unit | No | |
Kh_harvestOrder | ordercode | No | |
Kh_index | integervar | No | |
Kh_lastSound | sound | Yes | |
Kh_level | integer | Yes | |
Kh_loopingEffectDummy | unitcode | No | |
Kh_loopingEffectInterval | real | No | |
Kh_loopingEffectOffset | real | No | |
Kh_loopingEffectScale | real | Yes | |
Kh_loopingEffectTime | real | No | |
Kh_maxIndex | integer | No | |
Kh_missileDummy | unitcode | No | |
Kh_missileEffectDummy | unitcode | No | |
Kh_missileEffectInterval | real | No | |
Kh_missileEffectScale | real | Yes | |
Kh_missileEffectTime | real | No | |
Kh_missileFadeSpeed | real | Yes | |
Kh_missileGroup | group | Yes | |
Kh_missileHead | unit | Yes | |
Kh_missileHeadDummy | unitcode | No | |
Kh_missileHeadScale | real | Yes | |
Kh_missilePathType | pathingtype | No | |
Kh_missileScale | real | Yes | |
Kh_missileSpeed | real | Yes | |
Kh_missileStartOffset | real | No | |
Kh_orderID | ordercode | No | |
Kh_owner | player | Yes | |
Kh_pickedUnit | unit | No | |
Kh_reachedDistance | real | Yes | |
Kh_realTimer | real | Yes | |
Kh_realTimer2 | real | Yes | |
Kh_releaseEffectDummy | unitcode | No | |
Kh_releaseEffectOffset | real | No | |
Kh_releaseEffectScale | real | Yes | |
Kh_releaseEffectTime | real | No | |
Kh_releaseSound | sound | No | |
Kh_stageID | integer | Yes | |
Kh_startPoint | location | Yes | |
Kh_tempDest | destructable | No | |
Kh_tempGroup | group | No | |
Kh_tempLoc | location | No | |
Kh_tempLoc2 | location | No | |
Kh_throwAnimation | string | No | |
Kh_throwAnimationSpeed | real | Yes | |
Kh_throwDelay | real | Yes | |
Kh_timerSpeed | real | No | |
Knockback2DAmphibious | boolean | No | |
Knockback2DAngle | real | No | |
Knockback2DBounces | boolean | No | |
Knockback2DCollision | real | No | |
Knockback2DDefaultBounce | boolean | No | |
Knockback2DDefaultDestRadius | real | No | |
Knockback2DDefaultFriction | real | No | |
Knockback2DDefaultFX | string | No | |
Knockback2DDefaultFXRate | real | No | |
Knockback2DDefaultGravity | real | No | |
Knockback2DDefaultKillTrees | boolean | No | |
Knockback2DDefaultPause | boolean | No | |
Knockback2DDestRadius | real | No | |
Knockback2DDistance | real | No | |
Knockback2DFriction | real | No | |
Knockback2DFXRate | real | No | |
Knockback2DGravity | real | No | |
Knockback2DHeight | real | No | |
Knockback2DKillTrees | boolean | No | |
Knockback2DLoopFX | string | No | |
Knockback2DOnImpact | trigger | No | |
Knockback2DOverride | boolean | No | |
Knockback2DPause | boolean | No | |
Knockback2DRobustPathing | integer | No | |
Knockback2DSimple | boolean | No | |
Knockback2DSource | unit | No | |
Knockback2DTime | real | No | |
Knockback2DTreeOrDebris | string | No | |
Knockback2DUnbiasedCollision | boolean | No | |
Knockback2DUnit | unit | No | |
leashbreakdamage | boolean | No | |
leashbreakmanaburn | boolean | No | |
leashrange | real | Yes | |
level | integer | No | |
light | lightning | No | |
lightning | lightning | No | |
lightningcoloring | real | Yes | |
lightningtype | lightningtype | No | |
LoopInt | integer | No | |
manaburn | boolean | No | |
MC_Angle | real | Yes | |
MC_AngleAdjust | real | Yes | |
MC_AngleLimit | real | Yes | |
MC_AOE | real | Yes | |
MC_CleaveScale | real | Yes | |
MC_Delay | real | Yes | |
MC_DelayReset | real | Yes | |
MC_Division | real | Yes | |
MC_EffectDistance | real | Yes | |
MC_HealthDamage | real | Yes | |
MC_KnockbackForce | real | Yes | |
MC_ManaDamage | real | Yes | |
MC_NextNode | integer | Yes | |
MC_NodeNumber | integer | No | |
MC_Player | player | Yes | |
MC_PrevNode | integer | Yes | |
MC_RecyclableNodes | integer | No | |
MC_RecycleNodes | integer | Yes | |
MC_TempGroup | group | No | |
MC_Timer | timer | No | |
MC_Unit | unit | Yes | |
MEB_Angle | real | No | |
MEB_Bomb | unitcode | No | |
MEB_Bombs | group | No | |
MEB_BurnAoe | real | No | |
MEB_BurnDamageBase | real | No | |
MEB_BurnDamagePerLevel | real | No | |
MEB_DamageBase | real | No | |
MEB_DamagePerLevel | real | No | |
MEB_DistanceIncrease | real | No | |
MEB_DurationBase | real | No | |
MEB_DurationPerLevel | real | No | |
MEB_ExplosionAOEBase | real | No | |
MEB_ExplosionAOPerLevel | real | No | |
MEB_Hash | hashtable | No | |
MEB_I | integervar | No | |
MEB_KnockbackDetriment | real | No | |
MEB_KnockbackStrengthBase | real | No | |
MEB_KnockbackStrengthPerLevel | real | No | |
MEB_Lightning | string | No | |
MEB_LightningHeight | real | No | |
MEB_MagneticAOEBase | real | No | |
MEB_MagneticAOEPerLevel | real | No | |
MEB_MagneticStrengthBase | real | No | |
MEB_MagneticStrengthPerLevel | real | No | |
MEB_ManaDamageBase | real | No | |
MEB_ManaDamagePerLevel | real | No | |
MEB_ManaToHealthDamageBase | real | No | |
MEB_ManaToHealthDamagePerLevel | real | No | |
MEB_RockSmash | real | No | |
MEB_SFXDeath | string | No | |
MEB_SFXKnockback | string | No | |
MEB_SFXSpawn | string | No | |
MEB_SidesBase | integer | No | |
MEB_SidesPerLevel | integer | No | |
MEB_Speed | real | No | |
MEB_Spell | abilcode | No | |
MEB_StartDistance | real | No | |
MEB_Tail | unitcode | No | |
MEB_TailDurationBase | real | No | |
MEB_TailDurationPerLevel | real | No | |
MEB_TempGroup | group | No | |
MEB_TempI | integer | No | |
MEB_TempLightning | lightning | No | |
MEB_TempPoint | location | No | |
MEB_TempPoint2 | location | No | |
MEB_TempPoint3 | location | No | |
MEB_TempReal | real | No | |
MEB_TempReal2 | real | No | |
MEB_TempU | unit | No | |
MEB_TempX | real | No | |
MEB_TempY | real | No | |
MEB_TempZ | real | No | |
MEB_TempZ2 | real | No | |
MEB_TreeChecker | unit | No | |
MEB_TreeDestroyArea | real | No | |
MEB_TreeKill | boolean | No | |
MEB_U | unit | No | |
MEB_UHandle | integer | No | |
MEB_UHandleC | integer | No | |
MPS_ACTIVE_EVENT | real | No | |
MPS_ACTIVE_NODE | integer | No | |
MPS_AmmoNumber | integer | No | |
MPS_AmmoType | integer | Yes | |
MPS_Loc | location | No | |
MPS_MapMaxX | real | No | |
MPS_MapMaxY | real | No | |
MPS_MapMinX | real | No | |
MPS_MapMinY | real | No | |
MPS_MASTER_CRASH | real | No | |
MPS_MASTER_CREATE | real | No | |
MPS_MASTER_HIT | real | No | |
MPS_MASTER_UPDATE | real | No | |
MPS_MasterNode | integer | Yes | |
MPS_NO_EVENT | real | No | |
MPS_Projectile | unit | Yes | |
MPS_ProjectileAcceleration | real | Yes | |
MPS_ProjectileAnimation | integer | Yes | |
MPS_ProjectileAOE | real | Yes | |
MPS_ProjectileAttackType | attacktype | Yes | |
MPS_ProjectileCounter | integer | No | |
MPS_ProjectileCurrentEffect | effect | Yes | |
MPS_ProjectileDamageType | damagetype | Yes | |
MPS_ProjectileDeathModel | string | Yes | |
MPS_ProjectileHealthDamage | real | Yes | |
MPS_ProjectileHeight | real | Yes | |
MPS_ProjectileLastNode | integer | No | |
MPS_ProjectileLauncher | unit | Yes | |
MPS_ProjectileManaDamage | real | Yes | |
MPS_ProjectileModel | string | Yes | |
MPS_ProjectileModelScale | real | Yes | |
MPS_ProjectileName | string | Yes | |
MPS_ProjectileNextNode | integer | Yes | |
MPS_ProjectileNodeNumber | integer | No | |
MPS_ProjectilePlayer | player | Yes | |
MPS_ProjectilePrevNode | integer | Yes | |
MPS_ProjectileRecyclableNodes | integer | No | |
MPS_ProjectileRecycleNodes | integer | Yes | |
MPS_ProjectileRemoveTimer | real | Yes | |
MPS_ProjectileStageID | integer | Yes | |
MPS_ProjectileTargetAimOffset | real | Yes | |
MPS_ProjectileTargetUnit | unit | Yes | |
MPS_ProjectileTimer | timer | No | |
MPS_ProjectileTurnEfficiency | real | Yes | |
MPS_ProjectileTurnRate | real | Yes | |
MPS_ProjectileX | real | Yes | |
MPS_ProjectileY | real | Yes | |
MPS_Slave | unit | Yes | |
MPS_SLAVE_CREATE | real | No | |
MPS_SLAVE_DEATH | real | No | |
MPS_SLAVE_UPDATE | real | No | |
MPS_SlaveAngle | real | Yes | |
MPS_SlaveAOE | real | Yes | |
MPS_SlaveAttackType | attacktype | Yes | |
MPS_SlaveCounter | integer | No | |
MPS_SlaveCurrentEffect | effect | Yes | |
MPS_SlaveCurrentOffset | real | Yes | |
MPS_SlaveDamageType | damagetype | Yes | |
MPS_SlaveDeathModel | string | Yes | |
MPS_SlaveHealthDamage | real | Yes | |
MPS_SlaveLastNode | integer | No | |
MPS_SlaveManaDamage | real | Yes | |
MPS_SlaveModel | string | Yes | |
MPS_SlaveModelScale | real | Yes | |
MPS_SlaveName | string | Yes | |
MPS_SlaveNextNode | integer | Yes | |
MPS_SlaveNodeNumber | integer | No | |
MPS_SlaveNumber | integer | No | |
MPS_SlaveOffset | real | Yes | |
MPS_SlavePrevNode | integer | Yes | |
MPS_SlavePull | real | Yes | |
MPS_SlaveRecyclableNodes | integer | No | |
MPS_SlaveRecycleNodes | integer | Yes | |
MPS_SlaveSpin | real | Yes | |
MPS_SlaveType | integer | Yes | |
MPS_SlaveVel | real | Yes | |
MPS_TargetX | real | Yes | |
MPS_TargetY | real | Yes | |
MPS_TargetZ | real | Yes | |
MPS_TempGroup | group | No | |
MPS_XVel | real | Yes | |
MPS_YVel | real | Yes | |
MPS_ZVel | real | Yes | |
MS_Ability | abilcode | No | |
MS_AbilityLvl | integer | Yes | |
MS_AbilityStun | abilcode | No | |
MS_AoE | real | No | |
MS_AttackType | attacktype | No | |
MS_Blue | real | No | |
MS_Caster | unit | Yes | |
MS_Counter_SFX | real | Yes | |
MS_CurrentHeight | real | No | |
MS_Damage | real | Yes | |
MS_DamageType | damagetype | No | |
MS_DestroyTreeAoE | real | No | |
MS_DestroyTrees | boolean | No | |
MS_DistanceTraveled | real | Yes | |
MS_Dummy | unitcode | No | |
MS_DummyCaster | unit | No | |
MS_FallRate_XY | real | No | |
MS_FallRate_Z | real | No | |
MS_FallTime | real | No | |
MS_Green | real | No | |
MS_KBAoE | real | No | |
MS_KBDistance | real | No | |
MS_KBTime | real | No | |
MS_LandAoE | real | No | |
MS_LandingDamage | real | No | |
MS_LoopInt | integervar | No | |
MS_M_SpawnDistance | real | No | |
MS_M_SpawnHeight | real | No | |
MS_MaxIndex | integer | No | |
MS_MaxLevel | integer | No | |
MS_Meteor_SFX | effect | Yes | |
MS_MeteorDummy | unit | Yes | |
MS_MeteorLoc | location | No | |
MS_MeteorSize | real | No | |
MS_MoveRate | real | Yes | |
MS_NodeNext | integer | Yes | |
MS_NodePrev | integer | Yes | |
MS_Owner | player | Yes | |
MS_PeriodicTimer | real | No | |
MS_RecycledSize | integer | No | |
MS_RecycledStack | integer | Yes | |
MS_Red | real | No | |
MS_RollDirection | real | Yes | |
MS_RollDistance | real | Yes | |
MS_RollTime | real | Yes | |
MS_SFX_FallFreq | real | No | |
MS_SFX_RollFreq | real | Yes | |
MS_SFXDeath | string | No | |
MS_SFXFall | string | No | |
MS_SFXKB | string | No | |
MS_SFXLand | string | No | |
MS_SFXMeteor | string | No | |
MS_SFXRoll | string | No | |
MS_Size | real | No | |
MS_Spell_ID | integer | No | |
MS_SpellCount | integer | No | |
MS_Stage | integer | Yes | |
MS_StunAoE | real | No | |
MS_TargetLoc | location | Yes | |
MS_TempDest | destructable | No | |
MS_TempHeight | real | No | |
MS_TempInt | integervar | No | |
MS_TempLoc | location | No | |
MS_TempReal | real | No | |
MS_TempUnit | unit | No | |
MS_TreeKiller | unit | No | |
orderid | string | No | |
point1 | location | No | |
point2 | location | No | |
ProjectileSpeed | real | No | |
Radians_QuarterPi | real | No | |
Radians_QuarterTurn | real | No | |
Radians_Turn | real | No | |
RevealWarning | string | No | You will be revealed to your opponents unless you build a town-hall type structure |
RS_Animation_Speed | real | No | |
RS_Attack_Type | attacktype | No | |
RS_Caster | unit | Yes | |
RS_Current_Index | integer | No | |
RS_Damage | real | Yes | |
RS_Damage_Type | damagetype | No | |
RS_Effect | string | Yes | |
RS_Index | integer | Yes | |
RS_Index_Size | integer | No | |
RS_Level | integer | No | |
RS_Loop | integervar | No | |
RS_Max_Index | integer | No | |
RS_Slashes | integer | Yes | |
RS_Target | unit | Yes | |
RS_Transparency | real | No | |
RS_Weapon_Effect | effect | Yes | |
Rsla_Ability | abilcode | No | |
Rsla_Angle | real | Yes | |
Rsla_AttackType | attacktype | No | |
Rsla_Caster | unit | Yes | |
Rsla_Counter | integer | Yes | |
Rsla_DamageType | damagetype | No | |
Rsla_Distance | real | Yes | |
Rsla_Harvester | unit | No | |
Rsla_Index | integervar | No | |
Rsla_Level | integer | Yes | |
Rsla_MaxIndex | integer | No | |
Rsla_MoveSpeed | real | Yes | |
Rsla_SlashAnimation | string | No | |
Rsla_SlashAnimSpeed | real | No | |
Rsla_SlashDamage | real | Yes | |
Rsla_SlashEffect | string | No | |
Rsla_SlashTimes | integer | Yes | |
Rsla_Target | unit | Yes | |
Rsla_TempLoc | location | No | |
Rsla_TempLoc2 | location | No | |
Rsla_TempLoc3 | location | No | |
Rsla_Tree | destructable | No | |
sfx | string | No | |
Spell__Ability | abilcode | No | |
Spell__Caster | unit | No | |
Spell__CasterOwner | player | No | |
Spell__CastPoint | location | No | |
Spell__Channeling | boolean | No | |
Spell__Completed | boolean | No | |
Spell__DummyOwner | player | No | |
Spell__DummyType | unitcode | No | |
Spell__Duration | real | No | |
Spell__DurationPerLevel | real | No | |
Spell__Expired | boolean | No | |
Spell__Filter_AllowAlly | boolean | No | |
Spell__Filter_AllowDead | boolean | No | |
Spell__Filter_AllowEnemy | boolean | No | |
Spell__Filter_AllowFlying | boolean | No | |
Spell__Filter_AllowHero | boolean | No | |
Spell__Filter_AllowLiving | boolean | No | |
Spell__Filter_AllowMagicImmune | boolean | No | |
Spell__Filter_AllowMechanical | boolean | No | |
Spell__Filter_AllowNonHero | boolean | No | |
Spell__Filter_AllowStructure | boolean | No | |
Spell__Hash | hashtable | No | |
Spell__Index | integer | No | |
Spell__InRange | real | No | |
Spell__InRangeCount | integer | No | |
Spell__InRangeGroup | group | No | |
Spell__InRangePoint | location | No | |
Spell__InRangeUnits | unit | Yes | |
Spell__Interval | real | No | |
Spell__Level | integer | No | |
Spell__LevelMultiplier | real | No | |
Spell__Running | boolean | No | |
Spell__StartDuration | boolean | No | |
Spell__Target | unit | No | |
Spell__TargetGroup | group | No | |
Spell__TargetPoint | location | No | |
Spell__Time | real | No | |
Spell__Trigger_OnCast | trigger | No | |
Spell__Trigger_OnChannel | trigger | No | |
Spell__Trigger_OnEffect | trigger | No | |
Spell__Trigger_OnFinish | trigger | No | |
Spell__Trigger_OnLoop | trigger | No | |
Spell__UseTargetGroup | boolean | No | |
Spell__WakeTargets | boolean | No | |
Spell_i_AllowAlly | boolean | Yes | |
Spell_i_AllowDead | boolean | Yes | |
Spell_i_AllowEnemy | boolean | Yes | |
Spell_i_AllowFlying | boolean | Yes | |
Spell_i_AllowHero | boolean | Yes | |
Spell_i_AllowLiving | boolean | Yes | |
Spell_i_AllowMagicImmune | boolean | Yes | |
Spell_i_AllowMechanical | boolean | Yes | |
Spell_i_AllowNonHero | boolean | Yes | |
Spell_i_AllowStructure | boolean | Yes | |
Spell_i_Caster | unit | Yes | |
Spell_i_Channeling | boolean | Yes | |
Spell_i_Completed | boolean | Yes | |
Spell_i_Duration | real | Yes | |
Spell_i_EventType | integer | Yes | |
Spell_i_GroupN | integer | No | |
Spell_i_GroupStack | group | Yes | |
Spell_i_Head | integer | Yes | |
Spell_i_Instances | integer | No | |
Spell_i_LastTime | real | Yes | |
Spell_i_Level | integer | Yes | |
Spell_i_Linked | boolean | Yes | |
Spell_i_OnCastStack | trigger | Yes | |
Spell_i_OnChannelStack | trigger | Yes | |
Spell_i_OnEffectStack | trigger | Yes | |
Spell_i_OnFinishStack | trigger | Yes | |
Spell_i_OnLoopStack | trigger | Yes | |
Spell_i_PreloadDummy | unit | No | |
Spell_i_Recycle | integer | No | |
Spell_i_RecycleList | integer | Yes | |
Spell_i_Stack | integer | Yes | |
Spell_i_StackN | integer | No | |
Spell_i_StackRef | integer | Yes | |
Spell_i_Target | unit | Yes | |
Spell_i_TargetGroup | group | Yes | |
Spell_i_TargetX | real | Yes | |
Spell_i_TargetY | real | Yes | |
Spell_i_Time | real | Yes | |
Spell_i_Timer | timer | No | |
Spell_i_UseTG | boolean | Yes | |
SpinSpeed | real | No | |
SpreadSpeed | real | No | |
Star_Loop | integervar | No | |
Star_Loop_2 | integervar | No | |
StarSegmentAOEDamageBase | real | No | |
StarSegmentAOEDamagePerlevel | real | No | |
StarSidesBase | integer | No | |
StarSidesPerLevel | integer | No | |
StarSize | real | No | |
stormgroup | group | No | |
target | unit | No | |
Temp_Distance | real | No | |
Temp_Group | group | No | |
Temp_Point | location | No | |
Temp_Point2 | location | No | |
Temp_Point_2 | location | No | |
Temp_Point_3 | location | No | |
Temp_Point_4 | location | No | |
TempGroup | group | No | |
TempPoint | location | No | |
TempPoint2 | location | No | |
timer | real | No | |
u | unit | No | |
UDex | integer | No | |
UDexGen | integer | No | |
UDexNext | integer | Yes | |
UDexPrev | integer | Yes | |
UDexRecycle | integer | No | |
UDexUnits | unit | Yes | |
UDexWasted | integer | No | |
UHandle | integer | No | |
UnitIndexerEnabled | boolean | No | |
UnitIndexEvent | real | No | |
unitsfx | string | No | |
voodohash | hashtable | No | |
voodoobreakdamage | real | Yes | |
voodooburnpercent | real | Yes | |
voodoodps | real | Yes | |
voodoodrain1111 | abilcode | No | A01C |
voodooduration | real | Yes | |
voodoogroup | group | No | |
X | real | Yes | |
Y | real | Yes |
////////////////////////////////////////////////////////////////////
// Boss Ultimate Spellpack Channel V1.01 //
// Author: Tank-Commander //
// Purpose: Handles spell channelling within the spellpack //
// Used for: Soul Release, Scathe, Sheer Force, Energy Spike //
// //
// Notes: //
// - Read the readme before you try modifying the config //
// - Use the "Helpful files" to help you import the system //
// //
// Credits: //
// - (Dummy.mdl) Vexorian //
// //
// If you have used this spellpack in your map, you are required //
// to give credits to Tank-Commander for the creation of it //
// If you would like to use snippets of code from this for //
// whatever, getting permission and crediting the source/linking //
// would be much appreciated. //
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// README: //
// Before modifying this spell a few things need to be //
// understood and read, this is one of those things, while //
// most modification can be considered intuitive, it still //
// helps to read through these intstructions, as they will //
// inform you about how to configure this spell to your //
// desire. //
//----------------------------------------------------------------//
// Initial importing: The variable creator trigger can be //
// imported first and if you have the correct settings (file, //
// preferences, General, automatically create unknown variables //
// checked, then when you paste in the variable creator it //
// will automatically give you all the variables you need for //
// this spell //
// //
// While the remaining object editor based data is not required //
// to function (provided they're replaced with equivelents) //
// it's recommended that they are also imported, if their data //
// value are not the same as listed in the configuration, those //
// configurables will need to be changed to work correctly //
//----------------------------------------------------------------//
// CONFIGURABLE INFORMATION/HELP: //
// //
// - Viewing data values: To see data values in the editor you //
// need to press Ctrl + D, to shift back to normal viewing //
// press it again //
// //
// - Effects: Pathnames for effects used in the spells should //
// have two "\"s throughout or the effect will not work (the //
// WE progress bar will not go away when saving, however if //
// fixed afterwards the save will still work, but the progress //
// bar will still remain until the WE is closed) //
// e.g. "units\\human\\Footman\\Footman" //
// //
// - Effect Scaling: Some effects have scale values below them //
// the scale determines the size of the effect and is expressed //
// as a real percentage (1.00 = 100%) //
// //
// - Removing Effects: to remove an effect you don't want from //
// the ability, set the model path to that of Dummy.mdl //
// //
// - Timer: Some configurables have PerSecond values, the code //
// automatically accounts for changes to the timer as to //
// maintain consistency with what the user has chosen //
// All times in the system are expressions of seconds //
// //
//----------------------------------------------------------------//
// TimerSpeed: This is the amount of time in seconds between //
// each iteration of the channel loop function //
constant function BUSCR_TimerSpeed takes nothing returns real
return 0.031250000
endfunction
//----------------------------------------------------------------//
// DummyId: This is the raw data value of the dummy unit used //
// for creating the channeling effects it's advised this unit //
// uses Dummy.mdl for optimal usage, have death type set to //
// "can't raise does not decay" and a death time long enough //
// to play all effects (about 5.00 should be long enough) for //
// all effects) //
constant function BUSCR_DummyId takes nothing returns integer
return 'u002'
endfunction
//----------------------------------------------------------------//
// AttachmentPoint: This is the location on the dummy unit where //
// effects will be placed //
constant function BUSCR_AttachmentPoint takes nothing returns string
return "origin"
endfunction
//----------------------------------------------------------------//
// GroundMinAngle: This is the minimum angle off the floor that //
// all effects are made when the caster is a ground unit //
constant function BUSCR_GroundMinAngle takes nothing returns real
return 25.
endfunction
//----------------------------------------------------------------//
// DummyPlayer: This is the player that is given ownership of //
// all the dummy units used by the system //
constant function BUSCR_DummyPlayer takes nothing returns player
return Player(14)
endfunction
//----------------------------------------------------------------//
// END OF CONFIGURATION //
//----------------------------------------------------------------//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// RegisterChannel: This is the function used to register a new //
// type of channel (calling this function after setting up the //
// new channel will register it and allowit to be used) //
////////////////////////////////////////////////////////////////////
function BUS_RegisterChannel takes integer target returns nothing
local integer Id
if (target == 0) then
set udg_BUSCR_Counter = udg_BUSCR_Counter + 1
set Id = udg_BUSCR_Counter
else
set Id = target
endif
set udg_BUSCR_Name[Id] = StringCase(udg_BUSCR_Name[0], true)
set udg_BUSCR_Effect[Id] = udg_BUSCR_Effect[0]
set udg_BUSCR_MinAOE[Id] = udg_BUSCR_MinAOE[0]
set udg_BUSCR_MaxAOE[Id] = udg_BUSCR_MaxAOE[0]
set udg_BUSCR_AbsorbAOE[Id] = udg_BUSCR_AbsorbAOE[0]
set udg_BUSCR_MinSize[Id] = udg_BUSCR_MinSize[0]
set udg_BUSCR_MaxSize[Id] = udg_BUSCR_MaxSize[0]
set udg_BUSCR_SpawnRate[Id] = udg_BUSCR_SpawnRate[0]
set udg_BUSCR_SpawnCount[Id] = udg_BUSCR_SpawnCount[0]
set udg_BUSCR_Power[Id] = udg_BUSCR_Power[0]
set udg_BUSCR_HueRed[Id] = udg_BUSCR_HueRed[0]
set udg_BUSCR_HueGreen[Id] = udg_BUSCR_HueGreen[0]
set udg_BUSCR_HueBlue[Id] = udg_BUSCR_HueBlue[0]
set udg_BUSCR_HueAlpha[Id] = udg_BUSCR_HueAlpha[0]
set udg_BUSCR_HueSpeed[Id] = udg_BUSCR_HueSpeed[0]
endfunction
////////////////////////////////////////////////////////////////////
// GetChannelByName: This returns the Id number of the channel //
// which shares the name with the passed parameter, it can be //
// used to consistently refer to a channel without knowing the //
// order by which it was declared (allowing dynamic introduction //
// of channels //
////////////////////////////////////////////////////////////////////
function BUS_GetChannelByName takes string name returns integer
local integer iLoop = 0
set name = StringCase(name, true)
loop
set iLoop = iLoop + 1
exitwhen iLoop > udg_BUSCR_Counter
if (name == udg_BUSCR_Name[iLoop]) then
return iLoop
endif
endloop
return 0
endfunction
////////////////////////////////////////////////////////////////////
// GetZ: Used to get the Z height of a given location, used to //
// make sure that entities going over cliffs aren't incorrectly //
// moved/placed on the z plane //
////////////////////////////////////////////////////////////////////
function BUS_GetZ takes real x, real y returns real
call MoveLocation(udg_BUS_Loc, x, y)
return GetLocationZ(udg_BUS_Loc)
endfunction
////////////////////////////////////////////////////////////////////
// Function used to prevent two casts of the same channel being //
// done simultaneously //
////////////////////////////////////////////////////////////////////
function BUS_CheckChannel takes unit u returns integer
local integer Node = 0
local integer iLoop = 0
loop
set iLoop = iLoop + 1
set Node = udg_BUSC_NextNode[Node]
exitwhen (udg_BUSC_Unit[Node] == u)
if (Node == udg_BUSC_LastNode) then
return 0
endif
endloop
return Node
endfunction
////////////////////////////////////////////////////////////////////
// ChannelLoop: The function used to control the channel this //
// includes creating entities and moving them toward the caster //
// checking if they are still casting the channel and activating //
// the channel effects when it is completed //
////////////////////////////////////////////////////////////////////
function BUS_ChannelLoop takes nothing returns nothing
local integer Node = 0
local integer TempNode = 0
local integer iLoop = 0
local integer iLoop2 = 0
local integer EffectCount = 0
local real x
local real x2
local real x3
local real y
local real y2
local real y3
local real z
local real z2
local real dy
local real dx
local real Angle
local real Angle2
local real Distance
local real TempReal
loop
set iLoop2 = iLoop2 + 1
exitwhen iLoop2 > udg_BUSC_PCount
set TempNode = udg_BUSC_PNextNode[TempNode]
endloop
loop
set iLoop = iLoop + 1
exitwhen iLoop > udg_BUSC_CCount
set Node = udg_BUSC_NextNode[Node]
set x = GetUnitX(udg_BUSC_Unit[Node])
set y = GetUnitY(udg_BUSC_Unit[Node])
set z = BUS_GetZ(x, y) + GetUnitFlyHeight(udg_BUSC_Unit[Node])
set TempNode = 0
if (udg_BUSC_CDuration[Node] > 0) then
set udg_BUSC_CDuration[Node] = udg_BUSC_CDuration[Node] - BUSCR_TimerSpeed()
if (udg_BUSC_CDelay[Node] <= BUSCR_TimerSpeed()) then
set udg_BUSC_CDelay[Node] = udg_BUSC_Delay[Node]
set iLoop2 = 0
loop
set iLoop2 = iLoop2 + 1
exitwhen iLoop2 > udg_BUSCR_SpawnCount[udg_BUSC_ChannelId[Node]]
if (udg_BUSC_PRecyclableNodes == 0) then
set udg_BUSC_PNodeNumber = udg_BUSC_PNodeNumber + 1
set TempNode = udg_BUSC_PNodeNumber
else
set udg_BUSC_PRecyclableNodes = udg_BUSC_PRecyclableNodes - 1
set TempNode = udg_BUSC_PRecycleNodes[udg_BUSC_PRecyclableNodes]
endif
set udg_BUSC_PNextNode[TempNode] = 0
set udg_BUSC_PNextNode[udg_BUSC_PLastNode] = TempNode
set udg_BUSC_PPrevNode[TempNode] = udg_BUSC_PLastNode
set udg_BUSC_PLastNode = TempNode
set udg_BUSC_PCount = udg_BUSC_PCount + 1
set Angle = GetRandomReal(0, 360)
if (IsUnitType(udg_BUSC_Unit[Node], UNIT_TYPE_GROUND)) then
set Angle2 = GetRandomReal(BUSCR_GroundMinAngle(), 90)
else
set Angle2 = GetRandomReal(0, 180)
endif
set TempReal = GetRandomReal(udg_BUSCR_MinAOE[udg_BUSC_ChannelId[Node]], udg_BUSCR_MaxAOE[udg_BUSC_ChannelId[Node]])
set Distance = Cos(Angle2) * TempReal
if (Distance < 0) then
set Distance = Distance * -1
endif
set x2 = x + Distance * Cos(Angle * bj_DEGTORAD)
set y2 = y + Distance * Sin(Angle * bj_DEGTORAD)
set z2 = Sin(Angle2) * TempReal + z
set TempReal = GetRandomReal(udg_BUSCR_MinSize[udg_BUSC_ChannelId[Node]], udg_BUSCR_MaxSize[udg_BUSC_ChannelId[Node]])
set udg_BUSC_PCaster[TempNode] = udg_BUSC_Unit[Node]
set udg_BUSC_PXVelocity[TempNode] = 0
set udg_BUSC_PYVelocity[TempNode] = 0
set udg_BUSC_PZVelocity[TempNode] = 0
set udg_BUSC_PCurrentZ[TempNode] = z2
set udg_BUSC_PUnit[TempNode] = CreateUnit(BUSCR_DummyPlayer(), BUSCR_DummyId(), x2, y2, Angle + 180)
if UnitAddAbility(udg_BUSC_PUnit[TempNode], 'Amrf') and UnitRemoveAbility(udg_BUSC_PUnit[TempNode], 'Amrf') then
endif
set udg_BUSC_PCurrentEffect[TempNode] = AddSpecialEffectTarget(udg_BUSCR_Effect[udg_BUSC_ChannelId[Node]], udg_BUSC_PUnit[TempNode], BUSCR_AttachmentPoint())
call SetUnitScale(udg_BUSC_PUnit[TempNode], TempReal, 0.00, 0.00)
call SetUnitFlyHeight(udg_BUSC_PUnit[TempNode], udg_BUSC_PCurrentZ[TempNode] - BUS_GetZ(x2,y2), 0.00)
endloop
else
set udg_BUSC_CDelay[Node] = udg_BUSC_CDelay[Node] - BUSCR_TimerSpeed()
endif
if (udg_BUSC_HueChange[Node]) then
set udg_BUSC_CHueRed[Node] = udg_BUSC_CHueRed[Node] + udg_BUSC_HueChangeRed[Node]
set udg_BUSC_CHueGreen[Node] = udg_BUSC_CHueGreen[Node] + udg_BUSC_HueChangeGreen[Node]
set udg_BUSC_CHueBlue[Node] = udg_BUSC_CHueBlue[Node] + udg_BUSC_HueChangeBlue[Node]
set udg_BUSC_CHueAlpha[Node] = udg_BUSC_CHueAlpha[Node] + udg_BUSC_HueChangeAlpha[Node]
call SetUnitVertexColor(udg_BUSC_Unit[Node], udg_BUSC_CHueRed[Node], udg_BUSC_CHueGreen[Node], udg_BUSC_CHueBlue[Node], udg_BUSC_CHueAlpha[Node])
if (udg_BUSC_CChangeHueDelay[Node] < 0) then
set udg_BUSC_CChangeHueDelay[Node] = udg_BUSCR_HueSpeed[udg_BUSC_ChannelId[Node]]
set udg_BUSC_HueChangeRed[Node] = udg_BUSC_HueChangeRed[Node] * -1
set udg_BUSC_HueChangeGreen[Node] = udg_BUSC_HueChangeGreen[Node] * -1
set udg_BUSC_HueChangeBlue[Node] = udg_BUSC_HueChangeBlue[Node] * -1
set udg_BUSC_HueChangeAlpha[Node] = udg_BUSC_HueChangeAlpha[Node] * - 1
else
set udg_BUSC_CChangeHueDelay[Node] = udg_BUSC_CChangeHueDelay[Node] - BUSCR_TimerSpeed()
endif
endif
elseif (udg_BUSC_Running[Node]) then
set udg_BUS_Unit = udg_BUSC_Unit[Node]
set udg_BUS_Target = udg_BUSC_Target[Node]
set udg_BUS_X = udg_BUSC_TargetX[Node]
set udg_BUS_Y = udg_BUSC_TargetY[Node]
set udg_BUSC_Running[Node] = false
set udg_BUSC_Event = 0
set udg_BUSC_Event = udg_BUSC_Ability[Node]
endif
set TempNode = 0
set iLoop2 = 0
set EffectCount = 0
loop
set iLoop2 = iLoop2 + 1
exitwhen iLoop2 > udg_BUSC_PCount
set TempNode = udg_BUSC_PNextNode[TempNode]
if (udg_BUSC_PCaster[TempNode] == udg_BUSC_Unit[Node]) then
set x2 = GetUnitX(udg_BUSC_PUnit[TempNode])
set y2 = GetUnitY(udg_BUSC_PUnit[TempNode])
set z2 = BUS_GetZ(x2, y2) + GetUnitFlyHeight(udg_BUSC_PUnit[TempNode])
set Distance = SquareRoot((x - x2) * (x - x2) + (y - y2) * (y - y2) + (z - z2) * (z - z2))
if ((Distance < udg_BUSCR_AbsorbAOE[udg_BUSC_ChannelId[Node]]) or (not(GetUnitCurrentOrder(udg_BUSC_Unit[Node]) == udg_BUSC_Order[Node]) or udg_BUSC_Cancel[Node])) then
call DestroyEffect(udg_BUSC_PCurrentEffect[TempNode])
call KillUnit(udg_BUSC_PUnit[TempNode])
if (udg_BUSC_PLastNode == TempNode) then
set udg_BUSC_PLastNode = udg_BUSC_PPrevNode[TempNode]
endif
set udg_BUSC_PRecycleNodes[udg_BUSC_PRecyclableNodes] = TempNode
set udg_BUSC_PRecyclableNodes = udg_BUSC_PRecyclableNodes + 1
set udg_BUSC_PNextNode[udg_BUSC_PPrevNode[TempNode]] = udg_BUSC_PNextNode[TempNode]
set udg_BUSC_PPrevNode[udg_BUSC_PNextNode[TempNode]] = udg_BUSC_PPrevNode[TempNode]
set udg_BUSC_PCount = udg_BUSC_PCount - 1
set iLoop2 = iLoop2 - 1
if (udg_BUSC_PCount + udg_BUSC_CCount == 0) then
call PauseTimer(udg_BUSC_Timer)
endif
else
set EffectCount = EffectCount + 1
set dy = y - y2
set dx = x - x2
set Angle = Atan2(dy, dx)
set Angle2 = Atan2(z - z2, SquareRoot((dx * dx) + (dy * dy)))
set TempReal = udg_BUSCR_Power[udg_BUSC_ChannelId[Node]] / Distance
set udg_BUSC_PZVelocity[TempNode] = udg_BUSC_PZVelocity[TempNode] + TempReal * Sin(Angle2)
set udg_BUSC_PXVelocity[TempNode] = udg_BUSC_PXVelocity[TempNode] + TempReal * Cos(Angle) * Cos(Angle2)
set udg_BUSC_PYVelocity[TempNode] = udg_BUSC_PYVelocity[TempNode] + TempReal * Sin(Angle) * Cos(Angle2)
set udg_BUSC_PCurrentZ[TempNode] = udg_BUSC_PCurrentZ[TempNode] + udg_BUSC_PZVelocity[TempNode]
set x3 = x2 + udg_BUSC_PXVelocity[TempNode]
set y3 = y2 + udg_BUSC_PYVelocity[TempNode]
if ((udg_BUS_MapMinX <= x3) and (x3 <= udg_BUS_MapMaxX) and (udg_BUS_MapMinY <= y3)and (y3 <= udg_BUS_MapMaxY)) then
call SetUnitX(udg_BUSC_PUnit[TempNode], x3)
call SetUnitY(udg_BUSC_PUnit[TempNode], y3)
endif
call SetUnitFlyHeight(udg_BUSC_PUnit[TempNode], udg_BUSC_PCurrentZ[TempNode] - BUS_GetZ(x3,y3), 0.00)
call SetUnitAnimationByIndex(udg_BUSC_PUnit[TempNode], R2I(Atan2(udg_BUSC_PZVelocity[TempNode], SquareRoot((udg_BUSC_PXVelocity[TempNode] * udg_BUSC_PXVelocity[TempNode]) + (udg_BUSC_PYVelocity[TempNode] * udg_BUSC_PYVelocity[TempNode]))) * bj_RADTODEG + 0.5) + 90)
endif
endif
endloop
if (EffectCount == 0) and ((udg_BUSC_CDuration[Node] <= 0) or not(GetUnitCurrentOrder(udg_BUSC_Unit[Node]) == udg_BUSC_Order[Node] or udg_BUSC_Cancel[Node])) then
if (udg_BUSC_HueChange[Node]) then
call SetUnitVertexColor(udg_BUSC_Unit[Node], 255, 255, 255, 255)
endif
if (udg_BUSC_LastNode == Node) then
set udg_BUSC_LastNode = udg_BUSC_PrevNode[Node]
endif
set udg_BUSC_RecycleNodes[udg_BUSC_RecyclableNodes] = Node
set udg_BUSC_RecyclableNodes = udg_BUSC_RecyclableNodes + 1
set udg_BUSC_NextNode[udg_BUSC_PrevNode[Node]] = udg_BUSC_NextNode[Node]
set udg_BUSC_PrevNode[udg_BUSC_NextNode[Node]] = udg_BUSC_PrevNode[Node]
set udg_BUSC_CCount = udg_BUSC_CCount - 1
set iLoop = iLoop - 1
if (udg_BUSC_PCount + udg_BUSC_CCount == 0) then
call PauseTimer(udg_BUSC_Timer)
endif
endif
endloop
endfunction
////////////////////////////////////////////////////////////////////
// StartChannel: Used to start a channeling effect on a spell //
// Calling this function, passing the ability Id, the unit, any //
// target unit or point, the duration of the channel and the //
// duration of the channel (as well as if the channel will //
// include a hue change) //
////////////////////////////////////////////////////////////////////
function BUS_StartChannel takes integer Id, unit u, unit Target, real x, real y, real Duration, real Event, boolean Hue returns nothing
local integer Node = 0
local real TempReal = 0
set udg_BUSC_Cancel[BUS_CheckChannel(u)] = true
if (udg_BUSC_RecyclableNodes == 0) then
set udg_BUSC_NodeNumber = udg_BUSC_NodeNumber + 1
set Node = udg_BUSC_NodeNumber
else
set udg_BUSC_RecyclableNodes = udg_BUSC_RecyclableNodes - 1
set Node = udg_BUSC_RecycleNodes[udg_BUSC_RecyclableNodes]
endif
set udg_BUSC_NextNode[Node] = 0
set udg_BUSC_NextNode[udg_BUSC_LastNode] = Node
set udg_BUSC_PrevNode[Node] = udg_BUSC_LastNode
set udg_BUSC_LastNode = Node
set udg_BUSC_CCount = udg_BUSC_CCount + 1
set udg_BUSC_ChannelId[Node] = Id
set udg_BUSC_Ability[Node] = Event
set udg_BUSC_Unit[Node] = u
set udg_BUSC_Target[Node] = Target
set udg_BUSC_TargetX[Node] = x
set udg_BUSC_TargetY[Node] = y
set udg_BUSC_Order[Node] = GetUnitCurrentOrder(u)
set udg_BUSC_Cancel[Node] = false
set udg_BUSC_Running[Node] = true
set udg_BUSC_CDuration[Node] = Duration
set udg_BUSC_Delay[Node] = 1. / udg_BUSCR_SpawnRate[Id]
set udg_BUSC_CDelay[Node] = udg_BUSC_Delay[Node]
set udg_BUSC_HueChange[Node] = Hue
set udg_BUSC_CHueRed[Node] = 255
set udg_BUSC_CHueGreen[Node] = 255
set udg_BUSC_CHueBlue[Node] = 255
set udg_BUSC_CHueAlpha[Node] = 255
set TempReal = (1 / udg_BUSCR_HueSpeed[Id]) * BUSCR_TimerSpeed()
set udg_BUSC_HueChangeRed[Node] = R2I((udg_BUSCR_HueRed[Id] - udg_BUSC_CHueRed[Node]) * TempReal)
set udg_BUSC_HueChangeGreen[Node] = R2I((udg_BUSCR_HueGreen[Id] - udg_BUSC_CHueGreen[Node]) * TempReal)
set udg_BUSC_HueChangeBlue[Node] = R2I((udg_BUSCR_HueBlue[Id] - udg_BUSC_CHueBlue[Node]) * TempReal)
set udg_BUSC_HueChangeAlpha[Node] = R2I((udg_BUSCR_HueAlpha[Id] - udg_BUSC_CHueAlpha[Node]) * TempReal)
set udg_BUSC_CChangeHueDelay[Node] = udg_BUSCR_HueSpeed[Id]
if (udg_BUSC_CCount + udg_BUSC_PCount == 1) then
call TimerStart(udg_BUSC_Timer, BUSCR_TimerSpeed(), true, function BUS_ChannelLoop)
endif
endfunction
////////////////////////////////////////////////////////////////////
// InitTrig BUS Channel: Sets up the map bounds and the location //
// used for getting Z locations and the timer used to run the //
// loop //
////////////////////////////////////////////////////////////////////
function InitTrig_BUS_Channel takes nothing returns nothing
set udg_BUS_Loc = Location(0,0)
set udg_BUSC_Timer = CreateTimer()
set udg_BUS_MapMaxX = GetRectMaxX(bj_mapInitialPlayableArea)
set udg_BUS_MapMinX = GetRectMinX(bj_mapInitialPlayableArea)
set udg_BUS_MapMaxY = GetRectMaxY(bj_mapInitialPlayableArea)
set udg_BUS_MapMinY = GetRectMinY(bj_mapInitialPlayableArea)
endfunction
////////////////////////////////////////////////////////////////////
// End of the system //
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// MASTER PROJECTILE SYSTEM V1.02 //
// Author: Tank-Commander //
// Requires: Dummy.mdl //
// Purpose: Create complex and attractive projectiles //
// //
// Notes: //
// - Read the readme before you try modifying the config //
// - Use the "Helpful files" to help you import the spell //
// //
// Credits: //
// - (Dummy.mdl) Vexorian //
// //
// If you have used this system in your map, you are required //
// to give credits to Tank-Commander for the creation of it //
// If you would like to use snippets of code from this for //
// whatever, getting permission and crediting the source/linking //
// would be much appreciated. //
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// README: //
// Before modifying this system a few things need to be //
// understood and read, this is one of those things, while //
// most modification can be considered intuitive, it still //
// helps to read through these instructions, as they will //
// inform you about how to configure this system to your //
// desire. //
//----------------------------------------------------------------//
constant function MPS_ProjectileTimerSpeed takes nothing returns real
return 0.031250000
endfunction
//----------------------------------------------------------------//
// DummyID: This is the data value of the unit that serves as //
// the dummy, it should have Dummy.mdl set to its model have //
// locust as its ability, movement type float (or fly) and 0 //
// pitch and roll angle for optimal use //
constant function MPS_ProjectileDummyID takes nothing returns integer
return 'u002'
endfunction
//----------------------------------------------------------------//
// AttachmentPoint: This is the location on the Dummy unit that //
// Master and Slave projectiles will have their effects placed //
constant function MPS_ProjectileAttachmentPoint takes nothing returns string
return "origin"
endfunction
//----------------------------------------------------------------//
// DummyPlayer: This is the player who will own all dummy units //
// created by this ability, by default this is Player(14) //
constant function MPS_DummyPlayer takes nothing returns player
return Player(14)
endfunction
//----------------------------------------------------------------//
// HeightLet: This is how far off the ground a projectile can be //
// while still being considered to be in the ground (can prevent //
// odd changes in arc when hitting the ground) //
constant function MPS_HeightLet takes nothing returns real
return 3.00
endfunction
//----------------------------------------------------------------//
// Gravity: This is how fast projectiles are pulled back into //
// the ground //
constant function MPS_Gravity takes nothing returns real
return 0.3065
endfunction
//----------------------------------------------------------------//
// -READ ONLY-READ ONLY-READ ONLY-READ ONLY-READ ONLY-READONLY- //
constant function MPS_ProjectileStageID takes nothing returns integer
return 1
endfunction
//----------------------------------------------------------------//
constant function MPS_ProjectileRecycleStageID takes nothing returns integer
return 2
endfunction
//----------------------------------------------------------------//
// END OF CONFIGURATION //
//----------------------------------------------------------------//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function used for registering new ammo types into the system //
// call this function after setting up a new ammo type will //
// allow it to be used as an ammo type for spells/turrets/etc. //
////////////////////////////////////////////////////////////////////
function MPS_RegisterAmmo takes integer RegisterNumber returns nothing
local integer Id
if (RegisterNumber == 0) then
set udg_MPS_AmmoNumber = ( udg_MPS_AmmoNumber + 1 )
set Id = udg_MPS_AmmoNumber
else
set Id = RegisterNumber
endif
set udg_MPS_ProjectileName[Id] = StringCase(udg_MPS_ProjectileName[0], true)
set udg_MPS_ProjectileModel[Id] = udg_MPS_ProjectileModel[0]
set udg_MPS_ProjectileDeathModel[Id] = udg_MPS_ProjectileDeathModel[0]
set udg_MPS_ProjectileModelScale[Id] = udg_MPS_ProjectileModelScale[0]
set udg_MPS_ProjectileAOE[Id] = udg_MPS_ProjectileAOE[0]
set udg_MPS_ProjectileHealthDamage[Id] = udg_MPS_ProjectileHealthDamage[0]
set udg_MPS_ProjectileManaDamage[Id] = udg_MPS_ProjectileManaDamage[0]
set udg_MPS_ProjectileAttackType[Id] = udg_MPS_ProjectileAttackType[0]
set udg_MPS_ProjectileDamageType[Id] = udg_MPS_ProjectileDamageType[0]
set udg_MPS_ProjectileAcceleration[Id] = udg_MPS_ProjectileAcceleration[0]
set udg_MPS_ProjectileTurnRate[Id] = udg_MPS_ProjectileTurnRate[0]
set udg_MPS_ProjectileTurnEfficiency[Id] = udg_MPS_ProjectileTurnEfficiency[0]
set udg_MPS_ProjectileTargetAimOffset[Id] = udg_MPS_ProjectileTargetAimOffset[0]
endfunction
////////////////////////////////////////////////////////////////////
// This function returns the Id number of the ammunition //
// which shares the name with the passed parameter, it can be //
// used to consistently refer to ammunition without knowing the //
// order by which it was declared (allowing dynamic introduction //
// of ammunition types //
////////////////////////////////////////////////////////////////////
function MPS_GetAmmoByName takes string name returns integer
local integer iLoop = 0
set name = StringCase(name, true)
loop
set iLoop = iLoop + 1
exitwhen iLoop > udg_MPS_AmmoNumber
if (name == udg_MPS_ProjectileName[iLoop]) then
return iLoop
endif
endloop
return 0
endfunction
////////////////////////////////////////////////////////////////////
// Function used for registering new slave types into the system //
// call this function after setting up a new slave type will //
// allow it to be used as an slave type for spells/turrets/etc. //
////////////////////////////////////////////////////////////////////
function MPS_RegisterSlave takes integer RegisterNumber returns nothing
local integer Id
if (RegisterNumber == 0) then
set udg_MPS_SlaveNumber = ( udg_MPS_SlaveNumber + 1 )
set Id = udg_MPS_SlaveNumber
else
set Id = RegisterNumber
endif
set udg_MPS_SlaveName[Id] = StringCase(udg_MPS_SlaveName[0], true)
set udg_MPS_SlaveModel[Id] = udg_MPS_SlaveModel[0]
set udg_MPS_SlaveDeathModel[Id] = udg_MPS_SlaveDeathModel[0]
set udg_MPS_SlaveModelScale[Id] = udg_MPS_SlaveModelScale[0]
set udg_MPS_SlaveAOE[Id] = udg_MPS_SlaveAOE[0]
set udg_MPS_SlaveHealthDamage[Id] = udg_MPS_SlaveHealthDamage[0]
set udg_MPS_SlaveManaDamage[Id] = udg_MPS_SlaveManaDamage[0]
set udg_MPS_SlaveAttackType[Id] = udg_MPS_SlaveAttackType[0]
set udg_MPS_SlaveDamageType[Id] = udg_MPS_SlaveDamageType[0]
set udg_MPS_SlaveOffset[Id] = udg_MPS_SlaveOffset[0]
set udg_MPS_SlavePull[Id] = udg_MPS_SlavePull[0]
set udg_MPS_SlaveSpin[Id] = udg_MPS_SlaveSpin[0]
endfunction
////////////////////////////////////////////////////////////////////
// This function returns the Id number of the slave //
// which shares the name with the passed parameter, it can be //
// used to consistently refer to a slave without knowing the //
// order by which it was declared (allowing dynamic introduction //
// of slave types //
////////////////////////////////////////////////////////////////////
function MPS_GetSlaveByName takes string name returns integer
local integer iLoop = 0
set name = StringCase(name, true)
loop
set iLoop = iLoop + 1
exitwhen iLoop > udg_MPS_SlaveNumber
if (name == udg_MPS_SlaveName[iLoop]) then
return iLoop
endif
endloop
return iLoop
endfunction
////////////////////////////////////////////////////////////////////
// Function used to get the z height of locations needed by the //
// spell, since it can only be done with locations, this one //
// is reused throughout, instead of creating/destroying them //
////////////////////////////////////////////////////////////////////
function MPS_GetZ takes real x, real y returns real
//Gets the location Z of the selected location
call MoveLocation(udg_MPS_Loc, x, y)
return GetLocationZ(udg_MPS_Loc)
endfunction
////////////////////////////////////////////////////////////////////
// Function used to make sure that the location is within the //
// map bounds so that units cannot be moved outside of it and //
// get permanently stuck //
////////////////////////////////////////////////////////////////////
function MPS_ValidateLocation takes real x, real y returns boolean
//Check if the point is within the map bounds
return (x < udg_MPS_MapMaxX) and (x > udg_MPS_MapMinX) and (y < udg_MPS_MapMaxY) and (y > udg_MPS_MapMinY)
endfunction
////////////////////////////////////////////////////////////////////
// Function used to identify what units are valid damaging //
// targets for a given projectile //
////////////////////////////////////////////////////////////////////
function MPS_ValidateTarget takes unit u, integer Node returns boolean
//Checks if the passed unit can be used as a valid target for damage
return ((IsUnitEnemy(u, udg_MPS_ProjectilePlayer[Node])) and (GetUnitTypeId(u) != MPS_ProjectileDummyID()) and not(IsUnitType(u, UNIT_TYPE_DEAD) or GetUnitTypeId(u) == 0))
endfunction
////////////////////////////////////////////////////////////////////
// Function used to update event listeners //
////////////////////////////////////////////////////////////////////
function MPS_FireEvent takes real EventID returns nothing
set udg_MPS_ACTIVE_EVENT = EventID
set udg_MPS_ACTIVE_EVENT = udg_MPS_NO_EVENT
endfunction
////////////////////////////////////////////////////////////////////
// Function used to recycle instances, so that they can used //
// again later, keeping the total array sizes smaller //
////////////////////////////////////////////////////////////////////
function MPS_ProjectileRecycle takes integer Node returns nothing
if (udg_MPS_ProjectileLastNode == Node) then
set udg_MPS_ProjectileLastNode = udg_MPS_ProjectilePrevNode[Node]
endif
//Recycles the node
set udg_MPS_ProjectileRecycleNodes[udg_MPS_ProjectileRecyclableNodes] = Node
set udg_MPS_ProjectileRecyclableNodes = udg_MPS_ProjectileRecyclableNodes + 1
set udg_MPS_ProjectileNextNode[udg_MPS_ProjectilePrevNode[Node]] = udg_MPS_ProjectileNextNode[Node]
set udg_MPS_ProjectilePrevNode[udg_MPS_ProjectileNextNode[Node]] = udg_MPS_ProjectilePrevNode[Node]
set udg_MPS_ProjectileCounter = udg_MPS_ProjectileCounter - 1
//Stops the timer if this is the only remaining Node
if (udg_MPS_ProjectileCounter == 0) then
call PauseTimer(udg_MPS_ProjectileTimer)
endif
endfunction
////////////////////////////////////////////////////////////////////
// Function used to create new Nodes for the system whenever a //
// unit or effect is added to run in the loop function //
////////////////////////////////////////////////////////////////////
function MPS_ProjectileCreateNode takes nothing returns integer
//set up local
local integer Node = 0
//Checking for recycleable Nodes
if (udg_MPS_ProjectileRecyclableNodes == 0) then
set udg_MPS_ProjectileNodeNumber = udg_MPS_ProjectileNodeNumber + 1
set Node = udg_MPS_ProjectileNodeNumber
else
set udg_MPS_ProjectileRecyclableNodes = udg_MPS_ProjectileRecyclableNodes - 1
set Node = udg_MPS_ProjectileRecycleNodes[udg_MPS_ProjectileRecyclableNodes]
endif
//Sets up this Node
set udg_MPS_ProjectileNextNode[Node] = 0
set udg_MPS_ProjectileNextNode[udg_MPS_ProjectileLastNode] = Node
set udg_MPS_ProjectilePrevNode[Node] = udg_MPS_ProjectileLastNode
set udg_MPS_ProjectileLastNode = Node
set udg_MPS_ProjectileCounter = udg_MPS_ProjectileCounter + 1
return Node
endfunction
///////////////////////////////////////////////////////////////////
// Function used to recycle instances, so that they can used //
// again later, keeping the total array sizes smaller //
////////////////////////////////////////////////////////////////////
function MPS_SlaveRecycle takes integer Node returns nothing
if (udg_MPS_SlaveLastNode == Node) then
set udg_MPS_SlaveLastNode = udg_MPS_SlavePrevNode[Node]
endif
//Recycles the node
set udg_MPS_SlaveRecycleNodes[udg_MPS_SlaveRecyclableNodes] = Node
set udg_MPS_SlaveRecyclableNodes = udg_MPS_SlaveRecyclableNodes + 1
set udg_MPS_SlaveNextNode[udg_MPS_SlavePrevNode[Node]] = udg_MPS_SlaveNextNode[Node]
set udg_MPS_SlavePrevNode[udg_MPS_SlaveNextNode[Node]] = udg_MPS_SlavePrevNode[Node]
set udg_MPS_SlaveCounter = udg_MPS_SlaveCounter - 1
endfunction
////////////////////////////////////////////////////////////////////
// Function used to create new Nodes for the system whenever a //
// unit or effect is added to run in the loop function //
////////////////////////////////////////////////////////////////////
function MPS_SlaveCreateNode takes nothing returns integer
//set up local
local integer Node = 0
//Checking for recycleable Nodes
if (udg_MPS_SlaveRecyclableNodes == 0) then
set udg_MPS_SlaveNodeNumber = udg_MPS_SlaveNodeNumber + 1
set Node = udg_MPS_SlaveNodeNumber
else
set udg_MPS_SlaveRecyclableNodes = udg_MPS_SlaveRecyclableNodes - 1
set Node = udg_MPS_SlaveRecycleNodes[udg_MPS_SlaveRecyclableNodes]
endif
//Sets up this Node
set udg_MPS_SlaveNextNode[Node] = 0
set udg_MPS_SlaveNextNode[udg_MPS_SlaveLastNode] = Node
set udg_MPS_SlavePrevNode[Node] = udg_MPS_SlaveLastNode
set udg_MPS_SlaveLastNode = Node
set udg_MPS_SlaveCounter = udg_MPS_SlaveCounter + 1
return Node
endfunction
////////////////////////////////////////////////////////////////////
// Function used to move all projectile-type entities in the //
// abiity - the physics engine of the spell //
////////////////////////////////////////////////////////////////////
function MPS_Move takes integer Node returns boolean
//set up locals
local real dy = udg_MPS_TargetY[Node] - udg_MPS_ProjectileY[Node]
local real dx = udg_MPS_TargetX[Node]- udg_MPS_ProjectileX[Node]
local real x
local real y
local real Angle = Atan2(dy, dx)
local real Angle2 = Atan2((MPS_GetZ(udg_MPS_TargetX[Node], udg_MPS_TargetY[Node]) + udg_MPS_TargetZ[Node]) - (MPS_GetZ(udg_MPS_ProjectileX[Node], udg_MPS_ProjectileY[Node]) + GetUnitFlyHeight(udg_MPS_Projectile[Node])), Pow(dx * dx + dy * dy, 0.5))
local real Angle3 = Atan2(udg_MPS_YVel[Node], udg_MPS_XVel[Node])
local real Angle4 = Atan(udg_MPS_ZVel[Node])
local real TempReal = Pow((udg_MPS_ZVel[Node] * udg_MPS_ZVel[Node]) + (udg_MPS_XVel[Node] * udg_MPS_XVel[Node]) + (udg_MPS_YVel[Node] * udg_MPS_YVel[Node]), 0.5) * udg_MPS_ProjectileTurnEfficiency[udg_MPS_AmmoType[Node]]
local real TempReal2 = 1/(1 + udg_MPS_ProjectileTurnEfficiency[udg_MPS_AmmoType[Node]])
//Calculate new velocities
set udg_MPS_ZVel[Node] = ((udg_MPS_ZVel[Node] + (TempReal + udg_MPS_ProjectileTurnRate[udg_MPS_AmmoType[Node]]) * Sin(Angle2)) * udg_MPS_ProjectileAcceleration[udg_MPS_AmmoType[Node]]) * TempReal2
set udg_MPS_XVel[Node] = ((udg_MPS_XVel[Node] + (TempReal + udg_MPS_ProjectileTurnRate[udg_MPS_AmmoType[Node]]) * Cos(Angle) * Cos(Angle2)) * udg_MPS_ProjectileAcceleration[udg_MPS_AmmoType[Node]]) * TempReal2
set udg_MPS_YVel[Node] = ((udg_MPS_YVel[Node] + (TempReal + udg_MPS_ProjectileTurnRate[udg_MPS_AmmoType[Node]]) * Sin(Angle) * Cos(Angle2)) * udg_MPS_ProjectileAcceleration[udg_MPS_AmmoType[Node]]) * TempReal2
set udg_MPS_ProjectileHeight[Node] = udg_MPS_ProjectileHeight[Node] + udg_MPS_ZVel[Node] - MPS_Gravity()
set x = udg_MPS_ProjectileX[Node] + udg_MPS_XVel[Node]
set y = udg_MPS_ProjectileY[Node] + udg_MPS_YVel[Node]
//Make sure the location is within the map bounds
if MPS_ValidateLocation(x, y) then
set udg_MPS_ProjectileX[Node] = x
set udg_MPS_ProjectileY[Node] = y
call SetUnitX(udg_MPS_Projectile[Node], x)
call SetUnitY(udg_MPS_Projectile[Node], y)
endif
//Update target unit information if applicable
if not(udg_MPS_ProjectileTargetUnit[Node] == null) then
set udg_MPS_TargetX[Node] = GetUnitX(udg_MPS_ProjectileTargetUnit[Node])
set udg_MPS_TargetY[Node] = GetUnitY(udg_MPS_ProjectileTargetUnit[Node])
set udg_MPS_TargetZ[Node] = GetUnitFlyHeight(udg_MPS_ProjectileTargetUnit[Node]) + udg_MPS_ProjectileTargetAimOffset[udg_MPS_AmmoType[Node]]
endif
//Apply visuals
call SetUnitFlyHeight(udg_MPS_Projectile[Node], udg_MPS_ProjectileHeight[Node] - MPS_GetZ(x, y), 0.)
call SetUnitFacing(udg_MPS_Projectile[Node], bj_RADTODEG * Atan2(udg_MPS_YVel[Node], udg_MPS_XVel[Node]))
set udg_MPS_ProjectileAnimation[Node] = R2I(Atan2((udg_MPS_ZVel[Node]), Pow((udg_MPS_XVel[Node] * udg_MPS_XVel[Node]) + (udg_MPS_YVel[Node] * udg_MPS_YVel[Node]), 0.5) * bj_RADTODEG + 0.5)) + 70
call SetUnitAnimationByIndex(udg_MPS_Projectile[Node], udg_MPS_ProjectileAnimation[Node])
//Check if the unit has crashed into the ground
if (GetUnitFlyHeight(udg_MPS_Projectile[Node]) <= MPS_HeightLet()) then
call MPS_FireEvent(udg_MPS_MASTER_CRASH)
return true
endif
call MPS_FireEvent(udg_MPS_MASTER_UPDATE)
return false
endfunction
////////////////////////////////////////////////////////////////////
// Function used to identify when a projectile has hit its //
// target unit so that damage can be dealt & stun can be //
// applied if applicable //
////////////////////////////////////////////////////////////////////
function MPS_HitTarget takes integer Node returns boolean
//Set up locals
local real dx = udg_MPS_ProjectileX[Node] - udg_MPS_TargetX[Node]
local real dy = udg_MPS_ProjectileY[Node] - udg_MPS_TargetY[Node]
local real dz = (MPS_GetZ(udg_MPS_ProjectileX[Node], udg_MPS_ProjectileY[Node]) + GetUnitFlyHeight(udg_MPS_Projectile[Node])) - (MPS_GetZ(udg_MPS_TargetX[Node], udg_MPS_TargetY[Node]) + GetUnitFlyHeight(udg_MPS_ProjectileTargetUnit[Node]))
//Measure distance between the Unit and its Target and return if it's close enough
if (dx * dx + dy * dy + dz * dz <= udg_MPS_ProjectileAOE[udg_MPS_AmmoType[Node]] * udg_MPS_ProjectileAOE[udg_MPS_AmmoType[Node]]) then
call MPS_FireEvent(udg_MPS_MASTER_HIT)
return true
endif
return false
endfunction
////////////////////////////////////////////////////////////////////
// Function used to damage all valid units within the impact //
// area of the projectile once it has crashed or hit the target //
////////////////////////////////////////////////////////////////////
function MPS_ProjectileDamageArea takes integer Node returns nothing
//Set up locals
local unit u
local real x
local real y
local real z = GetUnitFlyHeight(udg_MPS_Projectile[Node])
local real dx
local real dy
local real dz
//Get units in range
call GroupEnumUnitsInRange(udg_MPS_TempGroup, udg_MPS_ProjectileX[Node], udg_MPS_ProjectileY[Node], udg_MPS_ProjectileAOE[udg_MPS_AmmoType[Node]], null)
loop
set u = FirstOfGroup(udg_MPS_TempGroup)
exitwhen (u == null)
set x = GetUnitX(u)
set y = GetUnitY(u)
set dx = udg_MPS_ProjectileX[Node] - x
set dy = udg_MPS_ProjectileY[Node] - y
set dz = (MPS_GetZ(udg_MPS_ProjectileX[Node], udg_MPS_ProjectileY[Node]) + z) - (MPS_GetZ(x, y) + GetUnitFlyHeight(u))
//Check if they are close enough and are valid as a damage target
if (dx * dx + dy * dy + dz * dz <= udg_MPS_ProjectileAOE[udg_MPS_AmmoType[Node]] * udg_MPS_ProjectileAOE[udg_MPS_AmmoType[Node]]) and (MPS_ValidateTarget(u, Node)) then
//Apply Damage
call UnitDamageTarget(udg_MPS_ProjectileLauncher[Node], u, udg_MPS_ProjectileHealthDamage[udg_MPS_AmmoType[Node]], false, false, udg_MPS_ProjectileAttackType[udg_MPS_AmmoType[Node]], udg_MPS_ProjectileDamageType[udg_MPS_AmmoType[Node]], null)
call SetUnitState(u, UNIT_STATE_MANA, GetUnitState(u, UNIT_STATE_MANA) - udg_MPS_ProjectileManaDamage[udg_MPS_AmmoType[Node]])
endif
call GroupRemoveUnit(udg_MPS_TempGroup, u)
endloop
endfunction
////////////////////////////////////////////////////////////////////
// Function used to keep all the Slave projectiles attached //
// to their masters, runs once at the end of the loop to keep //
// system efficiency up //
////////////////////////////////////////////////////////////////////
function MPS_UpdateSlaveProjectiles takes nothing returns nothing
//Set up locals
local integer TempInt = 0
local integer Node = 0
local real x
local real y
local real z
local real x2
local real y2
local real Incline
local real facing
local real correction
local real dx
local real dy
local real dz
local unit u
loop
set TempInt = TempInt + 1
exitwhen (TempInt > udg_MPS_SlaveCounter)
set Node = udg_MPS_SlaveNextNode[Node]
set udg_MPS_ACTIVE_NODE = Node
//Find the incline of the Orbit and position on the Orbit
set Incline = Atan2(udg_MPS_ZVel[udg_MPS_MasterNode[Node]] * udg_MPS_ZVel[udg_MPS_MasterNode[Node]], udg_MPS_XVel[udg_MPS_MasterNode[Node]] * udg_MPS_XVel[udg_MPS_MasterNode[Node]] + udg_MPS_YVel[udg_MPS_MasterNode[Node]] * udg_MPS_YVel[udg_MPS_MasterNode[Node]]) + 1.570800
set udg_MPS_SlaveAngle[Node] = udg_MPS_SlaveAngle[Node] + udg_MPS_SlaveSpin[udg_MPS_SlaveType[Node]]
set facing = GetUnitFacing(udg_MPS_Projectile[udg_MPS_MasterNode[Node]]) * bj_DEGTORAD
//Apply Pull in correct direction
if (udg_MPS_SlaveCurrentOffset[Node] > 0.) then
set udg_MPS_SlaveVel[Node] = udg_MPS_SlaveVel[Node] - udg_MPS_SlavePull[udg_MPS_SlaveType[Node]]
set correction = udg_MPS_SlaveAngle[Node]
else
set udg_MPS_SlaveVel[Node] = udg_MPS_SlaveVel[Node] + udg_MPS_SlavePull[udg_MPS_SlaveType[Node]]
set correction = udg_MPS_SlaveAngle[Node] * - 1
endif
//Find new location
set udg_MPS_SlaveCurrentOffset[Node] = udg_MPS_SlaveCurrentOffset[Node] + udg_MPS_SlaveVel[Node]
set x = udg_MPS_ProjectileX[udg_MPS_MasterNode[Node]] + (udg_MPS_SlaveCurrentOffset[Node] * Cos(correction))
set y = udg_MPS_ProjectileY[udg_MPS_MasterNode[Node]] + (udg_MPS_SlaveCurrentOffset[Node] * Sin(correction))
set z = udg_MPS_ProjectileHeight[udg_MPS_MasterNode[Node]] + (udg_MPS_SlaveCurrentOffset[Node] * Sin(Incline) * Cos(facing) * Cos(correction)) + (MPS_GetZ(x, y) - MPS_GetZ(udg_MPS_ProjectileX[udg_MPS_MasterNode[Node]], udg_MPS_ProjectileY[udg_MPS_MasterNode[Node]])) - MPS_GetZ(x, y)
//Apply new location
call SetUnitX(udg_MPS_Slave[Node], x)
call SetUnitY(udg_MPS_Slave[Node], y)
call SetUnitFlyHeight(udg_MPS_Slave[Node], z, 0.)
call SetUnitAnimationByIndex(udg_MPS_Slave[Node], udg_MPS_ProjectileAnimation[udg_MPS_MasterNode[Node]])
call SetUnitFacing(udg_MPS_Slave[Node], GetUnitFacing(udg_MPS_Projectile[udg_MPS_MasterNode[Node]]))
if (udg_MPS_ProjectileStageID[udg_MPS_MasterNode[Node]] == MPS_ProjectileRecycleStageID() or z <= MPS_HeightLet()) then
//Slave killed
call MPS_FireEvent(udg_MPS_SLAVE_DEATH)
//Destroy effects on crash or Master death
call DestroyEffect(udg_MPS_SlaveCurrentEffect[Node])
call DestroyEffect(AddSpecialEffectTarget(udg_MPS_SlaveDeathModel[udg_MPS_SlaveType[Node]], udg_MPS_Slave[Node], MPS_ProjectileAttachmentPoint()))
//Select units to damage
call GroupEnumUnitsInRange(udg_MPS_TempGroup, x, y, udg_MPS_SlaveAOE[udg_MPS_SlaveType[Node]], null)
loop
set u = FirstOfGroup(udg_MPS_TempGroup)
exitwhen (u == null)
set x2 = GetUnitX(u)
set y2 = GetUnitY(u)
set dx = x - x2
set dy = y - y2
set dz = (MPS_GetZ(x, y) + z) - (MPS_GetZ(x2, y2) + GetUnitFlyHeight(u))
//Check they are within range and are a valid target
if (dx * dx + dy * dy + dz * dz <= udg_MPS_SlaveAOE[udg_MPS_SlaveType[Node]] * udg_MPS_SlaveAOE[udg_MPS_SlaveType[Node]]) and (MPS_ValidateTarget(u, udg_MPS_MasterNode[Node])) then
//Deal Damage
call UnitDamageTarget(udg_MPS_ProjectileLauncher[udg_MPS_MasterNode[Node]], u, udg_MPS_SlaveHealthDamage[udg_MPS_SlaveType[Node]], false, false, udg_MPS_SlaveAttackType[udg_MPS_SlaveType[Node]], udg_MPS_SlaveDamageType[udg_MPS_SlaveType[Node]], null)
call SetUnitState(u, UNIT_STATE_MANA, GetUnitState(u, UNIT_STATE_MANA) - udg_MPS_SlaveManaDamage[udg_MPS_SlaveType[Node]])
endif
call GroupRemoveUnit(udg_MPS_TempGroup, u)
endloop
//Start Recycling
call KillUnit(udg_MPS_Slave[Node])
call MPS_SlaveRecycle(Node)
set TempInt = TempInt - 1
else
call MPS_FireEvent(udg_MPS_SLAVE_UPDATE)
endif
endloop
endfunction
////////////////////////////////////////////////////////////////////
// The main function which is used to handle the control of all //
// of the projectiles handled by the system //
////////////////////////////////////////////////////////////////////
function MPS_ProjectileLoop takes nothing returns nothing
//Sets up locals
local integer Node = 0
local integer TempInt = 0
loop
set TempInt = TempInt + 1
exitwhen TempInt > udg_MPS_ProjectileCounter
set Node = udg_MPS_ProjectileNextNode[Node]
set udg_MPS_ACTIVE_NODE = Node
//Projectiles
if (udg_MPS_ProjectileStageID[Node] == MPS_ProjectileStageID()) then
//Move the projectile
if (MPS_Move(Node)) or (MPS_HitTarget(Node)) then
//Destroy on crash
call DestroyEffect(udg_MPS_ProjectileCurrentEffect[Node])
call DestroyEffect(AddSpecialEffectTarget(udg_MPS_ProjectileDeathModel[udg_MPS_AmmoType[Node]], udg_MPS_Projectile[Node], MPS_ProjectileAttachmentPoint()))
//Deal Damage
call MPS_ProjectileDamageArea(Node)
//Start Recycling
set udg_MPS_ProjectileStageID[Node] = MPS_ProjectileRecycleStageID()
endif
//Recycling
else
//Remove and Recycle Unit
call KillUnit(udg_MPS_Projectile[Node])
call MPS_ProjectileRecycle(Node)
set TempInt = TempInt - 1
endif
endloop
//If you're not using the slave projectile system remove these lines of Code
//************************************************************************
if (udg_MPS_SlaveCounter > 0) then
call MPS_UpdateSlaveProjectiles()
endif
//************************************************************************
endfunction
///////////////////////////////////////////////////////////////////
// Function used to add Slave Projectiles to their Masters //
// only needs to know the Node number of the Master, what //
// Slave Ammo to use and how much of it to make //
///////////////////////////////////////////////////////////////////
function MPS_AddSlaveProjectiles takes integer Master, integer Ammo, integer Amount returns nothing
//Set up locals
local integer iLoop = 0
local integer Node
local real Angle = 0
local real Increment
//Make sure there's at least one to put on before dividing
if (Amount > 0) then
set Increment = 2 * bj_PI / Amount
//Create projectiles
loop
set iLoop = iLoop + 1
exitwhen (iLoop > Amount)
//Set up Slave Data
set Angle = Angle + Increment
set Node = MPS_SlaveCreateNode()
set udg_MPS_SlaveAngle[Node] = Angle
set udg_MPS_SlaveCurrentOffset[Node] = udg_MPS_SlaveOffset[Ammo]
set udg_MPS_SlaveVel[Node] = 0
set udg_MPS_MasterNode[Node] = Master
set udg_MPS_SlaveType[Node] = Ammo
//Create Slave Projectile and Apply Aesthetics
set udg_MPS_Slave[Node] = CreateUnit(MPS_DummyPlayer(), MPS_ProjectileDummyID(), udg_MPS_ProjectileX[Master], udg_MPS_ProjectileY[Master], GetUnitFacing(udg_MPS_Projectile[Master]))
set udg_MPS_SlaveCurrentEffect[Node] = AddSpecialEffectTarget(udg_MPS_SlaveModel[Ammo], udg_MPS_Slave[Node], MPS_ProjectileAttachmentPoint())
if UnitAddAbility(udg_MPS_Slave[Node], 'Amrf') and UnitRemoveAbility(udg_MPS_Slave[Node], 'Amrf') then
endif
call SetUnitScale(udg_MPS_Slave[Node], udg_MPS_SlaveModelScale[Ammo], 0., 0.)
call SetUnitFlyHeight(udg_MPS_Slave[Node], GetUnitFlyHeight(udg_MPS_Projectile[Master]), 0.)
call PauseUnit(udg_MPS_Slave[Node], true)
//Fire create event
set udg_MPS_ACTIVE_NODE = Node
call MPS_FireEvent(udg_MPS_SLAVE_CREATE)
endloop
endif
endfunction
////////////////////////////////////////////////////////////////////
// Function used to create the projectiles in the system, it //
// must be given an Ammo type, strength of launch, the angles //
// for the launch (Pitch and Angle), starting co-ordinates //
// and a target (if a unit is passed as a target then target //
// X and Y need not be passed (pass a value of 0 for both) //
////////////////////////////////////////////////////////////////////
function MPS_CreateProjectile takes unit u, integer Ammo, real Power, real Pitch, real Angle, real x, real y, real z, unit Target, real TargetX, real TargetY returns integer
local integer Node = MPS_ProjectileCreateNode()
//Setup up Master Projectile Data
set udg_MPS_AmmoType[Node] = Ammo
set udg_MPS_ProjectileX[Node] = x
set udg_MPS_ProjectileY[Node] = y
set udg_MPS_TargetX[Node] = TargetX
set udg_MPS_TargetY[Node] = TargetY
set udg_MPS_ZVel[Node] = Power * Sin(Pitch)
set udg_MPS_XVel[Node] = Power * Cos(Angle) * Cos(Pitch)
set udg_MPS_YVel[Node] = Power * Sin(Angle) * Cos(Pitch)
set udg_MPS_ProjectileHeight[Node] = z + MPS_GetZ(x, y)
set udg_MPS_ProjectileStageID[Node] = MPS_ProjectileStageID()
set udg_MPS_ProjectileTargetUnit[Node] = Target
set udg_MPS_ProjectileLauncher[Node] = u
set udg_MPS_ProjectilePlayer[Node] = GetTriggerPlayer()
//Check if it has a target
if not(Target == null) then
set udg_MPS_TargetZ[Node] = GetUnitFlyHeight(udg_MPS_ProjectileTargetUnit[Node]) + udg_MPS_ProjectileTargetAimOffset[udg_MPS_AmmoType[Node]]
else
set udg_MPS_TargetZ[Node] = 0.
endif
//Create Projectile and Apply Aesthetics
set udg_MPS_Projectile[Node] = CreateUnit(MPS_DummyPlayer(), MPS_ProjectileDummyID(), x, y, Angle * bj_RADTODEG)
if UnitAddAbility(udg_MPS_Projectile[Node], 'Amrf') and UnitRemoveAbility(udg_MPS_Projectile[Node], 'Amrf') then
endif
set udg_MPS_ProjectileCurrentEffect[Node] = AddSpecialEffectTarget(udg_MPS_ProjectileModel[Ammo], udg_MPS_Projectile[Node], MPS_ProjectileAttachmentPoint())
call SetUnitScale(udg_MPS_Projectile[Node], udg_MPS_ProjectileModelScale[Ammo], 0., 0.)
call SetUnitFlyHeight(udg_MPS_Projectile[Node], z, 0.)
call PauseUnit(udg_MPS_Projectile[Node], true)
//Fire create event
set udg_MPS_ACTIVE_NODE = Node
call MPS_FireEvent(udg_MPS_MASTER_CREATE)
//Start Timer
if udg_MPS_ProjectileCounter == 1 then
call TimerStart(udg_MPS_ProjectileTimer, MPS_ProjectileTimerSpeed(), true, function MPS_ProjectileLoop)
endif
//Pass back node number for Slave projectiles
return Node
endfunction
////////////////////////////////////////////////////////////////////
// Initialisation trigger, applies the conditions to triggers //
// and sets up the global location used to get location Z's //
// as well as the map bounds and event variable values //
////////////////////////////////////////////////////////////////////
function InitTrig_Master_Projectile_System takes nothing returns nothing
//Set up the location used to find Z heights
set udg_MPS_Loc = Location(0,0)
//Set up the Timer used to run the loop
set udg_MPS_ProjectileTimer = CreateTimer()
//Set up event variables
set udg_MPS_NO_EVENT = 0.
set udg_MPS_MASTER_CREATE = 1.
set udg_MPS_MASTER_UPDATE = 2.
set udg_MPS_MASTER_CRASH = 3.
set udg_MPS_MASTER_HIT = 4.
set udg_MPS_SLAVE_CREATE = 5.
set udg_MPS_SLAVE_UPDATE = 6.
set udg_MPS_SLAVE_DEATH = 7.
//Set up Amount of active slaves and ammo
set udg_MPS_AmmoNumber = 0
set udg_MPS_SlaveNumber = 0
//Sets up the variables used to make sure a point is within the map area
set udg_MPS_MapMaxX = GetRectMaxX(bj_mapInitialPlayableArea)
set udg_MPS_MapMinX = GetRectMinX(bj_mapInitialPlayableArea)
set udg_MPS_MapMaxY = GetRectMaxY(bj_mapInitialPlayableArea)
set udg_MPS_MapMinY = GetRectMinY(bj_mapInitialPlayableArea)
endfunction
////////////////////////////////////////////////////////////////////
// End of the system //
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// ARCANE BARRAGE V1.01 //
// Author: Tank-Commander //
// Purpose: A powerful keepaway ability for forcing enemies //
// to retreat //
// Requires: BUS Channel (Boss Ultimates Spellpack) //
// Master Projectile System //
// - Both created by Tank-Commander //
// //
// Notes: //
// - Read the readme before you try modifying the config //
// - Use the "Helpful files" to help you import the system //
// //
// Credits: //
// - (Dummy.mdl) Vexorian //
// - (Darkness_Bomb.mdl) nGy //
// //
// If you have used this spellpack in your map, you are required //
// to give credits to Tank-Commander for the creation of it //
// If you would like to use snippets of code from this for //
// whatever, getting permission and crediting the source/linking //
// would be much appreciated. //
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// README: //
// Before modifying this spell a few things need to be //
// understood and read, this is one of those things, while //
// most modification can be considered intuitive, it still //
// helps to read through these intstructions, as they will //
// inform you about how to configure this spell to your //
// desire. //
//----------------------------------------------------------------//
// Initial importing: The variable creator trigger can be //
// imported first and if you have the correct settings (file, //
// preferences, General, automatically create unknown variables //
// checked, then when you paste in the variable creator it //
// will automatically give you all the variables you need for //
// this spell //
// //
// While the remaining object editor based data is not required //
// to function (provided they're replaced with equivelents) //
// it's recommended that they are also imported, if their data //
// value are not the same as listed in the configuration, those //
// configurables will need to be changed to work correctly //
//----------------------------------------------------------------//
// MISC //
//----------------------------------------------------------------//
// TimerSpeed: the time in seconds between each iteration of //
// the main loop function (default is 0.031250000) it's //
// recommended you leave it like that //
constant function AB_TimerSpeed takes nothing returns real
return 0.031250000
endfunction
//----------------------------------------------------------------//
// Event: This is the number used to differentiate it from //
// other channel abilities - make sure this does not conflict //
// with any other BUS Channel-using abilities //
constant function AB_Event takes nothing returns integer
return 5
endfunction
//----------------------------------------------------------------//
// Ability: This is the data value of the ability used as the //
// base, make sure it is based off channel (to view raw data //
// press ctrl + d, pressing again switches back) //
constant function AB_Ability takes nothing returns integer
return 'A010'
endfunction
//----------------------------------------------------------------//
// MaxLevel: This is the maximum level of the ability - this //
// ensures that a projectile is registered for each level of //
// the ability
constant function AB_MaxLevel takes nothing returns integer
return 1
endfunction
//----------------------------------------------------------------//
// CHANNEL //
//----------------------------------------------------------------//
// ChannelType: This is the name of the channel, multiple //
// abilities can use the same channel
constant function AB_ChannelType takes nothing returns string
return "ArcaneBarrage"
endfunction
//----------------------------------------------------------------//
// Duration: This is how long the channel period for the spell //
// lasts for (in seconds) //
constant function AB_ChannelDurationBase takes nothing returns real
return 2.
endfunction
// //
constant function AB_ChannelDurationPerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// Effect: This is the filepath of the effect used for the //
// channel //
constant function AB_ChannelEffect takes nothing returns string
return "Abilities\\Spells\\Other\\BlackArrow\\BlackArrowMissile.mdl"
endfunction
//----------------------------------------------------------------//
// AOE: This is how far away from the caster the effects are //
// created //
constant function AB_ChannelMinAOE takes nothing returns real
return 200.
endfunction
// //
constant function AB_ChannelMaxAOE takes nothing returns real
return 300.
endfunction
//----------------------------------------------------------------//
// AbsorbAOE: This is how close to the caster the channel //
// effects must get to the caster before they are removed //
constant function AB_ChannelAbsorbAOE takes nothing returns real
return 50.
endfunction
//----------------------------------------------------------------//
// Size: This is how big each channel effect can be (1 = 100% //
// of their base size) //
constant function AB_ChannelMinSize takes nothing returns real
return 0.1
endfunction
// //
constant function AB_ChannelMaxSize takes nothing returns real
return 1.
endfunction
//----------------------------------------------------------------//
// SpawnRate: This is how many channel effects sets are created //
// per second that the unit is mid-channel //
constant function AB_ChannelSpawnRate takes nothing returns real
return 50.
endfunction
//----------------------------------------------------------------//
// SpawnCount: This is the amount of channel effects are created //
// every time a set is made //
constant function AB_ChannelSpawnCount takes nothing returns integer
return 2
endfunction
//----------------------------------------------------------------//
// Power: This is how storngly channel effects are pulled //
// towards the caster //
constant function AB_ChannelPower takes nothing returns real
return 90.
endfunction
//----------------------------------------------------------------//
// Hue: These are the values for the colour change of the unit //
// if colour change is enabled (255 = full colour) //
constant function AB_ChannelHueRed takes nothing returns integer
return 255
endfunction
// //
constant function AB_ChannelHueGreen takes nothing returns integer
return 0
endfunction
// //
constant function AB_ChannelHueBlue takes nothing returns integer
return 255
endfunction
// //
constant function AB_ChannelHueAlpha takes nothing returns integer
return 255
endfunction
//----------------------------------------------------------------//
// HueSpeed: This is how fast the unit oscillates between //
// the colour change and full colour - this value x 2 is how //
// long it takes to complete 1 full cycle //
constant function AB_ChannelHueSpeed takes nothing returns real
return 0.75
endfunction
//----------------------------------------------------------------//
// HaveHue: This determines whether or not this ability uses //
// a Hue change //
constant function AB_HaveHue takes nothing returns boolean
return true
endfunction
//----------------------------------------------------------------//
// PROJECTILE //
//----------------------------------------------------------------//
// MasterName: This is the name given to the projectile used //
// by the ability so that it can be uniquely identified //
constant function AB_MasterName takes nothing returns string
return "AB_Master"
endfunction
//----------------------------------------------------------------//
// Model: This is the filepath for the model used as the //
// projectile //
constant function AB_ProjectileModel takes nothing returns string
return "war3mapImported\\DarknessBomb.mdx"
endfunction
//----------------------------------------------------------------//
// DeathModel: This is the filepath for the model for when it //
// hits the target or the groun //
constant function AB_ProjectileDeathModel takes nothing returns string
return "Abilities\\Spells\\Human\\Feedback\\ArcaneTowerAttack.mdl"
endfunction
//----------------------------------------------------------------//
// Scale: This is the size of the projectile (1 = 100% of the //
// model's base size) //
constant function AB_ProjectileScaleBase takes nothing returns real
return 1.
endfunction
// //
constant function AB_ProjectileScalePerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// AOE: This is how close to the target the projectile must //
// get to damage it - it also gives the projectile this AOE to //
// nearby enemies //
constant function AB_ProjectileAOEBase takes nothing returns real
return 100.
endfunction
// //
constant function AB_ProjectileAOEPerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// HealthDamage: This is the amount of damage each projectile //
// deals to the target's health //
constant function AB_HealthDamageBase takes nothing returns real
return 50.
endfunction
// //
constant function AB_HealthDamagePerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// ManaDamage: This is the amount of damage each projectile //
// deals to the target's mana //
constant function AB_ManaDamageBase takes nothing returns real
return 10.
endfunction
// //
constant function AB_ManaDamagePerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// Accel: This is how much the speed of the projectiles are //
// multiplied by each loop iteration //
constant function AB_AccelBase takes nothing returns real
return 1.01
endfunction
// //
constant function AB_AccelPerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// TurnRate: This is the strength of the pull each projectile //
// has toward the target //
constant function AB_TurnRateBase takes nothing returns real
return 5.
endfunction
// //
constant function AB_TurnRatePerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// TurnEff: This is the efficiency of converting existing //
// speed toward the target (1 = 1/2 converted each loop //
// iteration //
constant function AB_TurnEffBase takes nothing returns real
return 0.3
endfunction
// //
constant function AB_TurnEffPerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// AimOffset: This is how far above the target unit the //
// projectiles will aim at //
constant function AB_AimOffsetBase takes nothing returns real
return 50.
endfunction
// //
constant function AB_AimOffsetPerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// AttackType: This is the type of attack used by the //
// projectile damage
constant function AB_AttackType takes nothing returns attacktype
return ATTACK_TYPE_NORMAL
endfunction
//----------------------------------------------------------------//
// DamageType: This is the type of damage used by the //
// projectile damage //
constant function AB_DamageType takes nothing returns damagetype
return DAMAGE_TYPE_NORMAL
endfunction
//----------------------------------------------------------------//
// MAIN ABILITY //
//----------------------------------------------------------------//
// AffectedEffect: This is the effect used for units that //
// are currently being targetted by the projectiles //
constant function AB_AffectedEffect takes nothing returns string
return "Abilities\\Spells\\Undead\\Curse\\CurseTarget.mdl"
endfunction
//----------------------------------------------------------------//
// ReleaseEffect: This is the effect used for units that have //
// just left the AOE or completed being shot at with //
// projectiles //
constant function AB_ReleaseEffect takes nothing returns string
return "war3mapImported\\Dummy.mdl"
endfunction
//----------------------------------------------------------------//
// AttachmentPoint: This is the attachment point the above //
// effects are attached to //
constant function AB_AttachmentPoint takes nothing returns string
return "overhead"
endfunction
//----------------------------------------------------------------//
// AOE: This is the range which targetted units need to leave //
// to stop being shot at with projectiles //
constant function AB_AOEBase takes nothing returns real
return 750.
endfunction
// //
constant function AB_AOEPerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// Duration: This is the time in seconds that units being //
// targetted will be shot at for //
constant function AB_DurationBase takes nothing returns real
return 5.
endfunction
// //
constant function AB_DurationPerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// FireRate: This is the amount of projectiles that are fired //
// per second //
constant function AB_FireRateBase takes nothing returns real
return 4.
endfunction
// //
constant function AB_FireRatePerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// FirePower: This is the velocity at which projectiles are //
// launched
constant function AB_FirePowerBase takes nothing returns real
return 180.
endfunction
// //
constant function AB_FirePowerPerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// FireAngle: This is the +-range of possible angles projectiles //
// can be fired at in radians (PI/2 = 90 degrees) giving 180 //
// degrees of possible values //
constant function AB_FireAngleBase takes nothing returns real
return bj_PI / 2
endfunction
// //
constant function AB_FireAnglePerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// FireAngleOrientation: This is the angle offset from the //
// caster to target that projectiles will be launched from //
// only "0" and bj_PI are sensible values for this as 0 is //
// towards them and bj_PI is away from them //
constant function AB_FireAngleOrientation takes nothing returns real
return bj_PI
endfunction
//----------------------------------------------------------------//
// GroundHeightOffset: This is the offset projectiles are //
// launched from when fired by a ground unit to keep them from //
// instantly hitting the ground (and looking visually wrong) //
constant function AB_GroundHeightOffset takes nothing returns real
return 50.
endfunction
//----------------------------------------------------------------//
// END OF CONFIGURATION //
//----------------------------------------------------------------//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Loop function used to create new projectiles, check that the //
// target is still within range of the ability and recycle //
// completed instances //
////////////////////////////////////////////////////////////////////
function AB_ArcaneBarrageLoop takes nothing returns nothing
//Locals
local integer iLoop = 0
local integer Node = 0
local real x
local real x2
local real y
local real y2
local real Angle
local real Angle2
//Cycle through each node
loop
set iLoop = iLoop + 1
exitwhen iLoop > udg_AB_CCount
set Node = udg_AB_NextNode[Node]
//Get location of unit and target
set x = GetUnitX(udg_AB_Unit[Node])
set x2 = GetUnitX(udg_AB_Target[Node])
set y = GetUnitY(udg_AB_Unit[Node])
set y2 = GetUnitY(udg_AB_Target[Node])
//Decrease duration timer
set udg_AB_Duration[Node] = udg_AB_Duration[Node] - AB_TimerSpeed()
//Check if the instance has ended
if(udg_AB_Duration[Node] <= 0.) or ((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y) > udg_AB_AOE[Node]) then
//Clean up effects
call DestroyEffect(udg_AB_Effect[Node])
call DestroyEffect(AddSpecialEffectTarget(AB_ReleaseEffect(), udg_AB_Target[Node], AB_AttachmentPoint()))
set udg_AB_Effect[Node] = null
set udg_AB_Unit[Node] = null
set udg_AB_Target[Node] = null
//Recycle
if (udg_AB_LastNode == Node) then
set udg_AB_LastNode = udg_AB_PrevNode[Node]
endif
set udg_AB_RecycleNodes[udg_AB_RecyclableNodes] = Node
set udg_AB_RecyclableNodes = udg_AB_RecyclableNodes + 1
set udg_AB_NextNode[udg_AB_PrevNode[Node]] = udg_AB_NextNode[Node]
set udg_AB_PrevNode[udg_AB_NextNode[Node]] = udg_AB_PrevNode[Node]
set udg_AB_CCount = udg_AB_CCount - 1
set iLoop = iLoop - 1
//Disable timer if this was the last instance
if (udg_AB_CCount == 0) then
call PauseTimer(udg_AB_Timer)
endif
else
//Update firing timer
set udg_AB_FireTimer[Node] = udg_AB_FireTimer[Node] - AB_TimerSpeed()
if (udg_AB_FireTimer[Node] <= 0.) then
//Create projectile
set udg_AB_FireTimer[Node] = udg_AB_FireRate[Node]
set Angle = GetRandomReal(-1 * udg_AB_FireAngle[Node], udg_AB_FireAngle[Node])
set Angle2 = Atan2(y2 - y, x2 - x) + AB_FireAngleOrientation()
call MPS_CreateProjectile(udg_AB_Unit[Node], udg_AB_Ammo[Node], udg_AB_FirePower[Node], Cos(Angle), Angle + Angle2, x, y, udg_AB_FireHeight[Node], udg_AB_Target[Node], x2, y2)
endif
endif
endloop
endfunction
////////////////////////////////////////////////////////////////////
// Function used when the channel has been completed //
// sets up spell data and adds units to the linked list //
////////////////////////////////////////////////////////////////////
function AB_ArcaneBarrageEvent takes nothing returns boolean
//Set up locals
local real rLevel = GetUnitAbilityLevel(udg_BUS_Unit, AB_Ability())
local integer Node
local real z = GetUnitFlyHeight(udg_BUS_Unit)
//Extra offset for ground units
if (IsUnitType(udg_BUS_Unit, UNIT_TYPE_GROUND)) then
set z = z + AB_GroundHeightOffset()
endif
//Set up Node
if (udg_AB_RecyclableNodes == 0) then
set udg_AB_NodeNumber = udg_AB_NodeNumber + 1
set Node = udg_AB_NodeNumber
else
set udg_AB_RecyclableNodes = udg_AB_RecyclableNodes - 1
set Node = udg_AB_RecycleNodes[udg_AB_RecyclableNodes]
endif
set udg_AB_NextNode[Node] = 0
set udg_AB_NextNode[udg_AB_LastNode] = Node
set udg_AB_PrevNode[Node] = udg_AB_LastNode
set udg_AB_LastNode = Node
set udg_AB_CCount = udg_AB_CCount + 1
//Set up Ability Data
set udg_AB_Unit[Node] = udg_BUS_Unit
set udg_AB_Target[Node] = udg_BUS_Target
set udg_AB_AOE[Node] = AB_AOEBase() + (AB_AOEPerLevel() * rLevel)
set udg_AB_AOE[Node] = udg_AB_AOE[Node] * udg_AB_AOE[Node]
set udg_AB_Ammo[Node] = MPS_GetAmmoByName(AB_MasterName() + R2S(rLevel))
set udg_AB_Duration[Node] = AB_DurationBase() + (AB_DurationPerLevel() * rLevel)
set udg_AB_FireAngle[Node] = AB_FireAngleBase() + (AB_FireAnglePerLevel() * rLevel)
set udg_AB_FirePower[Node] = AB_FirePowerBase() + (AB_FirePowerPerLevel() * rLevel)
set udg_AB_FireRate[Node] = 1. / (AB_FireRateBase() + (AB_FireRatePerLevel () * rLevel))
set udg_AB_FireHeight[Node] = z
set udg_AB_FireTimer[Node] = udg_AB_FireRate[Node]
set udg_AB_Effect[Node] = AddSpecialEffectTarget(AB_AffectedEffect(), udg_AB_Target[Node], AB_AttachmentPoint())
//Start timer if this is the only instance
if (udg_AB_CCount == 1) then
call TimerStart(udg_AB_Timer, AB_TimerSpeed(), true, function AB_ArcaneBarrageLoop)
endif
return false
endfunction
////////////////////////////////////////////////////////////////////
// Function used to start the channel process when the abiliyt //
// has been cast //
////////////////////////////////////////////////////////////////////
function AB_ArcaneBarrageStart takes nothing returns boolean
local unit u
//Start the channel
if (GetSpellAbilityId() == AB_Ability()) then
set u = GetTriggerUnit()
call BUS_StartChannel(BUS_GetChannelByName(AB_ChannelType()), u, GetSpellTargetUnit(), 0., 0., AB_ChannelDurationBase() + (GetUnitAbilityLevel(u, AB_Ability()) * AB_ChannelDurationPerLevel()), AB_Event(), AB_HaveHue())
set u = null
endif
return false
endfunction
////////////////////////////////////////////////////////////////////
// Function used to register the triggers, events, channel and //
// master projectile all used by this spell //
////////////////////////////////////////////////////////////////////
function InitTrig_Arcane_Barrage takes nothing returns nothing
//Set up local variables
local trigger t = CreateTrigger()
local integer i = 0
//Set up triggers
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function AB_ArcaneBarrageStart))
set t = CreateTrigger()
call TriggerRegisterVariableEvent(t, "udg_BUSC_Event", EQUAL, AB_Event())
call TriggerAddCondition(t, Condition(function AB_ArcaneBarrageEvent))
//Set up Channel
set udg_BUSCR_Name[0] = AB_ChannelType()
set udg_BUSCR_Effect[0] = AB_ChannelEffect()
set udg_BUSCR_MinAOE[0] = AB_ChannelMinAOE()
set udg_BUSCR_MaxAOE[0] = AB_ChannelMaxAOE()
set udg_BUSCR_AbsorbAOE[0] = AB_ChannelAbsorbAOE()
set udg_BUSCR_MinSize[0] = AB_ChannelMinSize()
set udg_BUSCR_MaxSize[0] = AB_ChannelMaxSize()
set udg_BUSCR_SpawnRate[0] = AB_ChannelSpawnRate()
set udg_BUSCR_SpawnCount[0] = AB_ChannelSpawnCount()
set udg_BUSCR_Power[0] = AB_ChannelPower()
set udg_BUSCR_HueRed[0] = AB_ChannelHueRed()
set udg_BUSCR_HueGreen[0] = AB_ChannelHueGreen()
set udg_BUSCR_HueBlue[0] = AB_ChannelHueBlue()
set udg_BUSCR_HueAlpha[0] = AB_ChannelHueAlpha()
set udg_BUSCR_HueSpeed[0] = AB_ChannelHueSpeed()
call BUS_RegisterChannel(0)
//Set up Master Projectile
set i = 0
loop
set i = i + 1
exitwhen i > AB_MaxLevel()
set udg_MPS_ProjectileName[0] = (AB_MasterName() + I2S(i) )
set udg_MPS_ProjectileModel[0] = AB_ProjectileModel()
set udg_MPS_ProjectileDeathModel[0] = AB_ProjectileDeathModel()
set udg_MPS_ProjectileModelScale[0] = AB_ProjectileScaleBase() + (AB_ProjectileScalePerLevel() * i)
set udg_MPS_ProjectileAOE[0] = AB_ProjectileAOEBase() + (AB_ProjectileAOEPerLevel() * i)
set udg_MPS_ProjectileHealthDamage[0] = AB_HealthDamageBase() + (AB_HealthDamagePerLevel() * i)
set udg_MPS_ProjectileManaDamage[0] = AB_ManaDamageBase() + (AB_ManaDamagePerLevel() * i)
set udg_MPS_ProjectileAcceleration[0] = AB_AccelBase() + (AB_AccelPerLevel() * i)
set udg_MPS_ProjectileTurnRate[0] = AB_TurnRateBase() + (AB_TurnRatePerLevel() * i)
set udg_MPS_ProjectileTurnEfficiency[0] = AB_TurnEffBase() + (AB_TurnEffPerLevel() * i)
set udg_MPS_ProjectileTargetAimOffset[0] = AB_AimOffsetBase() + (AB_AimOffsetPerLevel() * i)
set udg_MPS_ProjectileAttackType[0] = AB_AttackType()
set udg_MPS_ProjectileDamageType[0] = AB_DamageType()
call MPS_RegisterAmmo(0)
endloop
endfunction
////////////////////////////////////////////////////////////////////
//END OF THE SPELL //
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Boss Ultimate Spellpack Knockback V1.01 //
// Author: Tank-Commander //
// Purpose: Handles physics simulation within the spellpack //
// Used for: Scathe, Sheer Force //
// //
// Notes: //
// - Read the readme before you try modifying the config //
// - Use the "Helpful files" to help you import the system //
// //
// Credits: //
// - (Dummy.mdl) Vexorian //
// //
// If you have used this spellpack in your map, you are required //
// to give credits to Tank-Commander for the creation of it //
// If you would like to use snippets of code from this for //
// whatever, getting permission and crediting the source/linking //
// would be much appreciated. //
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// README: //
// Before modifying this spell a few things need to be //
// understood and read, this is one of those things, while //
// most modification can be considered intuitive, it still //
// helps to read through these intstructions, as they will //
// inform you about how to configure this spell to your //
// desire. //
//----------------------------------------------------------------//
// Initial importing: The variable creator trigger can be //
// imported first and if you have the correct settings (file, //
// preferences, General, automatically create unknown variables //
// checked, then when you paste in the variable creator it //
// will automatically give you all the variables you need for //
// this spell //
// //
// While the remaining object editor based data is not required //
// to function (provided they're replaced with equivelents) //
// it's recommended that they are also imported, if their data //
// value are not the same as listed in the configuration, those //
// configurables will need to be changed to work correctly //
//----------------------------------------------------------------//
// CONFIGURABLE INFORMATION/HELP: //
// //
// - Viewing data values: To see data values in the editor you //
// need to press Ctrl + D, to shift back to normal viewing //
// press it again //
// //
// - Effects: Pathnames for effects used in the spells should //
// have two "\"s throughout or the effect will not work (the //
// WE progress bar will not go away when saving, however if //
// fixed afterwards the save will still work, but the progress //
// bar will still remain until the WE is closed) //
// e.g. "units\\human\\Footman\\Footman" //
// //
// - Removing Effects: to remove an effect you don't want from //
// the ability, set the model path to that of Dummy.mdl //
// //
// - Timer: Some configurables have PerSecond values, the code //
// automatically accounts for changes to the timer as to //
// maintain consistency with what the user has chosen //
// All times in the system are expressions of seconds //
// //
//----------------------------------------------------------------//
// TimerSpeed: This is the amount of time in seconds between //
// each iteration of the Knockback Loop function //
constant function BUSKR_TimerSpeed takes nothing returns real
return 0.031250000
endfunction
//----------------------------------------------------------------//
// TreeCheckerId: This is the raw data Id of the unit used for //
// locating and potentially killing trees, it is advised this //
// unit uses dummy.mdl for its model for optimal usage and must //
// be able to harvest trees //
constant function BUSKR_TreeCheckerId takes nothing returns integer
return 'u000'
endfunction
//----------------------------------------------------------------//
// StunOrderId: This is the order Id of the ability used to //
// stun units that have been knocked back, by default this is //
// the order ID for storm bolt (use the one in the object editor //
// which has been placed onto the TreeChecker dummy unit there) //
constant function BUSKR_StunOrderId takes nothing returns integer
return 852095
endfunction
//----------------------------------------------------------------//
// AttachmentPoint: This is the point on affected units that the //
// effects will be placed on while they are being knocked back //
constant function BUSKR_AttachmentPoint takes nothing returns string
return "origin"
endfunction
//----------------------------------------------------------------//
// HeightResetRate: This is the speed at which units return to //
// their original heights (both flying units and ground units) //
constant function BUSKR_HeightResetRate takes nothing returns real
return 18.5
endfunction
//----------------------------------------------------------------//
// ForceAirDecay: This is the ratio at which momentum decays //
// while a unit is in the Air (Current Force / ForceDecay ) //
constant function BUSKR_ForceAirDecay takes nothing returns real
return 1.10
endfunction
//----------------------------------------------------------------//
// ForceGroundDecay: This is the ratio at which momentum decays //
// while a unit is on the ground (Current Force / Force Decay) //
constant function BUSKR_ForceGroundDecay takes nothing returns real
return 2.
endfunction
//----------------------------------------------------------------//
// DragLet: This is a "let" value for when units will be reset //
// (if the units current total knockback is less than this value //
// it will be treated as its knockback value is 0, this also //
// applies to fly heights and should not be 0 or less) //
constant function BUSKR_DragLet takes nothing returns real
return 2.
endfunction
//----------------------------------------------------------------//
// Use3DKnockback: This only applies to ground units, the value //
// determines whether or not ground units which are hit by a //
// force will be knocked into the air, this includes "bouncing" //
// off the ground when hit by a force coming from above (this //
// only occurs if the unit is currently on the ground) //
constant function BUSKR_Use3DKnockback takes nothing returns boolean
return true
endfunction
//----------------------------------------------------------------//
// StunGround: This determines whether or not ground units hit //
// into the air will be stunned for that time (so they do not //
// alter the arc) //
constant function BUSKR_StunGround takes nothing returns boolean
return true
endfunction
//----------------------------------------------------------------//
// KnockbackEffect: This is the path of the effect that will be //
// attached to units that are currently being knocked back //
constant function BUSKR_KnockbackEffect takes nothing returns string
return "Abilities\\Spells\\Other\\Tornado\\Tornado_Target.mdl"
endfunction
//----------------------------------------------------------------//
// GroundedEffect: This is the path of the effect that will be //
// created when a flying unit is knocked into the ground (fly //
// height of 0) //
constant function BUSKR_GroundedEffect takes nothing returns string
return "Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl"
endfunction
//----------------------------------------------------------------//
// InstantKillGround: This determines whether or not grounded //
// flyers will be instantly killed upon impact with the ground //
constant function BUSKR_InstantKillGround takes nothing returns boolean
return false
endfunction
//----------------------------------------------------------------//
// KillTrees; This determines whether or not trees will be //
// killed when a unit (on the ground) is pushed through them, if //
// set to false the system will attempt to prevent the unit from //
// moving into trees (but cannot be garunteed as 100% effective //
// due to knockback values potentially "jumping" the unit into //
// a clearing in the trees - TreeKillRadius can supplement this //
// issue //
constant function BUSKR_KillTrees takes nothing returns boolean
return false
endfunction
//----------------------------------------------------------------//
// TreeKillRadius: This determines the size of the area checked //
// when looking for trees to kill, but also functions as the //
// "let" radius for preventing units from being pushed through //
// trees, only applies to grounded units //
constant function BUSKR_TreeKillRadius takes nothing returns real
return 250.00
endfunction
//----------------------------------------------------------------//
// PreventUnpathable: This determines whether or not the system //
// will prevent units being knocked back into positions that //
// units cannot move in (it will assume ground units are not //
// able to move in deep water) //
constant function BUSKR_PreventUnpathable takes nothing returns boolean
return false
endfunction
//----------------------------------------------------------------//
// DummyPlayer: This is the player that is given ownership of //
// all the dummy units used by the system //
//----------------------------------------------------------------//
// END OF CONFIGURATION //
//----------------------------------------------------------------//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// TreeDestroy: Function used to count trees and kill them if //
// the configuration has been set up to do so //
////////////////////////////////////////////////////////////////////
function BUS_TreeDestroy takes nothing returns nothing
local destructable Tree = GetEnumDestructable()
set udg_BUSK_TreeCounter = udg_BUSK_TreeCounter + 1
call IssueTargetOrderById(udg_BUS_TreeChecker, 852018, Tree)
if (GetUnitCurrentOrder(udg_BUS_TreeChecker) == 852018) and (BUSKR_KillTrees()) then
call KillDestructable(Tree)
endif
call IssueImmediateOrderById(udg_BUS_TreeChecker, 851972)
set Tree = null
endfunction
////////////////////////////////////////////////////////////////////
// GetTrees: Part of the system used to locate trees and pass //
// them on to the TreeDestroy function //
////////////////////////////////////////////////////////////////////
function BUS_GetTrees takes real x, real y returns nothing
//Move Rect and find trees
call MoveRectTo(udg_BUS_Rect, x, y)
set udg_BUSK_TreeCounter = 0
call MoveLocation(udg_BUS_Loc, x, y)
set bj_enumDestructableCenter = udg_BUS_Loc
set bj_enumDestructableRadius = BUSKR_TreeKillRadius()
call EnumDestructablesInRect(udg_BUS_Rect, filterEnumDestructablesInCircleBJ, function BUS_TreeDestroy)
endfunction
////////////////////////////////////////////////////////////////////
// GetZ: Used to get the Z height of a given location, used to //
// make sure that entities going over cliffs aren't incorrectly //
// moved/placed on the z plane //
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// KnockbackLoop: function used to handle moving and changing //
// the heights knocked back units as well as slowing down their //
// speeds to 0 //
////////////////////////////////////////////////////////////////////
function BUS_KnockbackLoop takes nothing returns nothing
local integer Node = 0
local real x
local real x2
local real y
local real y2
local real TempReal
loop
set Node = udg_BUSK_NextNode[Node]
exitwhen Node == 0
set x2 = GetUnitX(udg_BUSK_Unit[Node])
set y2 = GetUnitY(udg_BUSK_Unit[Node])
set x = x2 + udg_BUSK_KnockbackX[Node]
set y = y2 + udg_BUSK_KnockbackY[Node]
set TempReal = BUS_GetZ(x, y)
if ((udg_BUS_MapMinX <= x) and (x <= udg_BUS_MapMaxX) and (udg_BUS_MapMinY <= y)and (y <= udg_BUS_MapMaxY)) then
if not((BUSKR_PreventUnpathable()) and not(IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY))) or not(udg_BUSK_UnitType[Node]) then
if (udg_BUSK_UnitType[Node] and udg_BUSK_CurrentHeight[Node] - TempReal <= 0) then
call BUS_GetTrees(x, y)
if (udg_BUSK_TreeCounter == 0) or (BUSKR_KillTrees()) then
call SetUnitX(udg_BUSK_Unit[Node], x)
call SetUnitY(udg_BUSK_Unit[Node], y)
endif
else
call SetUnitX(udg_BUSK_Unit[Node], x)
call SetUnitY(udg_BUSK_Unit[Node], y)
endif
endif
endif
if BUSKR_StunGround() then
call IssueTargetOrderById(udg_BUS_Stunner, BUSKR_StunOrderId(), udg_BUSK_Unit[Node])
endif
set udg_BUSK_CurrentHeight[Node] = udg_BUSK_CurrentHeight[Node] + udg_BUSK_KnockbackZ[Node] + (BUS_GetZ(x2, y2) - TempReal)
if ((udg_BUSK_CurrentHeight[Node] - TempReal) > 0) then
set udg_BUSK_KnockbackX[Node] = udg_BUSK_KnockbackX[Node] / BUSKR_ForceAirDecay()
set udg_BUSK_KnockbackY[Node] = udg_BUSK_KnockbackY[Node] / BUSKR_ForceAirDecay()
set udg_BUSK_KnockbackZ[Node] = udg_BUSK_KnockbackZ[Node] / BUSKR_ForceAirDecay()
else
set udg_BUSK_KnockbackX[Node] = udg_BUSK_KnockbackX[Node] / BUSKR_ForceGroundDecay()
set udg_BUSK_KnockbackY[Node] = udg_BUSK_KnockbackY[Node] / BUSKR_ForceGroundDecay()
set udg_BUSK_KnockbackZ[Node] = 0
if not(udg_BUSK_UnitType[Node]) then
call DestroyEffect(AddSpecialEffectTarget(BUSKR_GroundedEffect(), udg_BUSK_Unit[Node], BUSKR_AttachmentPoint()))
if (BUSKR_InstantKillGround()) then
call KillUnit(udg_BUSK_Unit[Node])
call DestroyEffect(udg_BUSK_CurrentEffect[Node])
set udg_BUSK_RecycleNodes[udg_BUSK_RecyclableNodes] = Node
set udg_BUSK_RecyclableNodes = udg_BUSK_RecyclableNodes + 1
set udg_BUSK_NextNode[udg_BUSK_PrevNode[Node]] = udg_BUSK_NextNode[Node]
set udg_BUSK_PrevNode[udg_BUSK_NextNode[Node]] = udg_BUSK_PrevNode[Node]
if (udg_BUSK_PrevNode[0] == 0) then
call PauseTimer(udg_BUSK_Timer)
endif
endif
endif
endif
call SetUnitFlyHeight(udg_BUSK_Unit[Node], udg_BUSK_CurrentHeight[Node] - TempReal, 0.00)
if (udg_BUSK_UnitType[Node]) then
if(udg_BUSK_KnockbackX[Node] + udg_BUSK_KnockbackY[Node] + udg_BUSK_KnockbackZ[Node] < BUSKR_DragLet()) and (udg_BUSK_CurrentHeight[Node] - TempReal <= 0) then
call SetUnitFlyHeight(udg_BUSK_Unit[Node], 0, 0.00)
call DestroyEffect(udg_BUSK_CurrentEffect[Node])
set udg_BUSK_RecycleNodes[udg_BUSK_RecyclableNodes] = Node
set udg_BUSK_RecyclableNodes = udg_BUSK_RecyclableNodes + 1
set udg_BUSK_NextNode[udg_BUSK_PrevNode[Node]] = udg_BUSK_NextNode[Node]
set udg_BUSK_PrevNode[udg_BUSK_NextNode[Node]] = udg_BUSK_PrevNode[Node]
if (udg_BUSK_PrevNode[0] == 0) then
call PauseTimer(udg_BUSK_Timer)
endif
endif
set udg_BUSK_CurrentHeight[Node] = udg_BUSK_CurrentHeight[Node] - BUSKR_HeightResetRate()
else
set TempReal = udg_BUSK_ReturnHeight[Node] - (udg_BUSK_CurrentHeight[Node] - TempReal)
if (TempReal * TempReal <= BUSKR_HeightResetRate() * BUSKR_HeightResetRate()) and (udg_BUSK_KnockbackZ[Node] < BUSKR_DragLet()) then
call SetUnitFlyHeight(udg_BUSK_Unit[Node], udg_BUSK_ReturnHeight[Node], 0.00)
call DestroyEffect(udg_BUSK_CurrentEffect[Node])
if (udg_BUSK_KnockbackX[Node] + udg_BUSK_KnockbackY[Node] + udg_BUSK_KnockbackZ[Node] < BUSKR_DragLet()) then
set udg_BUSK_RecycleNodes[udg_BUSK_RecyclableNodes] = Node
set udg_BUSK_RecyclableNodes = udg_BUSK_RecyclableNodes + 1
set udg_BUSK_NextNode[udg_BUSK_PrevNode[Node]] = udg_BUSK_NextNode[Node]
set udg_BUSK_PrevNode[udg_BUSK_NextNode[Node]] = udg_BUSK_PrevNode[Node]
if (udg_BUSK_PrevNode[0] == 0) then
call PauseTimer(udg_BUSK_Timer)
endif
endif
elseif (udg_BUSK_ReturnHeight[Node] > (udg_BUSK_CurrentHeight[Node] - TempReal)) then
set udg_BUSK_CurrentHeight[Node] = udg_BUSK_CurrentHeight[Node] + BUSKR_HeightResetRate()
else
set udg_BUSK_CurrentHeight[Node] = udg_BUSK_CurrentHeight[Node] - BUSKR_HeightResetRate()
endif
endif
endloop
endfunction
////////////////////////////////////////////////////////////////////
// StartKnockback: Function used to start a unit's knockback //
// and adds it into the loop to be knocked back, it also //
// prevents a unit having two iterations within the loop //
////////////////////////////////////////////////////////////////////
function BUS_StartKnockback takes unit u, real Force, real x, real x2, real y, real y2, real z, real z2 returns nothing
local boolean TempBoolean = true
local integer Node = 0
local real dx
local real dy
local real Angle
local real Angle2
loop
set Node = udg_BUSK_NextNode[Node]
if (udg_BUSK_Unit[Node] == u) then
set TempBoolean = false
endif
exitwhen (Node == 0) or (udg_BUSK_Unit[Node] == u)
endloop
if (TempBoolean) then
if (udg_BUSK_RecyclableNodes == 0) then
set udg_BUSK_NodeNumber = udg_BUSK_NodeNumber + 1
set Node = udg_BUSK_NodeNumber
else
set udg_BUSK_RecyclableNodes = udg_BUSK_RecyclableNodes - 1
set Node = udg_BUSK_RecycleNodes[udg_BUSK_RecyclableNodes]
endif
set udg_BUSK_NextNode[Node] = 0
set udg_BUSK_NextNode[udg_BUSK_PrevNode[0]] = Node
set udg_BUSK_PrevNode[Node] = udg_BUSK_PrevNode[0]
set udg_BUSK_PrevNode[0] = Node
set udg_BUSK_Unit[Node] = u
set udg_BUSK_ReturnHeight[Node] = GetUnitFlyHeight(u)
set udg_BUSK_CurrentHeight[Node] = udg_BUSK_ReturnHeight[Node] + BUS_GetZ(x, y)
set udg_BUSK_CurrentEffect[Node] = AddSpecialEffectTarget(BUSKR_KnockbackEffect(), u, BUSKR_AttachmentPoint())
set udg_BUSK_UnitType[Node] = IsUnitType(u, UNIT_TYPE_GROUND)
set udg_BUSK_KnockbackX[Node] = 0.
set udg_BUSK_KnockbackY[Node] = 0.
set udg_BUSK_KnockbackZ[Node] = 0.
if UnitAddAbility(udg_BUSK_Unit[Node], 'Amrf') and UnitRemoveAbility(udg_BUSK_Unit[Node], 'Amrf') then
endif
if (udg_BUSK_PrevNode[Node] == 0) then
call TimerStart(udg_BUSK_Timer, BUSKR_TimerSpeed(), true, function BUS_KnockbackLoop)
endif
endif
set dy = y - y2
set dx = x - x2
if (udg_BUSK_UnitType[Node]) and (udg_BUSK_CurrentHeight[Node] - BUS_GetZ(x, y) <= BUSKR_DragLet()) then
set Angle2 = Atan2((z2 - z), SquareRoot((dy * dy) + (dx * dx)))
if(BUSKR_Use3DKnockback()) then
if ((z2 - z) < 0) then
set Angle2 = Atan2((z - z2), SquareRoot((dy * dy) + (dx * dx)))
endif
set udg_BUSK_KnockbackZ[Node] = udg_BUSK_KnockbackZ[Node] + Sin(Angle2) * Force
endif
else
set Angle2 = Atan2((z - z2), SquareRoot((dy * dy) + (dx * dx)))
set udg_BUSK_KnockbackZ[Node] = udg_BUSK_KnockbackZ[Node] + Sin(Angle2) * Force
endif
set Angle = Atan2(dy, dx)
set udg_BUSK_KnockbackX[Node] = udg_BUSK_KnockbackX[Node] + Cos(Angle) * Cos(Angle2) * Force
set udg_BUSK_KnockbackY[Node] = udg_BUSK_KnockbackY[Node] + Sin(Angle) * Cos(Angle2) * Force
endfunction
////////////////////////////////////////////////////////////////////
// InitTrig BUS Knockback: function used to set up the timer //
// used by the system and the tree checking unit //
////////////////////////////////////////////////////////////////////
function InitTrig_BUS_Knockback takes nothing returns nothing
set udg_BUSK_Timer = CreateTimer()
set udg_BUS_TreeChecker = CreateUnit(BUSCR_DummyPlayer(), BUSKR_TreeCheckerId(), 0., 0. , 0.)
set udg_BUS_Stunner = CreateUnit(BUSCR_DummyPlayer(), BUSKR_TreeCheckerId(), 0., 0., 0.)
set udg_BUS_Rect = Rect(0, 0, BUSKR_TreeKillRadius(), BUSKR_TreeKillRadius())
set udg_BUS_Loc = Location(0,0)
set udg_BUS_MapMaxX = GetRectMaxX(bj_mapInitialPlayableArea)
set udg_BUS_MapMinX = GetRectMinX(bj_mapInitialPlayableArea)
set udg_BUS_MapMaxY = GetRectMaxY(bj_mapInitialPlayableArea)
set udg_BUS_MapMinY = GetRectMinY(bj_mapInitialPlayableArea)
endfunction
////////////////////////////////////////////////////////////////////
// End of the system //
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// MASSIVE CLEAVE V1.01 //
// Author: Tank-Commander //
// Purpose: A powerful keepaway ability for scaring opposition //
// //
// Requires: //
// - (optional) BUS_Knockback by Tank-Commander //
// remove lines outlined by "******" in code if not used //
// //
// Notes: //
// - Read the readme before you try modifying the config //
// - Use the "Helpful files" to help you import the system //
// //
// Credits: //
// - (Dummy.mdl) Vexorian //
// //
// If you have used this spell in your map, you are required //
// to give credits to Tank-Commander for the creation of it //
// If you would like to use snippets of code from this for //
// whatever, getting permission and crediting the source/linking //
// would be much appreciated. //
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// README: //
// Before modifying this spell a few things need to be //
// understood and read, this is one of those things, while //
// most modification can be considered intuitive, it still //
// helps to read through these intstructions, as they will //
// inform you about how to configure this spell to your //
// desire. //
//----------------------------------------------------------------//
// Initial importing: The variable creator trigger can be //
// imported first and if you have the correct settings (file, //
// preferences, General, automatically create unknown variables //
// checked, then when you paste in the variable creator it //
// will automatically give you all the variables you need for //
// this spell //
// //
// While the remaining object editor based data is not required //
// to function (provided they're replaced with equivelents) //
// it's recommended that they are also imported, if their data //
// value are not the same as listed in the configuration, those //
// configurables will need to be changed to work correctly //
//----------------------------------------------------------------//
// MISC //
//----------------------------------------------------------------//
// TimerSpeed: the time in seconds between each iteration of //
// the main loop function (default is 0.031250000) it's //
// recommended you leave it like that //
constant function MC_TimerSpeed takes nothing returns real
return 0.031250000
endfunction
//----------------------------------------------------------------//
// Ability: This is the data value of the ability used as the //
// base, make sure it is based off channel (to view raw data //
// press ctrl + d, pressing again switches back) //
constant function MC_Ability takes nothing returns integer
return 'A012'
endfunction
//----------------------------------------------------------------//
// DummyID: This is the data value of the unit to be used as the //
// dummy for blood effects generated by the cleave //
constant function MC_DummyID takes nothing returns integer
return 'u000'
endfunction
//----------------------------------------------------------------//
// OrderID: This is the order ID used by the ability to tell if //
// the unit is still channelling the ability and cancelling it //
// if it stops (852474 is default for 1.28) //
constant function MC_OrderID takes nothing returns integer
return 852473
endfunction
//----------------------------------------------------------------//
// Attachmentpoint: This is the location on the Dummy unit that //
// blood effects will be placed on //
constant function MC_AttachmentPoint takes nothing returns string
return "origin"
endfunction
//----------------------------------------------------------------//
// Clockwise: Determines what direction the cleave will take //
// (set it to match the handedness of the unit(s) using the //
// ability, righthanded: anticlockwise, lefthanded: clockwise //
constant function MC_Clockwise takes nothing returns boolean
return false
endfunction
//----------------------------------------------------------------//
// Timer: How long in seconds dummy units are alive for //
constant function MC_Timer takes nothing returns real
return 3.
endfunction
//----------------------------------------------------------------//
// DummyPlayer: The owning player of the dummy units //
constant function MC_DummyPlayer takes nothing returns player
return Player(14)
endfunction
//----------------------------------------------------------------//
// AttackType: The attack type used when dealing damage //
constant function MC_AttackType takes nothing returns attacktype
return ATTACK_TYPE_MAGIC
endfunction
//----------------------------------------------------------------//
// DamageType: The damage type used when dealing damage //
constant function MC_DamageType takes nothing returns damagetype
return DAMAGE_TYPE_MAGIC
endfunction
//----------------------------------------------------------------//
// MAIN ABILITY //
//----------------------------------------------------------------//
// AOE: The Area around the caster that the cleave reaches //
function MC_AOE takes real level returns real
return 250 + (25 * level)
endfunction
//----------------------------------------------------------------//
// EffectDistance: How far away from the caster blood effects //
// are created
function MC_EffectDistance takes real level returns real
return 150 + (25 * level)
endfunction
//----------------------------------------------------------------//
// Angle: The angle covered by the cleave (radians) bj_PI = 90 //
// degrees, it will eb centered around the unit facing angle //
function MC_Angle takes real level returns real
return 1.7 + (0.26 * level)
endfunction
//----------------------------------------------------------------//
// Divisions: This is the amount of segments in your cleave //
// it's recommended to have at least 3 for all levels //
function MC_Divisions takes real level returns real
return 2 + (1 * level)
endfunction
//----------------------------------------------------------------//
// HealthDamage: The amount of damage your cleave deals to //
// the health of units hit //
function MC_HealthDamage takes real level returns real
return 80 + (20 * level)
endfunction
//----------------------------------------------------------------//
// ManaDamage: The amount of damage your cleave deals to the //
// mana of units hit //
function MC_ManaDamage takes real level returns real
return 0.
endfunction
//----------------------------------------------------------------//
// InitialDelay: The time after starting the ability that the //
// first cleave segment is used and units are hit in seconds //
function MC_InitialDelay takes real level returns real
return .20 + (-0.01 * level)
endfunction
//----------------------------------------------------------------//
// DivisionDelay: The time between each cleave segment being //
// used and units getting hit in seconds //
function MC_DivisionDelay takes real level returns real
return 0.04 + (-0.01 * level)
endfunction
//----------------------------------------------------------------//
// KnockbackForce: The force at which units are hit by the //
// cleave (only relevent to knockback and not damage) //
function MC_KnockbackForce takes real level returns real
return 30 + (10 * level)
endfunction
//----------------------------------------------------------------//
// KnockbackCleaveAngle: This is the angle taken from straight //
// forward that units are knocked back in (positive values //
// lead to the unit getting pushed in the direction of the //
// cleaver) //
constant function MC_KnockbackCleaveAngle takes nothing returns real
return bj_PI / 3
endfunction
//----------------------------------------------------------------//
// PitchCalcVal: The hit height of the cleaver on target units //
// (used to work out their angle when launched, higher values //
// result in more steep arcs but may need more KnockbackForce //
// to be effective) //
constant function MC_PitchCalcVal takes nothing returns real
return 200.
endfunction
//----------------------------------------------------------------//
// CleaveHitEffect: The effect created when the cleaver hits //
// a unit successfully //
constant function MC_CleaveHitEffect takes nothing returns string
return "Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl"
endfunction
//----------------------------------------------------------------//
// CleaveHitScale: The size of the effect created when the //
// cleave hits a unit successfully (1 = 100% model size) //
constant function MC_CleaveHitScale takes real level returns real
return 1 + (0.2 * level)
endfunction
//----------------------------------------------------------------//
// FilterMaxZ: The Highest fly height a unit can have while //
// still being considered a valid target //
constant function MC_FilterMaxZ takes nothing returns real
return 0.01
endfunction
//----------------------------------------------------------------//
// CleaveAngleLet: Added to angles to compensate for floating //
// point arithmetic errors (read-only) //
constant function MC_CleaveAngleLet takes nothing returns real
return 0.01
endfunction
//----------------------------------------------------------------//
// AngleCorrection: Used to convert negative angles into //
// positive ones (read-only) //
constant function MC_AngleCorrection takes nothing returns real
return bj_PI * 2
endfunction
//----------------------------------------------------------------//
// END OF CONFIGURATION //
//----------------------------------------------------------------//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Target filter function used to differentiate between units //
// that can be hit by the spell and those that cannot //
////////////////////////////////////////////////////////////////////
function MC_TargetFilter takes unit u, player pl returns boolean
return (not IsUnitType(u, UNIT_TYPE_STRUCTURE)) and (GetUnitFlyHeight(u) <= MC_FilterMaxZ()) and (not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE)) and (IsUnitEnemy(u, pl)) and (GetUnitTypeId(u) != MC_DummyID()) and not(IsUnitType(u, UNIT_TYPE_DEAD) or GetUnitTypeId(u) == 0)
endfunction
////////////////////////////////////////////////////////////////////
// Check cleave function used ot prevent two channels being done //
// by the same unit at the same time //
////////////////////////////////////////////////////////////////////
function MC_CheckCleave takes unit u returns nothing
local integer Node = udg_MC_NextNode[0]
loop
exitwhen (Node == 0) or (udg_MC_Unit[Node] == u)
set Node = udg_MC_NextNode[Node]
endloop
set udg_MC_Delay[Node] = 0.
set udg_MC_Angle[Node] = udg_MC_AngleLimit[Node]
endfunction
////////////////////////////////////////////////////////////////////
// AbsAngle function used to convert negative angles (rads) into //
// positive angles (rads), standardises angles so formulas can //
// be used effectively //
////////////////////////////////////////////////////////////////////
function MC_AbsAngle takes real angle returns real
if angle < 0. then
return angle + MC_AngleCorrection()
else
return angle
endif
endfunction
////////////////////////////////////////////////////////////////////
// Validate Angle function used to check if a given unit is //
// within the boundaries of the current cleave segment //
////////////////////////////////////////////////////////////////////
function MC_ValidateAngle takes real boundary, real boundary2, real angle returns boolean
//Check what direction the cleave is going in
//And then check if the angle is within the two boundaries
if MC_Clockwise() then
if boundary <= 0 and angle < boundary2 then
set angle = angle - MC_AngleCorrection()
endif
return (boundary - angle >= -MC_CleaveAngleLet() and boundary2 - angle <= MC_CleaveAngleLet())
else
if boundary2 >= MC_AngleCorrection() and angle < boundary then
set angle = angle + MC_AngleCorrection()
endif
return (boundary2 - angle >= -MC_CleaveAngleLet() and boundary - angle <= MC_CleaveAngleLet())
endif
return false
endfunction
////////////////////////////////////////////////////////////////////
// Loop function used to control the cleave, damaging units //
// knocking them in the air and creating effects //
////////////////////////////////////////////////////////////////////
function MC_MassiveCleaveLoop takes nothing returns nothing
//Set up Locals
local integer Node = udg_MC_NextNode[0]
local real angle
local real angle2
local real tempReal
local real x
local real y
local real x2
local real y2
local real dy
local real dx
local boolean bool
local unit u
//Cycle through each node
loop
exitwhen Node == 0
//Check if it's time to create another cleave point
if udg_MC_Delay[Node] < MC_TimerSpeed() then
//Check if the cleave is finished
if (udg_MC_Angle[Node] >= (udg_MC_AngleLimit[Node] - MC_CleaveAngleLet()) and not(MC_Clockwise())) or ((udg_MC_Angle[Node] <= (udg_MC_AngleLimit[Node] + MC_CleaveAngleLet())) and MC_Clockwise()) then
set udg_MC_RecycleNodes[udg_MC_RecyclableNodes] = Node
set udg_MC_RecyclableNodes = udg_MC_RecyclableNodes + 1
set udg_MC_NextNode[udg_MC_PrevNode[Node]] = udg_MC_NextNode[Node]
set udg_MC_PrevNode[udg_MC_NextNode[Node]] = udg_MC_PrevNode[Node]
//Pause timer if this was the last instance
if (udg_MC_PrevNode[0] == 0) then
call PauseTimer(udg_MC_Timer)
endif
else
set x = GetUnitX(udg_MC_Unit[Node])
set y = GetUnitY(udg_MC_Unit[Node])
set bool = false
set udg_MC_Delay[Node] = udg_MC_DelayReset[Node]
set angle = udg_MC_Angle[Node] + udg_MC_Division[Node]
//Find units to cleave
call GroupEnumUnitsInRange(udg_MC_TempGroup, x, y, udg_MC_AOE[Node], null)
loop
set u = FirstOfGroup(udg_MC_TempGroup)
exitwhen u == null
//Valid target type
if MC_TargetFilter(u, udg_MC_Player[Node]) then
set x2 = GetUnitX(u)
set y2 = GetUnitY(u)
set dy = y2 - y
set dx = x2 - x
set angle2 = Atan2(dy, dx)
if angle2 < 0. then
set angle2 = angle2 + MC_AngleCorrection()
endif
//Within the correct arc
if (MC_ValidateAngle(udg_MC_Angle[Node], angle, angle2)) then
set bool = true
//Damage unit and setup knockback data
call SetUnitState(u, UNIT_STATE_MANA, GetUnitState(u, UNIT_STATE_MANA) - udg_MC_ManaDamage[Node])
call UnitDamageTarget(udg_MC_Unit[Node], u, udg_MC_HealthDamage[Node], true, false, MC_AttackType(), MC_DamageType(), null)
//*********************************************
//Knockback (delete if not using BUS_Knockback)
if MC_Clockwise() then
set angle2 = angle2 - MC_KnockbackCleaveAngle()
else
set angle2 = angle2 + MC_KnockbackCleaveAngle()
endif
set tempReal = SquareRoot(dx * dx + dy * dy)
call BUS_StartKnockback(u, udg_MC_KnockbackForce[Node], x2 + tempReal * Cos(angle2), x2, y2 + tempReal * Sin(angle2), y2, 0., MC_PitchCalcVal())
//*********************************************
endif
endif
call GroupRemoveUnit(udg_MC_TempGroup, u)
endloop
//Create blood effect if a unit was hit
if bool then
//Find position
set angle2 = udg_MC_Angle[Node] + udg_MC_AngleAdjust[Node]
//Create effect
set u = CreateUnit(MC_DummyPlayer(), MC_DummyID(), x + udg_MC_EffectDistance[Node] * Cos(angle2), y + udg_MC_EffectDistance[Node] * Sin(angle2), angle2 * bj_RADTODEG)
call SetUnitScale(u, udg_MC_CleaveScale[Node], 0., 0.)
call DestroyEffect(AddSpecialEffectTarget(MC_CleaveHitEffect(), u, MC_AttachmentPoint()))
call UnitApplyTimedLife(u, 'BHwe', MC_Timer())
set u = null
endif
//Move Position
set udg_MC_Angle[Node] = angle
endif
else
set udg_MC_Delay[Node] = udg_MC_Delay[Node] - MC_TimerSpeed()
if not(GetUnitCurrentOrder(udg_MC_Unit[Node]) == MC_OrderID()) then
set udg_MC_Delay[Node] = 0.
set udg_MC_Angle[Node] = udg_MC_AngleLimit[Node]
endif
endif
set Node = udg_MC_NextNode[Node]
endloop
endfunction
////////////////////////////////////////////////////////////////////
// Function used to start the channel process when the abiliyt //
// has been cast //
////////////////////////////////////////////////////////////////////
function MC_StartCleave takes nothing returns boolean
//Set up locals
local integer Node
local real level
local real offset
local real facing
local unit u
//Start the channel
if (GetSpellAbilityId() == MC_Ability()) then
//Get unit and check for multiple channels
set u = GetTriggerUnit()
call MC_CheckCleave(u)
//Set up Node
if (udg_MC_RecyclableNodes == 0) then
set udg_MC_NodeNumber = udg_MC_NodeNumber + 1
set Node = udg_MC_NodeNumber
else
set udg_MC_RecyclableNodes = udg_MC_RecyclableNodes - 1
set Node = udg_MC_RecycleNodes[udg_MC_RecyclableNodes]
endif
set udg_MC_NextNode[Node] = 0
set udg_MC_NextNode[udg_MC_PrevNode[0]] = Node
set udg_MC_PrevNode[Node] = udg_MC_PrevNode[0]
set udg_MC_PrevNode[0] = Node
//Start timer if this is the only instance
if (udg_MC_PrevNode[Node] == 0) then
call TimerStart(udg_MC_Timer, MC_TimerSpeed(), true, function MC_MassiveCleaveLoop)
endif
//Set up cleave data
set udg_MC_Unit[Node] = u
set udg_MC_Player[Node] = GetTriggerPlayer()
set level = GetUnitAbilityLevel(udg_MC_Unit[Node], MC_Ability())
set facing = GetUnitFacing(udg_MC_Unit[Node]) * bj_DEGTORAD
set offset = MC_Angle(level)
if MC_Clockwise() then
set udg_MC_Division[Node] = offset / -MC_Divisions(level)
set offset = offset / 2
set udg_MC_AngleLimit[Node] = MC_AbsAngle(facing + offset)
set udg_MC_Angle[Node] = udg_MC_AngleLimit[Node] - offset * 2
else
set udg_MC_Division[Node] = offset / MC_Divisions(level)
set offset = offset / -2
set udg_MC_Angle[Node] = MC_AbsAngle(facing + offset)
set udg_MC_AngleLimit[Node] = udg_MC_Angle[Node] - offset * 2
endif
set udg_MC_AOE[Node] = MC_AOE(level)
set udg_MC_EffectDistance[Node] = MC_EffectDistance(level)
set udg_MC_AngleAdjust[Node] = (udg_MC_Division[Node] / 2)
set udg_MC_HealthDamage[Node] = MC_HealthDamage(level)
set udg_MC_ManaDamage[Node] = MC_ManaDamage(level)
set udg_MC_Delay[Node] = MC_InitialDelay(level)
set udg_MC_DelayReset[Node] = MC_DivisionDelay(level)
set udg_MC_KnockbackForce[Node] = MC_KnockbackForce(level)
set udg_MC_CleaveScale[Node] = MC_CleaveHitScale(level)
endif
return false
endfunction
////////////////////////////////////////////////////////////////////
// Function used to register the trigger of the ability //
////////////////////////////////////////////////////////////////////
function InitTrig_Massive_Cleave takes nothing returns nothing
//Set up local variables
local trigger t = CreateTrigger()
//Set up trigger
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function MC_StartCleave))
endfunction
////////////////////////////////////////////////////////////////////
//END OF THE SPELL //
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Boss Ultimate Spellpack Soul Release V1.00 //
// Author: Tank-Commander //
// Purpose: Boss Ultimate Instant Kill //
// Requires: Dummy.mdl, BUS Channel //
// //
// Notes: //
// - Read the readme before you try modifying the config //
// - Use the "Helpful files" to help you import the system //
// //
// Credits: //
// - (Dummy.mdl) Vexorian //
// - (LightningWrath.mdl) Callahan //
// //
// Optimum User: Any (Large) //
// //
// If you have used this spellpack in your map, you are required //
// to give credits to Tank-Commander for the creation of it //
// If you would like to use snippets of code from this for //
// whatever, getting permission and crediting the source/linking //
// would be much appreciated. //
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// README: //
// Before modifying this spell a few things need to be //
// understood and read, this is one of those things, while //
// most modification can be considered intuitive, it still //
// helps to read through these intstructions, as they will //
// inform you about how to configure this spell to your //
// desire. //
//----------------------------------------------------------------//
// Initial importing: The variable creator trigger can be //
// imported first and if you have the correct settings (file, //
// preferences, General, automatically create unknown variables //
// checked, then when you paste in the variable creator it //
// will automatically give you all the variables you need for //
// this spell //
// //
// While the remaining object editor based data is not required //
// to function (provided they're replaced with equivelents) //
// it's recommended that they are also imported, if their data //
// value are not the same as listed in the configuration, those //
// configurables will need to be changed to work correctly //
//----------------------------------------------------------------//
// CONFIGURABLE INFORMATION/HELP: //
// //
// - Viewing data values: To see data values in the editor you //
// need to press Ctrl + D, to shift back to normal viewing //
// press it again //
// //
// - Effects: Pathnames for effects used in the spells should //
// have two "\"s throughout or the effect will not work (the //
// WE progress bar will not go away when saving, however if //
// fixed afterwards the save will still work, but the progress //
// bar will still remain until the WE is closed) //
// e.g. "units\\human\\Footman\\Footman" //
// //
// - Effect Scaling: Some effects have scale values below them //
// the scale determines the size of the effect and is expressed //
// as a real percentage (1.00 = 100%) //
// //
// - Removing Effects: to remove an effect you don't want from //
// the ability, set the model path to that of Dummy.mdl //
// //
// - Base and Per Values: Most configurables have a base and per //
// value, Base values are what a value is set to regardless of //
// other factors. Per values are what a value is set to based on //
// what the per value is the formula for calculating the result //
// is as follows: //
// - BaseValue + (Factor * PerValue) //
// //
// - Timer: Some configurables have PerSecond values, the code //
// automatically accounts for changes to the timer as to //
// maintain consistency with what the user has chosen //
// All times in the system are expressions of seconds //
// //
// - AttackTypes: This should match the Damage Type of the //
// ability, though it can be something else if you wish //
// //
// - DamageTypes: This changes the damage multiplyer vs. enemy //
// armour types, note that by default the damage filters //
// exclude magic immune units so changing this from MAGIC //
// damage will not make them take damage //
// //
// - WeaponTypes: Generally don't need to be used, should only //
// not be null if you particularly wish or need to use them //
// //
//----------------------------------------------------------------//
// TimerSpeed: This is the amount of time in seconds between //
// each iteration of the Soul Release Loop function //
constant function BUSRR_TimerSpeed takes nothing returns real
return 0.031250000
endfunction
//----------------------------------------------------------------//
// Ability: This is the AbilityId that is used as the dummy //
// ability used for the soul release spell //
constant function BUSRR_Ability takes nothing returns integer
return 'A01A'
endfunction
//----------------------------------------------------------------//
// InvulAbility: This is the AbilityId that is used to make the //
// spirits immune, this should be the ability "invulnerability" //
// (which one it is doesn't matter) //
constant function BUSRR_InvulAbility takes nothing returns integer
return 'Avul'
endfunction
//----------------------------------------------------------------//
// DummyId: This is the UnitId that is used to create effects //
// It is recommended this unit use Dummy.mdl for its model for //
// optimal usage //
constant function BUSRR_DummyId takes nothing returns integer
return 'u005'
endfunction
//----------------------------------------------------------------//
// Event: This is the value of BUS_Event that it will be set to //
// when the channeling ends, this should be unique to each //
// ability which uses the channel system //
constant function BUSRR_Event takes nothing returns integer
return 1
endfunction
//----------------------------------------------------------------//
// AttachmentPoint: This is the point on units that effects will //
// be attached to //
constant function BUSRR_AttachmentPoint takes nothing returns string
return "origin"
endfunction
//----------------------------------------------------------------//
// HaveHue: This determines whether or not a unit will have its //
// hue altered during the channeling stage //
constant function BUSRR_HaveHue takes nothing returns boolean
return true
endfunction
//----------------------------------------------------------------//
// ChannelType: This determines the type of channel that is used //
// This should match the name of channel type used //
constant function BUSRR_ChannelType takes nothing returns string
return "Holy Storm"
endfunction
//----------------------------------------------------------------//
// ChannelDurationBase: This determines how long the ability //
// will use the channel system before starting its next stage //
constant function BUSRR_ChannelDurationBase takes nothing returns real
return 6.
endfunction
//----------------------------------------------------------------//
// ChannelDurationPerLevel: The per level counterpart of //
// ChannelDurationBase //
constant function BUSRR_ChannelDurationPerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// HitDistanceBase: This is the range used to check if units //
// are valid targets for the ability once the channeling is //
// completed //
constant function BUSRR_HitDistanceBase takes nothing returns real
return 700.
endfunction
//----------------------------------------------------------------//
// HitDistancePerLevel: The per level counterpart of //
// HitDistanceBase //
constant function BUSRR_HitDistancePerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// MainAOEBase: This is the AOE of the central bolt of the //
// ability which will turn units into spirits //
constant function BUSRR_MainAOEBase takes nothing returns real
return 150.
endfunction
//----------------------------------------------------------------//
// MainAoePerLevel: This is the per level counterpart of //
// MainAOEBase //
constant function BUSRR_MainAOEPerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// MiniAOEBase: This is the AOE of the smaller bolts of the //
// ability which appear around the central bolt //
constant function BUSRR_MiniAOEBase takes nothing returns real
return 75.
endfunction
//----------------------------------------------------------------//
// MiniAOEPerLevel: This is the per level counterpart of //
// MiniAOEBase //
constant function BUSRR_MiniAOEPerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// MiniCountBase: This is the amount of smaller bolts that //
// appear around the central bolt //
constant function BUSRR_MiniCountBase takes nothing returns integer
return 8
endfunction
//----------------------------------------------------------------//
// MiniCountPerLevel: This is the per level counterpart of //
// MiniCountBase //
constant function BUSRR_MiniCountPerLevel takes nothing returns integer
return 0
endfunction
//----------------------------------------------------------------//
// MainScaleBase: This is the scaling size of the main bolt //
constant function BUSRR_MainScaleBase takes nothing returns real
return 3.
endfunction
//----------------------------------------------------------------//
// MainScalePerLevel: This is the per level counterpart of //
// MainScaleBase //
constant function BUSRR_MainScalePerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// MiniScaleBase: This is the scaling size of the smaller bolts //
// that appear around the central bolt //
constant function BUSRR_MiniScaleBase takes nothing returns real
return 0.5
endfunction
//----------------------------------------------------------------//
// MiniScalePerLevel: This is the per level counterpart of //
// MiniScaleBase //
constant function BUSRR_MiniScalePerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// MainEffect: This is the pathname of the model used for the //
// central bolt //
constant function BUSRR_MainEffect takes nothing returns string
return "Abilities\\Spells\\Human\\HolyBolt\\HolyBoltSpecialArt.mdl"
endfunction
//----------------------------------------------------------------//
// MiniEffect: This is the pathname of the model used for the //
// smaller bolts //
constant function BUSRR_MiniEffect takes nothing returns string
return "war3mapImported\\LightningWrath.mdx"
endfunction
//----------------------------------------------------------------//
// FailEffect: This is the pathname of the model used when the //
// Ability fails (target moved too far away) //
constant function BUSRR_FailEffect takes nothing returns string
return "Abilities\\Spells\\Human\\Invisibility\\InvisibilityTarget.mdl"
endfunction
//----------------------------------------------------------------//
// SpiritRed: This is the red hue of spirits created by the //
// ability //
constant function BUSRR_SpiritRed takes nothing returns integer
return 255
endfunction
//----------------------------------------------------------------//
// SpiritGreen: This is the green hue of spirits created by the //
// ability //
constant function BUSRR_SpiritGreen takes nothing returns integer
return 255
endfunction
//----------------------------------------------------------------//
// SpiritBlue: This is the blue hue of spirits created by the //
// ability //
constant function BUSRR_SpiritBlue takes nothing returns integer
return 125
endfunction
//----------------------------------------------------------------//
// SpiritAlpha: This is the alpha of spirits created by the //
// ability //
constant function BUSRR_SpiritAlpha takes nothing returns integer
return 125
endfunction
//----------------------------------------------------------------//
// AscentionBase: This is the speed at which spirits travel //
// upwards //
constant function BUSRR_AscentionBase takes nothing returns real
return 5.
endfunction
//----------------------------------------------------------------//
// AscentionPerLevel: This is the per level counterpart of //
// AscentionBase //
constant function BUSRR_AscentionPerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// AscentionStart: This is the starting height of spirits when //
// they are created //
constant function BUSRR_AscentionStart takes nothing returns real
return 200.
endfunction
//----------------------------------------------------------------//
// AscentionTimeBase: This is how long a spirit ascends //
constant function BUSRR_AscentionTimeBase takes nothing returns real
return 1.
endfunction
//----------------------------------------------------------------//
// AscentionTimePerLevel: This is the per level counterpart of //
// AscentionTimeBase //
constant function BUSRR_AscentionTimePerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// EffectTime: This is how long after the effects are completed //
// that they are completely removed from the lists //
constant function BUSRR_EffectTime takes nothing returns real
return 4.0
endfunction
//----------------------------------------------------------------//
// TargetFilter: This is the target filter for units that can //
// be turned into spirits, configure this as desired (requires //
// some coding knowledge, u is the target unit, pl is the player //
// who owns the caster) //
function BUS_RTargetFilter takes unit u, player pl returns boolean
return (not(IsUnitType(u, UNIT_TYPE_DEAD)) and not(IsUnitType(u, UNIT_TYPE_STRUCTURE)) and (IsPlayerEnemy(GetOwningPlayer(u), pl)))
endfunction
//----------------------------------------------------------------//
// END OF CONFIGURATION //
//----------------------------------------------------------------//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// SoulReleaseLoop: Function used to move and handle spirits and //
// effects that are no longer in use //
////////////////////////////////////////////////////////////////////
function BUS_SoulReleaseLoop takes nothing returns nothing
local integer Node = 0
loop
set Node = udg_BUSR_PNextNode[Node]
exitwhen Node == 0
if (udg_BUSR_PCurrentAlpha[Node] <= 0) then
call RemoveUnit(udg_BUSR_PUnit[Node])
set udg_BUSR_PRecycleNodes[udg_BUSR_PRecyclableNodes] = Node
set udg_BUSR_PRecyclableNodes = udg_BUSR_PRecyclableNodes + 1
set udg_BUSR_PNextNode[udg_BUSR_PPrevNode[Node]] = udg_BUSR_PNextNode[Node]
set udg_BUSR_PPrevNode[udg_BUSR_PNextNode[Node]] = udg_BUSR_PPrevNode[Node]
if (udg_BUSR_NextNode[0] + udg_BUSR_PNextNode[0] == 0) then
call PauseTimer(udg_BUSR_Timer)
endif
else
set udg_BUSR_PCurrentAlpha[Node] = udg_BUSR_PCurrentAlpha[Node] - udg_BUSR_PAlphaReduction[Node]
call SetUnitVertexColor(udg_BUSR_PUnit[Node], BUSRR_SpiritRed(), BUSRR_SpiritGreen(), BUSRR_SpiritBlue(), udg_BUSR_PCurrentAlpha[Node])
call SetUnitFlyHeight(udg_BUSR_PUnit[Node], GetUnitFlyHeight(udg_BUSR_PUnit[Node]) + udg_BUSR_PSpeed[Node], 0.)
endif
endloop
set Node = 0
loop
set Node = udg_BUSR_NextNode[Node]
exitwhen Node == 0
if (udg_BUSR_Time[Node] < 0) then
call RemoveUnit(udg_BUSR_Unit[Node])
set udg_BUSR_RecycleNodes[udg_BUSR_RecyclableNodes] = Node
set udg_BUSR_RecyclableNodes = udg_BUSR_RecyclableNodes + 1
set udg_BUSR_NextNode[udg_BUSR_PrevNode[Node]] = udg_BUSR_NextNode[Node]
set udg_BUSR_PrevNode[udg_BUSR_NextNode[Node]] = udg_BUSR_PrevNode[Node]
if (udg_BUSR_NextNode[0] + udg_BUSR_PNextNode[0] == 0) then
call PauseTimer(udg_BUSR_Timer)
endif
else
set udg_BUSR_Time[Node] = udg_BUSR_Time[Node] - BUSRR_TimerSpeed()
endif
endloop
endfunction
////////////////////////////////////////////////////////////////////
// SoulReleaseSpawn: The main function, used to kill units, //
// create spirits and effects and set up the loop //
////////////////////////////////////////////////////////////////////
function BUS_SoulReleaseSpawn takes real x, real y, real AOE, real Scale, real Speed, real Time, player pl, string m returns nothing
local integer Node
local unit u
if (udg_BUSR_RecyclableNodes == 0) then
set udg_BUSR_NodeNumber = udg_BUSR_NodeNumber + 1
set Node = udg_BUSR_NodeNumber
else
set udg_BUSR_RecyclableNodes = udg_BUSR_RecyclableNodes - 1
set Node = udg_BUSR_RecycleNodes[udg_BUSR_RecyclableNodes]
endif
set udg_BUSR_NextNode[Node] = 0
set udg_BUSR_NextNode[udg_BUSR_PrevNode[0]] = Node
set udg_BUSR_PrevNode[Node] = udg_BUSR_PrevNode[0]
set udg_BUSR_PrevNode[0] = Node
if (udg_BUSR_PrevNode[Node] + udg_BUSR_PPrevNode[0] == 0) then
call TimerStart(udg_BUSR_Timer, BUSRR_TimerSpeed(), true, function BUS_SoulReleaseLoop)
endif
set udg_BUSR_Unit[Node] = CreateUnit(BUSCR_DummyPlayer(), BUSRR_DummyId(), x, y, 0.)
call SetUnitScale(udg_BUSR_Unit[Node], Scale, 0., 0.)
call DestroyEffect(AddSpecialEffectTarget(m, udg_BUSR_Unit[Node], BUSRR_AttachmentPoint()))
set udg_BUSR_Time[Node] = BUSRR_EffectTime()
call GroupEnumUnitsInRange(udg_BUSR_UnitGroup, x, y, AOE, null)
loop
set u = FirstOfGroup(udg_BUSR_UnitGroup)
exitwhen u == null
call GroupRemoveUnit(udg_BUSR_UnitGroup, u)
if (BUS_RTargetFilter(u, pl)) then
if (udg_BUSR_PRecyclableNodes == 0) then
set udg_BUSR_PNodeNumber = udg_BUSR_PNodeNumber + 1
set Node = udg_BUSR_PNodeNumber
else
set udg_BUSR_PRecyclableNodes = udg_BUSR_PRecyclableNodes - 1
set Node = udg_BUSR_PRecycleNodes[udg_BUSR_PRecyclableNodes]
endif
set udg_BUSR_PNextNode[Node] = 0
set udg_BUSR_PNextNode[udg_BUSR_PPrevNode[0]] = Node
set udg_BUSR_PPrevNode[Node] = udg_BUSR_PPrevNode[0]
set udg_BUSR_PPrevNode[0] = Node
call KillUnit(u)
set x = GetUnitX(u)
set y = GetUnitY(u)
set udg_BUSR_PUnit[Node] = CreateUnit(Player(15), GetUnitTypeId(u), x, y, GetUnitFacing(u))
call SetUnitColor(udg_BUSR_PUnit[Node], GetPlayerColor(GetOwningPlayer(u)))
call SetUnitVertexColor(udg_BUSR_PUnit[Node], BUSRR_SpiritRed(), BUSRR_SpiritGreen(), BUSRR_SpiritBlue(), BUSRR_SpiritAlpha())
call SetUnitPathing(udg_BUSR_PUnit[Node], false)
if UnitAddAbility(udg_BUSR_PUnit[Node], 'Amrf') and UnitRemoveAbility(udg_BUSR_PUnit[Node], 'Amrf') then
endif
call PauseUnit(udg_BUSR_PUnit[Node], true)
call UnitAddAbility(udg_BUSR_PUnit[Node], BUSRR_InvulAbility())
call SetUnitFlyHeight(udg_BUSR_PUnit[Node], BUSRR_AscentionStart(), 0.)
set udg_BUSR_PSpeed[Node] = Speed
set udg_BUSR_PCurrentAlpha[Node] = BUSRR_SpiritAlpha()
set udg_BUSR_PAlphaReduction[Node] = R2I((I2R(BUSRR_SpiritAlpha()) / Time) * BUSRR_TimerSpeed())
endif
endloop
endfunction
////////////////////////////////////////////////////////////////////
// SoulReleaseEvent: Function used to determine the points of //
// impact. Runs when the channeling is finished and handles //
// all calculations //
////////////////////////////////////////////////////////////////////
function BUS_SoulReleaseEvent takes nothing returns boolean
local real rLevel = GetUnitAbilityLevel(udg_BUS_Unit, BUSRR_Ability())
local real x = GetUnitX(udg_BUS_Unit)
local real y = GetUnitY(udg_BUS_Unit)
local real x2 = GetUnitX(udg_BUS_Target)
local real y2 = GetUnitY(udg_BUS_Target)
local real TempReal
local real TempReal2
local real TempReal3
local real TempReal4
local real TempReal5
local real TempReal6
local real Angle
local integer iLoop
local integer TempInt
local player pl
if (SquareRoot((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y)) <= BUSRR_HitDistanceBase() + (rLevel * BUSRR_HitDistancePerLevel())) then
set pl = GetOwningPlayer(udg_BUS_Unit)
set TempReal = BUSRR_MainAOEBase() + (rLevel * BUSRR_MainAOEPerLevel())
set TempReal2 = BUSRR_MainScaleBase() + (rLevel * BUSRR_MainScalePerLevel())
set TempReal3 = BUSRR_AscentionBase() + (rLevel * BUSRR_AscentionPerLevel())
set TempReal4 = BUSRR_AscentionTimeBase() + (rLevel * BUSRR_AscentionTimePerLevel())
call BUS_SoulReleaseSpawn(x2, y2, TempReal, TempReal2, TempReal3, TempReal4, pl, BUSRR_MainEffect())
set TempReal2 = BUSRR_MiniAOEBase() + (rLevel * BUSRR_MiniAOEPerLevel())
set TempReal6 = TempReal + TempReal2
set TempReal = BUSRR_MiniScaleBase() + (rLevel *BUSRR_MiniScalePerLevel())
set TempInt = BUSRR_MiniCountBase() + (R2I(rLevel) * BUSRR_MiniCountPerLevel())
set TempReal5 = 360 / I2R(TempInt)
set Angle = 0
set iLoop = 0
loop
set iLoop = iLoop + 1
exitwhen iLoop > TempInt
set Angle = Angle + TempReal5
set x = x2 + TempReal6 * Cos(Angle * bj_DEGTORAD)
set y = y2 + TempReal6 * Sin(Angle * bj_DEGTORAD)
call BUS_SoulReleaseSpawn(x, y, TempReal2, TempReal, TempReal3, TempReal4, pl, BUSRR_MiniEffect())
endloop
set pl = null
else
call DestroyEffect(AddSpecialEffectTarget(BUSRR_FailEffect(), udg_BUS_Unit, BUSRR_AttachmentPoint()))
endif
return false
endfunction
////////////////////////////////////////////////////////////////////
// SoulReleaseStart: Function used to set up the channeling //
// for the ability //
////////////////////////////////////////////////////////////////////
function BUS_SoulReleaseStart takes nothing returns boolean
local unit u
if (GetSpellAbilityId() == BUSRR_Ability()) then
set u = GetTriggerUnit()
call BUS_StartChannel(BUS_GetChannelByName(BUSRR_ChannelType()), u, GetSpellTargetUnit(), 0., 0., BUSRR_ChannelDurationBase() + (GetUnitAbilityLevel(u, BUSRR_Ability()) * BUSRR_ChannelDurationPerLevel()), BUSRR_Event(), BUSRR_HaveHue())
set u = null
endif
return false
endfunction
////////////////////////////////////////////////////////////////////
// InitTrig BUS Soul Release: Function used to set up the //
// event and starting functions of the ability as well as the //
// timer for the loop //
////////////////////////////////////////////////////////////////////
function InitTrig_BUS_Soul_Release takes nothing returns nothing
local trigger t = CreateTrigger()
local integer index = 0
loop
call TriggerRegisterPlayerUnitEvent(t, Player(index),EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
set index = index + 1
exitwhen index >= bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddCondition(t, Condition(function BUS_SoulReleaseStart))
set t = CreateTrigger()
call TriggerRegisterVariableEvent(t, "udg_BUSC_Event", EQUAL, BUSRR_Event())
call TriggerAddCondition(t, Condition(function BUS_SoulReleaseEvent))
set udg_BUSS_Timer = CreateTimer()
endfunction
////////////////////////////////////////////////////////////////////
// End of the spell //
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Boss Ultimate Spellpack Scathe V1.00 //
// Author: Tank-Commander //
// Purpose: Boss Strong Knockback/High Damage Laser //
// Requires: Dummy.mdl, BUS Channel, BUS Knockback //
// //
// Notes: //
// - Read the readme before you try modifying the config //
// - Use the "Helpful files" to help you import the system //
// //
// Credits: //
// - (Dummy.mdl) Vexorian //
// - (OrbitalRay.mdl) Callahan //
// //
// Optimum User: Any //
// //
// If you have used this spellpack in your map, you are required //
// to give credits to Tank-Commander for the creation of it //
// If you would like to use snippets of code from this for //
// whatever, getting permission and crediting the source/linking //
// would be much appreciated. //
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// README: //
// Before modifying this spell a few things need to be //
// understood and read, this is one of those things, while //
// most modification can be considered intuitive, it still //
// helps to read through these intstructions, as they will //
// inform you about how to configure this spell to your //
// desire. //
//----------------------------------------------------------------//
// Initial importing: The variable creator trigger can be //
// imported first and if you have the correct settings (file, //
// preferences, General, automatically create unknown variables //
// checked, then when you paste in the variable creator it //
// will automatically give you all the variables you need for //
// this spell //
// //
// While the remaining object editor based data is not required //
// to function (provided they're replaced with equivelents) //
// it's recommended that they are also imported, if their data //
// value are not the same as listed in the configuration, those //
// configurables will need to be changed to work correctly //
//----------------------------------------------------------------//
// CONFIGURABLE INFORMATION/HELP: //
// //
// - Viewing data values: To see data values in the editor you //
// need to press Ctrl + D, to shift back to normal viewing //
// press it again //
// //
// - Effects: Pathnames for effects used in the spells should //
// have two "\"s throughout or the effect will not work (the //
// WE progress bar will not go away when saving, however if //
// fixed afterwards the save will still work, but the progress //
// bar will still remain until the WE is closed) //
// e.g. "units\\human\\Footman\\Footman" //
// //
// - Effect Scaling: Some effects have scale values below them //
// the scale determines the size of the effect and is expressed //
// as a real percentage (1.00 = 100%) //
// //
// - Removing Effects: to remove an effect you don't want from //
// the ability, set the model path to that of Dummy.mdl //
// //
// - Base and Per Values: Most configurables have a base and per //
// value, Base values are what a value is set to regardless of //
// other factors. Per values are what a value is set to based on //
// what the per value is the formula for calculating the result //
// is as follows: //
// - BaseValue + (Factor * PerValue) //
// //
// - Timer: Some configurables have PerSecond values, the code //
// automatically accounts for changes to the timer as to //
// maintain consistency with what the user has chosen //
// All times in the system are expressions of seconds //
// //
// - AttackTypes: This should match the Damage Type of the //
// ability, though it can be something else if you wish //
// //
// - DamageTypes: This changes the damage multiplyer vs. enemy //
// armour types, note that by default the damage filters //
// exclude magic immune units so changing this from MAGIC //
// damage will not make them take damage //
// //
// - WeaponTypes: Generally don't need to be used, should only //
// not be null if you particularly wish or need to use them //
// //
//----------------------------------------------------------------//
// TimerSpeed: This is the amount of time in seconds between //
// each iteration of the Scathe Loop function //
constant function BUSSR_TimerSpeed takes nothing returns real
return 0.031250000
endfunction
//----------------------------------------------------------------//
// Ability: This is the AbilityId that is used as the dummy //
// ability used for the scathe spell //
constant function BUSSR_Ability takes nothing returns integer
return 'A018'
endfunction
//----------------------------------------------------------------//
// DummyId: This is the UnitId that is used to create effects //
// It is recommended this unit use Dummy.mdl for its model for //
// optimal usage //
constant function BUSSR_DummyId takes nothing returns integer
return 'u005'
endfunction
//----------------------------------------------------------------//
// Event: This is the value of BUS_Event that it will be set to //
// when the channeling ends, this should be unique to each //
// ability which uses the channel system //
constant function BUSSR_Event takes nothing returns integer
return 2
endfunction
//----------------------------------------------------------------//
// Order: This is the order ID of the ability used to make sure //
// that the unit is still channeling the ability //
constant function BUSSR_Order takes nothing returns integer
return 852187
endfunction
//----------------------------------------------------------------//
// AttachmentPoint: This is the point that effects are attached //
// to on units and dummy units //
constant function BUSSR_AttachmentPoint takes nothing returns string
return "origin"
endfunction
//----------------------------------------------------------------//
// HaveHue; This determines whether or not during channeling //
// the hue of the caster changes throughout //
constant function BUSSR_HaveHue takes nothing returns boolean
return true
endfunction
//----------------------------------------------------------------//
// ChannelType: This is the name of the channel type used by //
// this ability (it should match the name of the channel type) //
constant function BUSSR_ChannelType takes nothing returns string
return "Arcane charge"
endfunction
//----------------------------------------------------------------//
// HealthDamageBase: This is the damage dealt by the laser to //
// enemy units //
constant function BUSSR_HealthDamageBase takes nothing returns real
return 300.0
endfunction
//----------------------------------------------------------------//
// HealthDamagePerLevel: This is the per level counterpart of //
// HealthDamageBase //
constant function BUSSR_HealthDamagePerLevel takes nothing returns real
return 0.00
endfunction
//----------------------------------------------------------------//
// ManaDamageBase: This is the mana damage dealt by the laser //
// to enemy units //
constant function BUSSR_ManaDamageBase takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// ManaDamagePerLevel: This is the per level counterpart of //
// ManaDamageBase //
constant function BUSSR_ManaDamagePerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// ChannelDurationBase: This is the duration of the channeling //
// used by the spell //
constant function BUSSR_ChannelDurationBase takes nothing returns real
return 2.5
endfunction
//----------------------------------------------------------------//
// ChannelDurationPerLevel: This is the per level counterpart of //
// ChannelDurationBase //
constant function BUSSR_ChannelDurationPerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// AOEBase: This is the AOE of the laser (width of the laser) //
constant function BUSSR_AOEBase takes nothing returns real
return 150.
endfunction
//----------------------------------------------------------------//
// AOEPerLevel: This is the per level counterpart of AOEBASE //
constant function BUSSR_AOEPerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// RangeBase: This is the maximum distance of the laser //
constant function BUSSR_RangeBase takes nothing returns real
return 1000.
endfunction
//----------------------------------------------------------------//
// RangePerLevel: This is the per level counterpart of RangeBase //
constant function BUSSR_RangePerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// ForceBase: This is the amount of force the laser exerts on //
// units which are hit by it //
constant function BUSSR_ForceBase takes nothing returns real
return 60.
endfunction
//----------------------------------------------------------------//
// ForcePerLevel: This is the per level counterpart of ForceBase //
constant function BUSSR_ForcePerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// EndChannelTimeBase: This is the time after channeling is //
// completed that the laser is created (this value + the Angle //
// delay == how long after channeling the laser fires) //
constant function BUSSR_EndChannelTimeBase takes nothing returns real
return 0.75
endfunction
//----------------------------------------------------------------//
// EndChannelTimePerLevel: This is the per level counterpart //
// EndChannelTimeBase //
constant function BUSSR_EndChannelTimePerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// EndChannelAngleDelay: This is the time after being created //
// that the laser fires //
constant function BUSSR_EndChannelAngleDelay takes nothing returns real
return 0.50
endfunction
//----------------------------------------------------------------//
// EffectRemove: This is how long after an effect has been //
// completed that it is removed //
constant function BUSSR_EffectRemove takes nothing returns real
return 4.00
endfunction
//----------------------------------------------------------------//
// PointerScaleBase: This is the scale of the effect which //
// denotes the angle of fire of the laser //
constant function BUSSR_PointerScaleBase takes nothing returns real
return 2.
endfunction
//----------------------------------------------------------------//
// PointerScalePerLevel: This is the per level counterpart //
// PointerScaleBase //
constant function BUSSR_PointerScalePerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// LaserScaleBase: This is the scaling size of the laser //
constant function BUSSR_LaserScaleBase takes nothing returns real
return 1.50
endfunction
//----------------------------------------------------------------//
// LaserScalePerLevel: This is the per level counterpart of //
// LaserScaleBase //
constant function BUSSR_LaserScalePerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// OffsetBase: This is the offset from the casting unit that all //
// laser effects are created at //
constant function BUSSR_OffsetBase takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// OffsetPerLevel: This is the per level counterpart of //
// OffsetBase //
constant function BUSSR_OffsetPerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// GroundHeightOffset: This is the z offset lasers are created //
// at when the spell is cast by a ground unit //
constant function BUSSR_GroundHeightOffset takes nothing returns real
return 200.
endfunction
//----------------------------------------------------------------//
// PointerEffect: This is the pathname of the effect used to //
// denote the direction of the laser //
constant function BUSSR_PointerEffect takes nothing returns string
return "Abilities\\Spells\\Orc\\LightningShield\\LightningShieldTarget.mdl"
endfunction
//----------------------------------------------------------------//
// LaserEffect: This is the pathname of the effect used to //
// denote the laser //
constant function BUSSR_LaserEffect takes nothing returns string
return "war3mapImported\\OrbitalRay.mdx"
endfunction
//----------------------------------------------------------------//
// UnitDamageEffect: This is the pathname of the effect used to //
// denote a unit being damaged //
constant function BUSSR_UnitDamageEffect takes nothing returns string
return "Objects\\Spawnmodels\\NightElf\\NEDeathSmall\\NEDeathSmall.mdl"
endfunction
//----------------------------------------------------------------//
// GroundDamageEffect: This is the pathname of the effect used //
// to mark where the laser hits the ground //
constant function BUSSR_GroundDamageEffect takes nothing returns string
return "Abilities\\Spells\\Human\\Thunderclap\\ThunderClapCaster.mdl"
endfunction
//----------------------------------------------------------------//
// AttackType: This is the attacktype used by the spell //
constant function BUSSR_AttackType takes nothing returns attacktype
return ATTACK_TYPE_MAGIC
endfunction
//----------------------------------------------------------------//
// DamageType: This is the damagetype used by the spell //
constant function BUSSR_DamageType takes nothing returns damagetype
return DAMAGE_TYPE_MAGIC
endfunction
//----------------------------------------------------------------//
// WeaponType: This is the weapontype used by the spell //
constant function BUSSR_WeaponType takes nothing returns weapontype
return null
endfunction
//----------------------------------------------------------------//
// TargetFilter: This is the target filter for units that can //
// be turned into spirits, configure this as desired (requires //
// some coding knowledge, u is the target unit, Node is the //
// index of the casting unit //
function BUS_STargetFilter takes unit u, integer Node returns boolean
return (not(IsUnitType(u, UNIT_TYPE_DEAD)) and not(IsUnitType(u, UNIT_TYPE_STRUCTURE)) and (IsPlayerEnemy(GetOwningPlayer(u), udg_BUSS_Owner[Node])))
endfunction
//----------------------------------------------------------------//
// END OF CONFIGURATION //
//----------------------------------------------------------------//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function used to prevent two casts of the same channel being //
// done simultaneously //
////////////////////////////////////////////////////////////////////
function BUS_CheckScathe takes unit u returns integer
local integer Node = 0
loop
set Node = udg_BUSS_NextNode[Node]
exitwhen (udg_BUSS_Unit[Node] == u) or (Node == 0)
endloop
return Node
endfunction
////////////////////////////////////////////////////////////////////
// ScatheLoop: The main function used to make sure the caster is //
// still channeling the ability, fire the laser and handle all //
// effects used by the ability //
////////////////////////////////////////////////////////////////////
function BUS_ScatheLoop takes nothing returns nothing
local integer Node = 0
local integer TempNode = 0
local real TempRealX
local real TempRealY
local real TempRealZ
local real TempRealMax
local real x
local real y
local real z
local real dx
local real dy
local real Angle
local real Angle2
local unit TempUnit
local boolean TempBoolean
loop
set Node = udg_BUSS_NextNode[Node]
exitwhen Node == 0
if (GetUnitCurrentOrder(udg_BUSS_Unit[Node]) == BUSSR_Order()) and not(udg_BUSS_Cancel[Node]) then
if (udg_BUSS_EndChannelTime[Node] < 0) and (udg_BUSS_Activate[Node]) then
set udg_BUSS_Activate[Node] = false
set udg_BUSS_EndDelay[Node] = BUSSR_EndChannelAngleDelay()
set udg_BUSS_EffectMade[Node] = true
if (udg_BUSS_PRecyclableNodes == 0) then
set udg_BUSS_PNodeNumber = udg_BUSS_PNodeNumber + 1
set TempNode = udg_BUSS_PNodeNumber
else
set udg_BUSS_PRecyclableNodes = udg_BUSS_PRecyclableNodes - 1
set TempNode = udg_BUSS_PRecycleNodes[udg_BUSS_PRecyclableNodes]
endif
set udg_BUSS_PNextNode[TempNode] = 0
set udg_BUSS_PNextNode[udg_BUSS_PPrevNode[0]] = TempNode
set udg_BUSS_PPrevNode[TempNode] = udg_BUSS_PPrevNode[0]
set udg_BUSS_PPrevNode[0] = TempNode
set udg_BUSS_PRemove[TempNode] = false
set udg_BUSS_PCaster[TempNode] = udg_BUSS_Unit[Node]
set udg_BUSS_PUnit[TempNode] = CreateUnit(BUSCR_DummyPlayer(), BUSSR_DummyId(),udg_BUSS_PX[Node],udg_BUSS_PY[Node], udg_BUSS_Angle[Node])
if UnitAddAbility(udg_BUSS_PUnit[TempNode], 'Amrf') and UnitRemoveAbility(udg_BUSS_PUnit[TempNode], 'Amrf') then
endif
call SetUnitScale(udg_BUSS_PUnit[TempNode], udg_BUSS_LaserScale[Node], 0.00, 0.00)
call SetUnitAnimationByIndex(udg_BUSS_PUnit[TempNode], udg_BUSS_PAnimationIndex[Node])
set udg_BUSS_PCurrentEffect[TempNode] = null
call SetUnitFlyHeight(udg_BUSS_PUnit[TempNode], udg_BUSS_PZ[Node] - BUS_GetZ(udg_BUSS_PX[Node], udg_BUSS_PY[Node]), 0.00)
else
set udg_BUSS_EndChannelTime[Node] = udg_BUSS_EndChannelTime[Node] - BUSSR_TimerSpeed()
endif
if (udg_BUSS_EndDelay[Node] < 0) and (not(udg_BUSS_Activate[Node])) and (udg_BUSS_EffectMade[Node]) then
set TempNode = 0
loop
set TempNode = udg_BUSS_PNextNode[TempNode]
exitwhen TempNode == 0
if (udg_BUSS_PCurrentEffect[TempNode] == null) and (udg_BUSS_PCaster[TempNode] == udg_BUSS_Unit[Node]) then
set udg_BUSS_PCurrentEffect[TempNode] = AddSpecialEffectTarget(BUSSR_LaserEffect(), udg_BUSS_PUnit[TempNode], BUSSR_AttachmentPoint())
set udg_BUSS_EffectMade[Node] = false
endif
endloop
set TempRealX = udg_BUSS_PX[Node]
set TempRealY = udg_BUSS_PY[Node]
set TempRealZ = udg_BUSS_PZ[Node]
set TempRealMax = 0.
loop
call GroupEnumUnitsInRange(udg_BUSS_UnitGroup, TempRealX, TempRealY, udg_BUSS_AOE[Node], null)
loop
set TempUnit = FirstOfGroup(udg_BUSS_UnitGroup)
exitwhen TempUnit == null
set x = GetUnitX(TempUnit)
set y = GetUnitY(TempUnit)
set z = GetUnitFlyHeight(TempUnit) + BUS_GetZ(x,y)
if (BUS_STargetFilter(TempUnit, Node)) and (SquareRoot((TempRealX - x) * (TempRealX - x) + (TempRealY - y) * (TempRealY - y) + (TempRealZ - z) * (TempRealZ - z)) < udg_BUSS_AOE[Node]) then
call UnitDamageTarget(udg_BUSS_Unit[Node], TempUnit, udg_BUSS_HealthDamage[Node], false, false, BUSSR_AttackType(), BUSSR_DamageType(), BUSSR_WeaponType())
call SetUnitState(TempUnit, UNIT_STATE_MANA, GetUnitState(TempUnit, UNIT_STATE_MANA) - udg_BUSS_ManaDamage[Node])
call DestroyEffect(AddSpecialEffectTarget(BUSSR_UnitDamageEffect(), TempUnit, BUSSR_AttachmentPoint()))
call BUS_StartKnockback(TempUnit, udg_BUSS_Force[Node], x, udg_BUSS_PX[Node], y, udg_BUSS_PY[Node], z, udg_BUSS_PZ[Node])
endif
call GroupRemoveUnit(udg_BUSS_UnitGroup, TempUnit)
endloop
exitwhen ((TempRealMax > udg_BUSS_Range[Node]) or (TempRealZ < BUS_GetZ(TempRealX, TempRealY)))
set TempRealX = TempRealX + (udg_BUSS_DX[Node])
set TempRealY = TempRealY + (udg_BUSS_DY[Node])
set TempRealZ = TempRealZ + (udg_BUSS_DZ[Node])
set TempRealMax = TempRealMax + udg_BUSS_AOE[Node]
endloop
if (TempRealZ < BUS_GetZ(TempRealX, TempRealY)) then
call DestroyEffect(AddSpecialEffect(BUSSR_GroundDamageEffect(), TempRealX, TempRealY))
endif
else
set udg_BUSS_EndDelay[Node] = udg_BUSS_EndDelay[Node] - BUSSR_TimerSpeed()
endif
else
set TempNode = 0
loop
set TempNode = udg_BUSS_PNextNode[TempNode]
exitwhen TempNode == 0
if (udg_BUSS_PCaster[TempNode] == udg_BUSS_Unit[Node]) then
if not(udg_BUSS_PCurrentEffect[TempNode] == null) then
call DestroyEffect(udg_BUSS_PCurrentEffect[TempNode])
endif
set udg_BUSS_PRemove[TempNode] = true
set udg_BUSS_PTimer[TempNode] = BUSSR_EffectRemove()
endif
endloop
set udg_BUSS_RecycleNodes[udg_BUSS_RecyclableNodes] = Node
set udg_BUSS_RecyclableNodes = udg_BUSS_RecyclableNodes + 1
set udg_BUSS_NextNode[udg_BUSS_PrevNode[Node]] = udg_BUSS_NextNode[Node]
set udg_BUSS_PrevNode[udg_BUSS_NextNode[Node]] = udg_BUSS_PrevNode[Node]
if (udg_BUSS_NextNode[0] + udg_BUSS_PNextNode[0] == 0) then
call PauseTimer(udg_BUSS_Timer)
endif
endif
endloop
set TempNode = 0
loop
set TempNode = udg_BUSS_PNextNode[TempNode]
exitwhen TempNode == 0
if (udg_BUSS_PRemove[TempNode]) then
if (udg_BUSS_PTimer[TempNode] < 0) then
call RemoveUnit(udg_BUSS_PUnit[TempNode])
set udg_BUSS_PRecycleNodes[udg_BUSS_PRecyclableNodes] = TempNode
set udg_BUSS_PRecyclableNodes = udg_BUSS_PRecyclableNodes + 1
set udg_BUSS_PNextNode[udg_BUSS_PPrevNode[TempNode]] = udg_BUSS_PNextNode[TempNode]
set udg_BUSS_PPrevNode[udg_BUSS_PNextNode[TempNode]] = udg_BUSS_PPrevNode[TempNode]
if (udg_BUSS_NextNode[0] + udg_BUSS_PNextNode[0] == 0) then
call PauseTimer(udg_BUSS_Timer)
endif
else
set udg_BUSS_PTimer[TempNode] = udg_BUSS_PTimer[TempNode] - BUSSR_TimerSpeed()
endif
endif
endloop
endfunction
////////////////////////////////////////////////////////////////////
// ScatheEvent: Function used to set up all the data and effects //
// that are used in the loop. Activates when the channeling is //
// completed //
////////////////////////////////////////////////////////////////////
function BUS_ScatheEvent takes nothing returns boolean
local real rLevel = GetUnitAbilityLevel(udg_BUS_Unit, BUSSR_Ability())
local integer Node
local integer TempNode
local real x = GetUnitX(udg_BUS_Unit)
local real y = GetUnitY(udg_BUS_Unit)
local real x2 = GetUnitX(udg_BUS_Target)
local real y2 = GetUnitY(udg_BUS_Target)
local real z = BUS_GetZ(x,y) + GetUnitFlyHeight(udg_BUS_Unit)
local real z2 = BUS_GetZ(x2, y2) + GetUnitFlyHeight(udg_BUS_Target)
local real Angle
local real TempReal = BUSSR_OffsetBase() + (rLevel * BUSSR_OffsetPerLevel())
if (IsUnitType(udg_BUS_Unit, UNIT_TYPE_GROUND)) then
set z = z + BUSSR_GroundHeightOffset()
endif
if (udg_BUSS_RecyclableNodes == 0) then
set udg_BUSS_NodeNumber = udg_BUSS_NodeNumber + 1
set Node = udg_BUSS_NodeNumber
else
set udg_BUSS_RecyclableNodes = udg_BUSS_RecyclableNodes - 1
set Node = udg_BUSS_RecycleNodes[udg_BUSS_RecyclableNodes]
endif
set udg_BUSS_NextNode[Node] = 0
set udg_BUSS_NextNode[udg_BUSS_PrevNode[0]] = Node
set udg_BUSS_PrevNode[Node] = udg_BUSS_PrevNode[0]
set udg_BUSS_PrevNode[0] = Node
set udg_BUSS_Unit[Node] = udg_BUS_Unit
set udg_BUSS_Owner[Node] = GetOwningPlayer(udg_BUSS_Unit[Node])
set udg_BUSS_HealthDamage[Node] = BUSSR_HealthDamageBase() + (rLevel * BUSSR_HealthDamagePerLevel())
set udg_BUSS_ManaDamage[Node] = BUSSR_ManaDamageBase() + (rLevel * BUSSR_ManaDamagePerLevel())
set udg_BUSS_AOE[Node] = BUSSR_AOEBase() + (rLevel * BUSSR_AOEPerLevel())
set udg_BUSS_Range[Node] = BUSSR_RangeBase() + (rLevel * BUSSR_RangePerLevel())
set udg_BUSS_Force[Node] = BUSSR_ForceBase() + (rLevel * BUSSR_ForcePerLevel())
set udg_BUSS_EndChannelTime[Node] = BUSSR_EndChannelTimeBase() + (rLevel * BUSSR_EndChannelTimePerLevel())
set udg_BUSS_Activate[Node] = true
set udg_BUSS_Cancel[Node] = false
set udg_BUSS_DY[Node] = y2 - y
set udg_BUSS_DX[Node] = x2 - x
set Angle = Atan2(udg_BUSS_DY[Node], udg_BUSS_DX[Node])
set udg_BUSS_DZ[Node] = Atan2(z2 - z, SquareRoot((udg_BUSS_DX[Node] * udg_BUSS_DX[Node]) + (udg_BUSS_DY[Node] * udg_BUSS_DY[Node])))
set udg_BUSS_PZ[Node] = z + (TempReal * Sin(udg_BUSS_DZ[Node]))
set udg_BUSS_PX[Node] = x + (TempReal * Cos(Angle) * Cos(udg_BUSS_DZ[Node]))
set udg_BUSS_PY[Node] = y + (TempReal * Sin(Angle) * Cos(udg_BUSS_DZ[Node]))
if (udg_BUSS_PrevNode[Node] + udg_BUSS_PPrevNode[0] == 0) then
call TimerStart(udg_BUSS_Timer, BUSSR_TimerSpeed(), true, function BUS_ScatheLoop)
endif
if (udg_BUSS_PRecyclableNodes == 0) then
set udg_BUSS_PNodeNumber = udg_BUSS_PNodeNumber + 1
set TempNode = udg_BUSS_PNodeNumber
else
set udg_BUSS_PRecyclableNodes = udg_BUSS_PRecyclableNodes - 1
set TempNode = udg_BUSS_PRecycleNodes[udg_BUSS_PRecyclableNodes]
endif
set udg_BUSS_PNextNode[TempNode] = 0
set udg_BUSS_PNextNode[udg_BUSS_PPrevNode[0]] = TempNode
set udg_BUSS_PPrevNode[TempNode] = udg_BUSS_PPrevNode[0]
set udg_BUSS_PPrevNode[0] = TempNode
set udg_BUSS_Angle[Node] = Angle * bj_RADTODEG
set udg_BUSS_PRemove[TempNode] = false
set udg_BUSS_PCaster[TempNode] = udg_BUS_Unit
set udg_BUSS_PUnit[TempNode] = CreateUnit(BUSCR_DummyPlayer(), BUSSR_DummyId(),udg_BUSS_PX[Node],udg_BUSS_PY[Node], udg_BUSS_Angle[Node])
if UnitAddAbility(udg_BUSS_PUnit[TempNode], 'Amrf') and UnitRemoveAbility(udg_BUSS_PUnit[TempNode], 'Amrf') then
endif
set TempReal = z2 - z
if (TempReal < 0) then
set udg_BUSS_PScale[Node] = -1 * (BUSSR_PointerScaleBase() + (rLevel * BUSSR_PointerScalePerLevel()))
set udg_BUSS_LaserScale[Node] = -1 * (BUSSR_LaserScaleBase() + (rLevel * BUSSR_LaserScalePerLevel()))
set udg_BUSS_PAnimationIndex[Node] = R2I(Atan2((TempReal), SquareRoot((udg_BUSS_DX[Node] * udg_BUSS_DX[Node]) + (udg_BUSS_DY[Node] * udg_BUSS_DY[Node]))) * bj_RADTODEG + 0.5) + 180
else
set udg_BUSS_PScale[Node] = (BUSSR_PointerScaleBase() + (rLevel * BUSSR_PointerScalePerLevel()))
set udg_BUSS_LaserScale[Node] = (BUSSR_LaserScaleBase() + (rLevel * BUSSR_LaserScalePerLevel()))
set udg_BUSS_PAnimationIndex[Node] = R2I(Atan2((TempReal), SquareRoot((udg_BUSS_DX[Node] * udg_BUSS_DX[Node]) + (udg_BUSS_DY[Node] * udg_BUSS_DY[Node]))) * bj_RADTODEG + 0.5)
endif
call SetUnitScale(udg_BUSS_PUnit[TempNode], udg_BUSS_PScale[Node], 0.00, 0.00)
call SetUnitAnimationByIndex(udg_BUSS_PUnit[TempNode], udg_BUSS_PAnimationIndex[Node])
set udg_BUSS_PCurrentEffect[TempNode] = AddSpecialEffectTarget(BUSSR_PointerEffect(), udg_BUSS_PUnit[TempNode], BUSSR_AttachmentPoint())
call SetUnitFlyHeight(udg_BUSS_PUnit[TempNode], udg_BUSS_PZ[Node] - BUS_GetZ(udg_BUSS_PX[Node], udg_BUSS_PY[Node]), 0.00)
set udg_BUSS_DX[Node] = Cos(Angle) * Cos(udg_BUSS_DZ[Node]) * udg_BUSS_AOE[Node]
set udg_BUSS_DY[Node] = Sin(Angle) * Cos(udg_BUSS_DZ[Node]) * udg_BUSS_AOE[Node]
set udg_BUSS_DZ[Node] = Sin(udg_BUSS_DZ[Node]) * udg_BUSS_AOE[Node]
return false
endfunction
////////////////////////////////////////////////////////////////////
// ScatheStart: Function used to set up the channeling for the //
// ability //
////////////////////////////////////////////////////////////////////
function BUS_ScatheStart takes nothing returns boolean
local unit u
if (GetSpellAbilityId() == BUSSR_Ability()) then
set u = GetTriggerUnit()
set udg_BUSS_Cancel[BUS_CheckScathe(u)] = true
call BUS_StartChannel(BUS_GetChannelByName(BUSSR_ChannelType()), u, GetSpellTargetUnit(), 0., 0., BUSSR_ChannelDurationBase() + (GetUnitAbilityLevel(u, BUSSR_Ability()) * BUSSR_ChannelDurationPerLevel()), BUSSR_Event(), BUSSR_HaveHue())
set u = null
endif
return false
endfunction
////////////////////////////////////////////////////////////////////
// InitTrig BUS Scathe: Function used to set up the event and //
// starting functions of the ability as well as the timer for //
// the loop //
////////////////////////////////////////////////////////////////////
function InitTrig_BUS_Scathe takes nothing returns nothing
local trigger t = CreateTrigger()
local integer index = 0
loop
call TriggerRegisterPlayerUnitEvent(t, Player(index),EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
set index = index + 1
exitwhen index >= bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddCondition(t, Condition(function BUS_ScatheStart))
set t = CreateTrigger()
call TriggerRegisterVariableEvent(t, "udg_BUSC_Event", EQUAL, BUSSR_Event())
call TriggerAddCondition(t, Condition(function BUS_ScatheEvent))
set udg_BUSS_Timer = CreateTimer()
endfunction
////////////////////////////////////////////////////////////////////
// End of the spell //
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Boss Ultimate Spellpack Sheer Force V1.00 //
// Author: Tank-Commander //
// Purpose: Boss Strong Knockback (ring out) //
// Requires: Dummy.mdl, BUS Channel, BUS Knockback //
// //
// Notes: //
// - Read the readme before you try modifying the config //
// - Use the "Helpful files" to help you import the system //
// //
// Credits: //
// - (Dummy.mdl) Vexorian //
// - (ForceField.mdl) Fingolfin //
// //
// Optimum User: Flyer (any) //
// //
// If you have used this spellpack in your map, you are required //
// to give credits to Tank-Commander for the creation of it //
// If you would like to use snippets of code from this for //
// whatever, getting permission and crediting the source/linking //
// would be much appreciated. //
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// README: //
// Before modifying this spell a few things need to be //
// understood and read, this is one of those things, while //
// most modification can be considered intuitive, it still //
// helps to read through these intstructions, as they will //
// inform you about how to configure this spell to your //
// desire. //
//----------------------------------------------------------------//
// Initial importing: The variable creator trigger can be //
// imported first and if you have the correct settings (file, //
// preferences, General, automatically create unknown variables //
// checked, then when you paste in the variable creator it //
// will automatically give you all the variables you need for //
// this spell //
// //
// While the remaining object editor based data is not required //
// to function (provided they're replaced with equivelents) //
// it's recommended that they are also imported, if their data //
// value are not the same as listed in the configuration, those //
// configurables will need to be changed to work correctly //
//----------------------------------------------------------------//
// CONFIGURABLE INFORMATION/HELP: //
// //
// - Viewing data values: To see data values in the editor you //
// need to press Ctrl + D, to shift back to normal viewing //
// press it again //
// //
// - Effects: Pathnames for effects used in the spells should //
// have two "\"s throughout or the effect will not work (the //
// WE progress bar will not go away when saving, however if //
// fixed afterwards the save will still work, but the progress //
// bar will still remain until the WE is closed) //
// e.g. "units\\human\\Footman\\Footman" //
// //
// - Effect Scaling: Some effects have scale values below them //
// the scale determines the size of the effect and is expressed //
// as a real percentage (1.00 = 100%) //
// //
// - Removing Effects: to remove an effect you don't want from //
// the ability, set the model path to that of Dummy.mdl //
// //
// - Base and Per Values: Most configurables have a base and per //
// value, Base values are what a value is set to regardless of //
// other factors. Per values are what a value is set to based on //
// what the per value is the formula for calculating the result //
// is as follows: //
// - BaseValue + (Factor * PerValue) //
// //
// - Timer: Some configurables have PerSecond values, the code //
// automatically accounts for changes to the timer as to //
// maintain consistency with what the user has chosen //
// All times in the system are expressions of seconds //
// //
// - AttackTypes: This should match the Damage Type of the //
// ability, though it can be something else if you wish //
// //
// - DamageTypes: This changes the damage multiplyer vs. enemy //
// armour types, note that by default the damage filters //
// exclude magic immune units so changing this from MAGIC //
// damage will not make them take damage //
// //
// - WeaponTypes: Generally don't need to be used, should only //
// not be null if you particularly wish or need to use them //
// //
//----------------------------------------------------------------//
// TimerSpeed: This is the amount of time in seconds between //
// each iteration of the Sheer Force Loop function //
constant function BUSFR_TimerSpeed takes nothing returns real
return 0.031250000
endfunction
//----------------------------------------------------------------//
// Ability: This is the AbilityId that is used as the dummy //
// ability used for the Sheer Force spell //
constant function BUSFR_Ability takes nothing returns integer
return 'A019'
endfunction
//----------------------------------------------------------------//
// DummyId: This is the UnitId that is used to create effects //
// It is recommended this unit use Dummy.mdl for its model for //
// optimal usage //
constant function BUSFR_DummyId takes nothing returns integer
return 'u005'
endfunction
//----------------------------------------------------------------//
// Event: This is the value of BUS_Event that it will be set to //
// when the channeling ends, this should be unique to each //
// ability which uses the channel system //
constant function BUSFR_Event takes nothing returns integer
return 3
endfunction
//----------------------------------------------------------------//
// AttachmentPoint: This is the point that effects are attached //
// to on units and dummy units //
constant function BUSFR_AttachmentPoint takes nothing returns string
return "origin"
endfunction
//----------------------------------------------------------------//
// HaveHue; This determines whether or not during channeling //
// the hue of the caster changes throughout //
constant function BUSFR_HaveHue takes nothing returns boolean
return true
endfunction
//----------------------------------------------------------------//
// ChannelType: This is the name of the channel type used by //
// this ability (it should match the name of the channel type) //
constant function BUSFR_ChannelType takes nothing returns string
return "gravity"
endfunction
//----------------------------------------------------------------//
// ChannelDurationBase: This is the duration of the channeling //
// used by the spell //
constant function BUSFR_ChannelDurationBase takes nothing returns real
return 2.
endfunction
//----------------------------------------------------------------//
// ChannelDurationPerLevel: This is the per level counterpart of //
// ChannelDurationBase //
constant function BUSFR_ChannelDurationPerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// AOEBase: This is the AOE of the ability //
constant function BUSFR_AOEBase takes nothing returns real
return 800.
endfunction
//----------------------------------------------------------------//
// AOEPerLevel: This is the per level counterpart of AOEBase //
constant function BUSFR_AOEPerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// ForceBase: This is the amount of force this ability exerts //
// on the units that are affected //
constant function BUSFR_ForceBase takes nothing returns real
return 400.
endfunction
//----------------------------------------------------------------//
// ForcePerLevel: This is the per level counterpart of ForceBase //
constant function BUSFR_ForcePerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// ForceDegradeBase: This is the change of force over distance //
// the lower the value the faster the force degrades //
constant function BUSFR_ForceDegradeBase takes nothing returns real
return 10.
endfunction
//----------------------------------------------------------------//
// ForceDegradePerLevel: This is the per level counterpart of //
// ForceDegradeBase //
constant function BUSFR_ForceDegradePerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// ForceDamageMultiplyerBase: This is the multiplyer of damage //
// in terms of Force, Force * Multiplyer = Damage //
constant function BUSFR_ForceDamageMultiplyerBase takes nothing returns real
return .01
endfunction
//----------------------------------------------------------------//
// ForceDamageMultiplyerPerLevel: This is the per level //
// counterpart of ForceDamageMultiplyerBase //
constant function BUSFR_ForceDamageMultiplyerPerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// DamageMana: This determines whether or not the same damage //
// is dealt to the units mana //
constant function BUSFR_DamageMana takes nothing returns boolean
return false
endfunction
//----------------------------------------------------------------//
// OrbStartSizeBase: This determines the start size of the orb //
// effect which marks the boundaries of the effect //
constant function BUSFR_OrbStartSizeBase takes nothing returns real
return 0.01
endfunction
//----------------------------------------------------------------//
// OrbStartSizePerLevel: This is the per level counterpart of //
// OrbStartSizeBase //
constant function BUSFR_OrbStartSizePerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// OrbEndSizeBase: This is the final size of the Orb effect //
constant function BUSFR_OrbEndSizeBase takes nothing returns real
return 1.
endfunction
//----------------------------------------------------------------//
// OrbEndSizePerLevel: This is the per level counterpart of //
// OrbEndSizeBase //
constant function BUSFR_OrbEndSizePerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// OrbTimeBase: This is how long it takes for the Orb to reach //
// its maximum size //
constant function BUSFR_OrbTimeBase takes nothing returns real
return 0.25
endfunction
//----------------------------------------------------------------//
// OrbTimePerLevel: This is the per level counterpart of //
// OrbTimeBase //
constant function BUSFR_OrbTimePerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// OrbEffect: This is the pathname of the effect used to denote //
// the boarder of the ability //
constant function BUSFR_OrbEffect takes nothing returns string
return "war3mapImported\\ForceField.mdx"
endfunction
//----------------------------------------------------------------//
// AttackType: This is the attacktype used by the spell //
constant function BUSFR_AttackType takes nothing returns attacktype
return ATTACK_TYPE_MAGIC
endfunction
//----------------------------------------------------------------//
// DamageType: This is the damagetype used by the spell //
constant function BUSFR_DamageType takes nothing returns damagetype
return DAMAGE_TYPE_MAGIC
endfunction
//----------------------------------------------------------------//
// WeaponType: This is the weapontype used by the spell //
constant function BUSFR_WeaponType takes nothing returns weapontype
return null
endfunction
//----------------------------------------------------------------//
// EffectRemove: This is how long after an effect has been //
// completed that it is removed //
constant function BUSFR_EffectRemove takes nothing returns real
return 2.00
endfunction
//----------------------------------------------------------------//
// TargetFilter: This is the target filter for units that can //
// be turned into spirits, configure this as desired (requires //
// some coding knowledge, u is the target unit, Node is the //
// index of the casting unit //
function BUS_FTargetFilter takes unit u, player pl returns boolean
return (not(IsUnitType(u, UNIT_TYPE_DEAD)) and not(IsUnitType(u, UNIT_TYPE_STRUCTURE)) and (IsPlayerEnemy(GetOwningPlayer(u), pl)))
endfunction
//----------------------------------------------------------------//
// END OF CONFIGURATION //
//----------------------------------------------------------------//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// SheerForceLoop: Function used to handle the effects of the //
// ability and recycle the ones that have been completed //
////////////////////////////////////////////////////////////////////
function BUS_SheerForceLoop takes nothing returns nothing
local integer Node = 0
loop
set Node = udg_BUSF_NextNode[Node]
exitwhen Node == 0
if (udg_BUSF_Remove[Node]) then
if (udg_BUSF_RemoveTimer[Node] <= 0) then
call RemoveUnit(udg_BUSF_Unit[Node])
set udg_BUSF_RecycleNodes[udg_BUSF_RecyclableNodes] = Node
set udg_BUSF_RecyclableNodes = udg_BUSF_RecyclableNodes + 1
set udg_BUSF_NextNode[udg_BUSF_PrevNode[Node]] = udg_BUSF_NextNode[Node]
set udg_BUSF_PrevNode[udg_BUSF_NextNode[Node]] = udg_BUSF_PrevNode[Node]
if (udg_BUSF_PrevNode[0] == 0) then
call PauseTimer(udg_BUSF_Timer)
endif
else
set udg_BUSF_RemoveTimer[Node] = udg_BUSF_RemoveTimer[Node] - BUSFR_TimerSpeed()
endif
else
set udg_BUSF_CurrentSize[Node] = udg_BUSF_CurrentSize[Node] + udg_BUSF_ScaleSpeed[Node]
set udg_BUSF_GrowthTime[Node] = udg_BUSF_GrowthTime[Node] - BUSFR_TimerSpeed()
call SetUnitScale(udg_BUSF_Unit[Node], udg_BUSF_CurrentSize[Node], 0., 0.)
if (udg_BUSF_GrowthTime[Node] <= 0) then
set udg_BUSF_Remove[Node] = true
call DestroyEffect(udg_BUSF_CurrentEffect[Node])
endif
endif
endloop
endfunction
////////////////////////////////////////////////////////////////////
// SheerForceEvent: The main function, used to start the //
// knockback of units as well as start the effects used in the //
// loop of the ability //
////////////////////////////////////////////////////////////////////
function BUS_SheerForceEvent takes nothing returns boolean
local real rLevel = GetUnitAbilityLevel(udg_BUS_Unit, BUSFR_Ability())
local real x = GetUnitX(udg_BUS_Unit)
local real y = GetUnitY(udg_BUS_Unit)
local real z = GetUnitFlyHeight(udg_BUS_Unit) + BUS_GetZ(x, y)
local real x2
local real y2
local real z2
local real TempReal = BUSFR_AOEBase() + (rLevel * BUSFR_AOEPerLevel())
local real TempReal2 = BUSFR_ForceBase() + (rLevel * BUSFR_ForcePerLevel())
local real TempReal3 = BUSFR_ForceDegradeBase() + (rLevel * BUSFR_ForceDegradePerLevel())
local real TempReal4 = BUSFR_ForceDamageMultiplyerBase() + (rLevel * BUSFR_ForceDamageMultiplyerPerLevel())
local real TempReal5
local real TempReal6
local unit u
local player pl = GetOwningPlayer(udg_BUS_Unit)
local integer Node
if (udg_BUSF_RecyclableNodes == 0) then
set udg_BUSF_NodeNumber = udg_BUSF_NodeNumber + 1
set Node = udg_BUSF_NodeNumber
else
set udg_BUSF_RecyclableNodes = udg_BUSF_RecyclableNodes - 1
set Node = udg_BUSF_RecycleNodes[udg_BUSF_RecyclableNodes]
endif
set udg_BUSF_NextNode[Node] = 0
set udg_BUSF_NextNode[udg_BUSF_PrevNode[0]] = Node
set udg_BUSF_PrevNode[Node] = udg_BUSF_PrevNode[0]
set udg_BUSF_PrevNode[0] = Node
set udg_BUSF_Unit[Node] = CreateUnit(BUSCR_DummyPlayer(), BUSFR_DummyId(), x, y, 0.)
set udg_BUSF_CurrentEffect[Node] = AddSpecialEffectTarget(BUSFR_OrbEffect(), udg_BUSF_Unit[Node], BUSFR_AttachmentPoint())
set udg_BUSF_CurrentSize[Node] = BUSFR_OrbStartSizeBase() + (rLevel * BUSFR_OrbStartSizePerLevel())
set udg_BUSF_GrowthTime[Node] = BUSFR_OrbTimeBase() + (rLevel * BUSFR_OrbTimePerLevel())
set udg_BUSF_ScaleSpeed[Node] = (((BUSFR_OrbEndSizeBase() + (rLevel * BUSFR_OrbEndSizePerLevel())) - udg_BUSF_CurrentSize[Node]) / udg_BUSF_GrowthTime[Node]) * BUSFR_TimerSpeed()
set udg_BUSF_RemoveTimer[Node] = BUSFR_EffectRemove()
set udg_BUSF_Remove[Node] = false
call SetUnitScale(udg_BUSF_Unit[Node], udg_BUSF_CurrentSize[Node], 0.,0.)
if UnitAddAbility(udg_BUSF_Unit[Node], 'Amrf') and UnitRemoveAbility(udg_BUSF_Unit[Node], 'Amrf') then
endif
call SetUnitFlyHeight(udg_BUSF_Unit[Node], z, 0.)
if (udg_BUSF_PrevNode[Node] == 0) then
call TimerStart(udg_BUSF_Timer, BUSFR_TimerSpeed(), true, function BUS_SheerForceLoop)
endif
call GroupEnumUnitsInRange(udg_BUSF_UnitGroup, x, y, TempReal, null)
loop
set u = FirstOfGroup(udg_BUSF_UnitGroup)
exitwhen u == null
call GroupRemoveUnit(udg_BUSF_UnitGroup, u)
if (BUS_FTargetFilter(u, pl)) then
set x2 = GetUnitX(u)
set y2 = GetUnitY(u)
set z2 = GetUnitFlyHeight(u) + BUS_GetZ(x2, y2)
set TempReal5 = SquareRoot((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y) + (z2 - z) * (z2 - z))
if (TempReal5 < TempReal3) then
set TempReal5 = TempReal3
endif
if (TempReal5 <= TempReal) then
set TempReal6 = (TempReal2) / (TempReal5 / TempReal3)
call UnitDamageTarget(udg_BUS_Unit, u, TempReal6 * TempReal3, false, false, BUSFR_AttackType(), BUSFR_DamageType(), BUSFR_WeaponType())
if (BUSFR_DamageMana()) then
call SetUnitState(u, UNIT_STATE_MANA, GetUnitState(u, UNIT_STATE_MANA) - (TempReal6 * TempReal3))
endif
call BUS_StartKnockback(u, TempReal6, x2, x, y2, y, z2, z)
endif
endif
endloop
set pl = null
return false
endfunction
////////////////////////////////////////////////////////////////////
// SheerForceStart: Function used to set up the channeling for //
// the ability //
////////////////////////////////////////////////////////////////////
function BUS_SheerForceStart takes nothing returns boolean
local unit u
if (GetSpellAbilityId() == BUSFR_Ability()) then
set u = GetTriggerUnit()
call BUS_StartChannel(BUS_GetChannelByName(BUSFR_ChannelType()), u, null, 0., 0., BUSFR_ChannelDurationBase() + (GetUnitAbilityLevel(u, BUSFR_Ability()) * BUSFR_ChannelDurationPerLevel()), BUSFR_Event(), BUSFR_HaveHue())
set u = null
endif
return false
endfunction
////////////////////////////////////////////////////////////////////
// InitTrig BUS Sheer Force: Function used to set up the event //
// and starting functions of the ability as well as the timer //
// for the loop //
////////////////////////////////////////////////////////////////////
function InitTrig_BUS_Sheer_Force takes nothing returns nothing
local trigger t = CreateTrigger()
local integer index = 0
loop
call TriggerRegisterPlayerUnitEvent(t, Player(index),EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
set index = index + 1
exitwhen index >= bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddCondition(t, Condition(function BUS_SheerForceStart))
set t = CreateTrigger()
call TriggerRegisterVariableEvent(t, "udg_BUSC_Event", EQUAL, BUSFR_Event())
call TriggerAddCondition(t, Condition(function BUS_SheerForceEvent))
set udg_BUSF_Timer = CreateTimer()
endfunction
////////////////////////////////////////////////////////////////////
// End of the spell //
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Boss Ultimate Spellpack Energy Spike V1.00 //
// Author: Tank-Commander //
// Purpose: Boss Huge Damage AOE strike //
// Requires: Dummy.mdl, BUS Channel //
// //
// Notes: //
// - Read the readme before you try modifying the config //
// - Use the "Helpful files" to help you import the system //
// //
// Credits: //
// - (Dummy.mdl) Vexorian //
// - (DragonBlade.mdl) HappyTauren //
// //
// Optimum User: Flyer (large) //
// //
// If you have used this spellpack in your map, you are required //
// to give credits to Tank-Commander for the creation of it //
// If you would like to use snippets of code from this for //
// whatever, getting permission and crediting the source/linking //
// would be much appreciated. //
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// README: //
// Before modifying this spell a few things need to be //
// understood and read, this is one of those things, while //
// most modification can be considered intuitive, it still //
// helps to read through these intstructions, as they will //
// inform you about how to configure this spell to your //
// desire. //
//----------------------------------------------------------------//
// Initial importing: The variable creator trigger can be //
// imported first and if you have the correct settings (file, //
// preferences, General, automatically create unknown variables //
// checked, then when you paste in the variable creator it //
// will automatically give you all the variables you need for //
// this spell //
// //
// While the remaining object editor based data is not required //
// to function (provided they're replaced with equivelents) //
// it's recommended that they are also imported, if their data //
// value are not the same as listed in the configuration, those //
// configurables will need to be changed to work correctly //
//----------------------------------------------------------------//
// CONFIGURABLE INFORMATION/HELP: //
// //
// - Viewing data values: To see data values in the editor you //
// need to press Ctrl + D, to shift back to normal viewing //
// press it again //
// //
// - Effects: Pathnames for effects used in the spells should //
// have two "\"s throughout or the effect will not work (the //
// WE progress bar will not go away when saving, however if //
// fixed afterwards the save will still work, but the progress //
// bar will still remain until the WE is closed) //
// e.g. "units\\human\\Footman\\Footman" //
// //
// - Effect Scaling: Some effects have scale values below them //
// the scale determines the size of the effect and is expressed //
// as a real percentage (1.00 = 100%) //
// //
// - Removing Effects: to remove an effect you don't want from //
// the ability, set the model path to that of Dummy.mdl //
// //
// - Base and Per Values: Most configurables have a base and per //
// value, Base values are what a value is set to regardless of //
// other factors. Per values are what a value is set to based on //
// what the per value is the formula for calculating the result //
// is as follows: //
// - BaseValue + (Factor * PerValue) //
// //
// - Timer: Some configurables have PerSecond values, the code //
// automatically accounts for changes to the timer as to //
// maintain consistency with what the user has chosen //
// All times in the system are expressions of seconds //
// //
// - AttackTypes: This should match the Damage Type of the //
// ability, though it can be something else if you wish //
// //
// - DamageTypes: This changes the damage multiplyer vs. enemy //
// armour types, note that by default the damage filters //
// exclude magic immune units so changing this from MAGIC //
// damage will not make them take damage //
// //
// - WeaponTypes: Generally don't need to be used, should only //
// not be null if you particularly wish or need to use them //
// //
//----------------------------------------------------------------//
// TimerSpeed: This is the amount of time in seconds between //
// each iteration of the Energy Spike Loop function //
constant function BUSER_TimerSpeed takes nothing returns real
return 0.031250000
endfunction
//----------------------------------------------------------------//
// Ability: This is the AbilityId that is used as the dummy //
// ability used for the Energy Spike spell //
constant function BUSER_Ability takes nothing returns integer
return 'A017'
endfunction
//----------------------------------------------------------------//
// DummyId: This is the UnitId that is used to create effects //
// It is recommended this unit use Dummy.mdl for its model for //
// optimal usage //
constant function BUSER_DummyId takes nothing returns integer
return 'u005'
endfunction
//----------------------------------------------------------------//
// Event: This is the value of BUS_Event that it will be set to //
// when the channeling ends, this should be unique to each //
// ability which uses the channel system //
constant function BUSER_Event takes nothing returns integer
return 4
endfunction
//----------------------------------------------------------------//
// Order: This is the order ID of the ability used to make sure //
// that the unit is still channeling the ability //
constant function BUSER_Order takes nothing returns integer
return 852089
endfunction
//----------------------------------------------------------------//
// AttachmentPoint: This is the point that effects are attached //
// to on units and dummy units //
constant function BUSER_AttachmentPoint takes nothing returns string
return "origin"
endfunction
//----------------------------------------------------------------//
// HaveHue; This determines whether or not during channeling //
// the hue of the caster changes throughout //
constant function BUSER_HaveHue takes nothing returns boolean
return true
endfunction
//----------------------------------------------------------------//
// ChannelType: This is the name of the channel type used by //
// this ability (it should match the name of the channel type) //
constant function BUSER_ChannelType takes nothing returns string
return "burning fury"
endfunction
//----------------------------------------------------------------//
// HealthDamageBase: This is the amount of damage the swords //
// will do to a unit per second //
constant function BUSER_HealthDamageBase takes nothing returns real
return 20.0
endfunction
//----------------------------------------------------------------//
// HealthDamagePerLevel: This is the per level counterpart of //
// HealthDamageBase //
constant function BUSER_HealthDamagePerLevel takes nothing returns real
return 0.00
endfunction
//----------------------------------------------------------------//
// ManaDamageBase: This is the amount of damage th swords will //
// to a unit's mana per second //
constant function BUSER_ManaDamageBase takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// ManaDamagePerLevel: This is the per level counterpart of //
// ManaDamageBase //
constant function BUSER_ManaDamagePerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// ChannelDurationBase: This is the duration of the channeling //
// used by the spell //
constant function BUSER_ChannelDurationBase takes nothing returns real
return 3.
endfunction
//----------------------------------------------------------------//
// ChannelDurationPerLevel: This is the per level counterpart of //
// ChannelDurationBase //
constant function BUSER_ChannelDurationPerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// AOEBase: This is the Width of the swords used to damage units //
constant function BUSER_AOEBase takes nothing returns real
return 125.
endfunction
//----------------------------------------------------------------//
// AOEPerLevel: This is the per level counterpart of AOEBase //
constant function BUSER_AOEPerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// RangeBase: This is the length of the swords used to damage //
// units //
constant function BUSER_RangeBase takes nothing returns real
return 500.
endfunction
//----------------------------------------------------------------//
// RangePerLevel: This is the per level counterpart of RangeBase //
constant function BUSER_RangePerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// OrbStartSizeBase: This is the starting size of the orb effect //
// used around the swords //
constant function BUSER_OrbStartSizeBase takes nothing returns real
return 1.
endfunction
//----------------------------------------------------------------//
// OrbStartSizePerLevel: This is the per level counterpart of //
// OrbStartSizeBase //
constant function BUSER_OrbStartSizePerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// OrbEndSizeBase: This is the ending size of the orb effect //
// used around the swords //
constant function BUSER_OrbEndSizeBase takes nothing returns real
return 5.
endfunction
//----------------------------------------------------------------//
// OrbEndSizePerLevel: This is the per level counterpart of //
// OrbEndSizeBase //
constant function BUSER_OrbEndSizePerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// OrbTimeBase: This is the length of time it takes for the Orb //
// to become full sized //
constant function BUSER_OrbTimeBase takes nothing returns real
return 0.09
endfunction
//----------------------------------------------------------------//
// OrbTimePerLevel: This is the per level counterpart of //
// OrbTimeBase //
constant function BUSER_OrbTimePerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// LaserStartSizeBase: This is the starting size of the //
// swords/lasers //
constant function BUSER_LaserStartSizeBase takes nothing returns real
return 0.01
endfunction
//----------------------------------------------------------------//
// LaserStartSizePerLevel: This is the per level counterpart of //
// LaserStartSizeBase //
constant function BUSER_LaserStartSizePerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// LaserEndSizeBase: This is the ending size of the //
// swords/lasers //
constant function BUSER_LaserEndSizeBase takes nothing returns real
return 7.
endfunction
//----------------------------------------------------------------//
// LaserEndSizePerLevel: This is the per level counterpart of //
// LaserEndSizeBase //
constant function BUSER_LaserEndSizePerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// LaserTimeBase: This is how long it takes for the //
// swords/lasers to become full sized //
constant function BUSER_LaserTimeBase takes nothing returns real
return 0.25
endfunction
//----------------------------------------------------------------//
// LaserTimePerLevel: This is the per level counterpart of //
// LaserTimeBase //
constant function BUSER_LaserTimePerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// LaserXYCountBase: This is the amount of laser sets that will //
// be made on the X and Y axis //
constant function BUSER_LaserXYCountBase takes nothing returns integer
return 8
endfunction
//----------------------------------------------------------------//
// LaserXYCountPerLevel: This is the per level counterpart of //
// LaserXYCountBase //
constant function BUSER_LaserXYCountPerLevel takes nothing returns integer
return 0
endfunction
//----------------------------------------------------------------//
// LaserZCountBase: This is the amount of lasers that are in a //
// single laser set //
constant function BUSER_LaserZCountBase takes nothing returns integer
return 5
endfunction
//----------------------------------------------------------------//
// LaserZCountPerLevel: This is the per level counterpart of //
// LaserZCountBase //
constant function BUSER_LaserZCountPerLevel takes nothing returns integer
return 0
endfunction
//----------------------------------------------------------------//
// LaserEdgeOffset: This is the ZAngle offset that the lasers //
// have (0 will mean one set points directly up and one down) //
constant function BUSER_LaserEdgeOffset takes nothing returns real
return 12.
endfunction
//----------------------------------------------------------------//
// PanningTimeBase: This is the amount of time after becoming //
// full sized that the swords/lasers begin panning //
constant function BUSER_PanningTimeBase takes nothing returns real
return 1.
endfunction
//----------------------------------------------------------------//
// PanningTimePerLevel: This is the per level counterpard of //
// PanningTimeBase //
constant function BUSER_PanningTimePerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// PanningBase: This is how fast the swords/lasers pan downwards //
// positive is a pan downward, negative is a pan upwards //
constant function BUSER_PanningBase takes nothing returns real
return 1.
endfunction
//----------------------------------------------------------------//
// PanningPerLevel: This is the per level counterpard of //
// PanningBase //
constant function BUSER_PanningPerLevel takes nothing returns real
return 0.
endfunction
//----------------------------------------------------------------//
// OrbEffect: This is the filepath of the effect used to denote //
// the orb around the swords/lasers //
constant function BUSER_OrbEffect takes nothing returns string
return "Abilities\\Spells\\Other\\ImmolationRed\\ImmolationRedTarget.mdl"
endfunction
//----------------------------------------------------------------//
// DamageEffect: This is the filepath of the effect used to //
// denote damage being dealt to units by the swords/lasers //
constant function BUSER_DamageEffect takes nothing returns string
return "Abilities\\Spells\\Other\\Incinerate\\IncinerateBuff.mdl"
endfunction
//----------------------------------------------------------------//
// LaserEffect: This is the filepath of the effect used to //
// denote the swords/lasers //
constant function BUSER_LaserEffect takes nothing returns string
return "war3mapImported\\DragonBladePlusDeathAndBirth.mdx"
endfunction
//----------------------------------------------------------------//
// EndEffect: This is the filepath of the effect used to denote //
// the spell ending //
constant function BUSER_EndEffect takes nothing returns string
return "Abilities\\Spells\\Human\\Resurrect\\ResurrectTarget.mdl"
endfunction
//----------------------------------------------------------------//
// EffectRemove: This is how long after an effect has been //
// completed that it is removed
constant function BUSER_EffectRemove takes nothing returns real
return 2.00
endfunction
//----------------------------------------------------------------//
// AttackType: This is the attacktype used by the spell //
constant function BUSER_AttackType takes nothing returns attacktype
return ATTACK_TYPE_MAGIC
endfunction
//----------------------------------------------------------------//
// DamageType: This is the damagetype used by the spell //
constant function BUSER_DamageType takes nothing returns damagetype
return DAMAGE_TYPE_MAGIC
endfunction
//----------------------------------------------------------------//
// WeaponType: This is the weapontype used by the spell // //
constant function BUSER_WeaponType takes nothing returns weapontype
return null
endfunction
//----------------------------------------------------------------//
// TargetFilter: This is the target filter for units that can //
// be turned into spirits, configure this as desired (requires //
// some coding knowledge, u is the target unit, Node is the //
// index of the casting unit //
function BUS_ETargetFilter takes unit u, integer Node returns boolean
return (not(IsUnitType(u, UNIT_TYPE_DEAD)) and not(IsUnitType(u, UNIT_TYPE_STRUCTURE)) and (IsPlayerEnemy(GetOwningPlayer(u), udg_BUSE_POwner[Node])))
endfunction
//----------------------------------------------------------------//
// END OF CONFIGURATION //
//----------------------------------------------------------------//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function used to prevent two casts of the same channel being //
// done simultaneously //
////////////////////////////////////////////////////////////////////
function BUS_CheckEnergySpike takes unit u returns integer
local integer Node = 0
loop
set Node = udg_BUSE_NextNode[Node]
exitwhen (udg_BUSE_Unit[Node] == u) or (Node == 0)
endloop
return Node
endfunction
////////////////////////////////////////////////////////////////////
// EnergySpikeLoop: The main function, used to control the angle //
// of the swords/lasers and damage units, as well as recycle //
// completed effects and make sure that the caster is still //
// channeling the ability //
////////////////////////////////////////////////////////////////////
function BUS_EnergySpikeLoop takes nothing returns nothing
local integer Node = 0
local integer TempNode = 0
local real TempReal
local real x
local real y
local real z
local real x2
local real y2
local real z2
local unit TempUnit
loop
set Node = udg_BUSE_NextNode[Node]
exitwhen Node == 0
if not(GetUnitCurrentOrder(udg_BUSE_Unit[Node]) == BUSER_Order()) or (udg_BUSE_Cancel[Node]) then
set TempNode = 0
loop
set TempNode = udg_BUSE_PNextNode[TempNode]
exitwhen TempNode == 0
if (udg_BUSE_PCaster[TempNode] == udg_BUSE_Unit[Node]) then
call DestroyEffect(udg_BUSE_PCurrentEffect[TempNode])
set udg_BUSE_PRemove[TempNode] = true
if not(udg_BUSE_PDoesPan[TempNode]) then
call DestroyEffect(AddSpecialEffectTarget(BUSER_EndEffect(), udg_BUSE_PUnit[TempNode], BUSER_AttachmentPoint()))
endif
endif
endloop
set udg_BUSE_RecycleNodes[udg_BUSE_RecyclableNodes] = Node
set udg_BUSE_RecyclableNodes = udg_BUSE_RecyclableNodes + 1
set udg_BUSE_NextNode[udg_BUSE_PrevNode[Node]] = udg_BUSE_NextNode[Node]
set udg_BUSE_PrevNode[udg_BUSE_NextNode[Node]] = udg_BUSE_PrevNode[Node]
if (udg_BUSE_PPrevNode[0] + udg_BUSE_PrevNode[0] == 0) then
call PauseTimer(udg_BUSE_Timer)
endif
endif
endloop
set Node = 0
loop
set Node = udg_BUSE_PNextNode[Node]
exitwhen Node == 0
if (udg_BUSE_PRemove[Node]) then
if (udg_BUSE_PTimer[Node] <= 0) then
call RemoveUnit(udg_BUSE_PUnit[Node])
set udg_BUSE_PRecycleNodes[udg_BUSE_PRecyclableNodes] = Node
set udg_BUSE_PRecyclableNodes = udg_BUSE_PRecyclableNodes + 1
set udg_BUSE_PNextNode[udg_BUSE_PPrevNode[Node]] = udg_BUSE_PNextNode[Node]
set udg_BUSE_PPrevNode[udg_BUSE_PNextNode[Node]] = udg_BUSE_PPrevNode[Node]
if (udg_BUSE_PPrevNode[0] + udg_BUSE_PrevNode[0] == 0) then
call PauseTimer(udg_BUSE_Timer)
endif
else
set udg_BUSE_PTimer[Node] = udg_BUSE_PTimer[Node] - BUSER_TimerSpeed()
endif
elseif (udg_BUSE_PGrowing[Node]) then
set udg_BUSE_PCurrentSize[Node] = udg_BUSE_PCurrentSize[Node] + udg_BUSE_PScaleSpeed[Node]
set udg_BUSE_PGrowthTime[Node] = udg_BUSE_PGrowthTime[Node] - BUSER_TimerSpeed()
call SetUnitScale(udg_BUSE_PUnit[Node], udg_BUSE_PCurrentSize[Node], 0., 0.)
if (udg_BUSE_PGrowthTime[Node] <= 0) then
set udg_BUSE_PGrowing[Node] = false
endif
else
if (udg_BUSE_PDoesPan[Node]) then
if (udg_BUSE_PPanningTime[Node] <= 0) then
set udg_BUSE_PDZ[Node] = udg_BUSE_PDZ[Node] - udg_BUSE_PPan[Node]
call SetUnitAnimationByIndex(udg_BUSE_PUnit[Node], R2I(Atan2(udg_BUSE_PDZ[Node], SquareRoot((udg_BUSE_PDX[Node] * udg_BUSE_PDX[Node]) + (udg_BUSE_PDY[Node] * udg_BUSE_PDY[Node]))) * bj_RADTODEG + 0.5) + 90)
else
set udg_BUSE_PPanningTime[Node] = udg_BUSE_PPanningTime[Node] - BUSER_TimerSpeed()
endif
set x = GetUnitX(udg_BUSE_PUnit[Node])
set y = GetUnitY(udg_BUSE_PUnit[Node])
set z = GetUnitFlyHeight(udg_BUSE_PUnit[Node]) + BUS_GetZ(x,y)
set TempReal = 0
loop
set x = x + udg_BUSE_PDX[Node]
set y = y + udg_BUSE_PDY[Node]
set z = z + udg_BUSE_PDZ[Node]
exitwhen (z < BUS_GetZ(x, y)) or (TempReal > udg_BUSE_PRange[Node])
call GroupEnumUnitsInRange(udg_BUSE_UnitGroup, x, y,udg_BUSE_PAOE[Node], null)
loop
set TempUnit = FirstOfGroup(udg_BUSE_UnitGroup)
exitwhen (TempUnit == null)
call GroupRemoveUnit(udg_BUSE_UnitGroup, TempUnit)
set x2 = GetUnitX(TempUnit)
set y2 = GetUnitY(TempUnit)
set z2 = GetUnitFlyHeight(TempUnit) + BUS_GetZ(x2,y2)
if (BUS_ETargetFilter(TempUnit, Node)) and (SquareRoot((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y) + (z2 - z) * (z2 - z)) <= udg_BUSE_PAOE[Node]) then
call UnitDamageTarget(udg_BUSE_PCaster[Node], TempUnit, udg_BUSE_PHealthDamage[Node], false, false, BUSER_AttackType(), BUSER_DamageType(), BUSER_WeaponType())
call SetUnitState(TempUnit, UNIT_STATE_MANA, GetUnitState(TempUnit, UNIT_STATE_MANA) - udg_BUSE_PManaDamage[Node])
call DestroyEffect(AddSpecialEffectTarget(BUSER_DamageEffect(), TempUnit, BUSER_AttachmentPoint()))
endif
endloop
set TempReal = TempReal + udg_BUSE_PAOE[Node]
endloop
endif
endif
endloop
endfunction
////////////////////////////////////////////////////////////////////
// EnergySpikeEvent: Function used to set up all the data and //
// effects that are used in the loop. Activates when the //
// channeling is completed //
////////////////////////////////////////////////////////////////////
function BUS_EnergySpikeEvent takes nothing returns boolean
local integer iLevel = GetUnitAbilityLevel(udg_BUS_Unit, BUSER_Ability())
local real rLevel = I2R(iLevel)
local integer Node = 0
local integer TempNode = 0
local integer iLoop = 0
local integer iLoop2
local integer TempInt
local integer TempInt2
local real x
local real y
local real z
local real TempSin
local real SinIncrement
local real TempAngle = GetUnitFacing(udg_BUS_Unit)
local real AngleIncrement
local real TempAngle2
local real TempAngle3
if (udg_BUSE_RecyclableNodes == 0) then
set udg_BUSE_NodeNumber = udg_BUSE_NodeNumber + 1
set Node = udg_BUSE_NodeNumber
else
set udg_BUSE_RecyclableNodes = udg_BUSE_RecyclableNodes - 1
set Node = udg_BUSE_RecycleNodes[udg_BUSE_RecyclableNodes]
endif
set udg_BUSE_NextNode[Node] = 0
set udg_BUSE_NextNode[udg_BUSE_PrevNode[0]] = Node
set udg_BUSE_PrevNode[Node] = udg_BUSE_PrevNode[0]
set udg_BUSE_PrevNode[0] = Node
set udg_BUSE_Unit[Node] = udg_BUS_Unit
set udg_BUSE_Cancel[Node] = false
set x = GetUnitX(udg_BUSE_Unit[Node])
set y = GetUnitY(udg_BUSE_Unit[Node])
set z = GetUnitFlyHeight(udg_BUSE_Unit[Node])
if (udg_BUSE_PrevNode[Node] + udg_BUSE_PPrevNode[0] == 0) then
call TimerStart(udg_BUSE_Timer, BUSER_TimerSpeed(), true, function BUS_EnergySpikeLoop)
endif
if (udg_BUSE_PRecyclableNodes == 0) then
set udg_BUSE_PNodeNumber = udg_BUSE_PNodeNumber + 1
set TempNode = udg_BUSE_PNodeNumber
else
set udg_BUSE_PRecyclableNodes = udg_BUSE_PRecyclableNodes - 1
set TempNode = udg_BUSE_PRecycleNodes[udg_BUSE_PRecyclableNodes]
endif
set udg_BUSE_PNextNode[TempNode] = 0
set udg_BUSE_PNextNode[udg_BUSE_PPrevNode[0]] = TempNode
set udg_BUSE_PPrevNode[TempNode] = udg_BUSE_PPrevNode[0]
set udg_BUSE_PPrevNode[0] = TempNode
set udg_BUSE_PUnit[TempNode] = CreateUnit(BUSCR_DummyPlayer(), BUSER_DummyId(), x, y, 0.)
set udg_BUSE_PCaster[TempNode] = udg_BUSE_Unit[Node]
set udg_BUSE_PCurrentEffect[TempNode] = AddSpecialEffectTarget(BUSER_OrbEffect(), udg_BUSE_PUnit[TempNode], BUSER_AttachmentPoint())
set udg_BUSE_PCurrentSize[TempNode] = BUSER_OrbStartSizeBase() + (rLevel * BUSER_OrbStartSizePerLevel())
set udg_BUSE_PGrowthTime[TempNode] = BUSER_OrbTimeBase() + (rLevel * BUSER_OrbTimePerLevel())
set udg_BUSE_PScaleSpeed[TempNode] = (((BUSER_OrbEndSizeBase() + (rLevel * BUSER_OrbEndSizePerLevel())) - udg_BUSE_PCurrentSize[TempNode]) / udg_BUSE_PGrowthTime[TempNode]) * BUSER_TimerSpeed()
set udg_BUSE_PGrowing[TempNode] = true
set udg_BUSE_PDoesPan[TempNode] = false
set udg_BUSE_PTimer[TempNode] = BUSER_EffectRemove()
set udg_BUSE_PRemove[TempNode] = false
call SetUnitScale(udg_BUSE_PUnit[TempNode], udg_BUSE_PCurrentSize[TempNode], 0.,0.)
if UnitAddAbility(udg_BUSE_PUnit[TempNode], 'Amrf') and UnitRemoveAbility(udg_BUSE_PUnit[TempNode], 'Amrf') then
endif
call SetUnitFlyHeight(udg_BUSE_PUnit[TempNode], z, 0.)
set TempInt = BUSER_LaserXYCountBase() + (iLevel * BUSER_LaserXYCountPerLevel())
set TempInt2 = BUSER_LaserZCountBase() + (iLevel * BUSER_LaserZCountPerLevel())
set SinIncrement = (180 - (2 * BUSER_LaserEdgeOffset())) / TempInt2
set AngleIncrement = 360 / TempInt
loop
set iLoop = iLoop + 1
exitwhen iLoop > TempInt
set iLoop2 = 0
set TempAngle = TempAngle + AngleIncrement
if (IsUnitType(udg_BUSE_Unit[Node], UNIT_TYPE_GROUND)) then
set TempSin = BUSER_LaserEdgeOffset()
else
set TempSin = -90 + BUSER_LaserEdgeOffset()
endif
set TempAngle2 = bj_DEGTORAD * TempAngle
loop
set iLoop2 = iLoop2 + 1
exitwhen iLoop2 > TempInt2
set TempAngle3 = bj_DEGTORAD * TempSin
if (udg_BUSE_PRecyclableNodes == 0) then
set udg_BUSE_PNodeNumber = udg_BUSE_PNodeNumber + 1
set TempNode = udg_BUSE_PNodeNumber
else
set udg_BUSE_PRecyclableNodes = udg_BUSE_PRecyclableNodes - 1
set TempNode = udg_BUSE_PRecycleNodes[udg_BUSE_PRecyclableNodes]
endif
set udg_BUSE_PNextNode[TempNode] = 0
set udg_BUSE_PNextNode[udg_BUSE_PPrevNode[0]] = TempNode
set udg_BUSE_PPrevNode[TempNode] = udg_BUSE_PPrevNode[0]
set udg_BUSE_PPrevNode[0] = TempNode
set udg_BUSE_PAOE[TempNode] = BUSER_AOEBase() + (rLevel * BUSER_AOEPerLevel())
set udg_BUSE_PUnit[TempNode] = CreateUnit(Player(14), BUSER_DummyId(), x, y, TempAngle)
set udg_BUSE_PCaster[TempNode] = udg_BUSE_Unit[Node]
set udg_BUSE_POwner[TempNode] = GetOwningPlayer(udg_BUS_Unit)
set udg_BUSE_PHealthDamage[TempNode] = (BUSER_HealthDamageBase() + (rLevel * BUSER_HealthDamagePerLevel())) * BUSER_TimerSpeed()
set udg_BUSE_PManaDamage[TempNode] = (BUSER_ManaDamageBase() + (rLevel * BUSER_ManaDamagePerLevel())) * BUSER_TimerSpeed()
set udg_BUSE_PCurrentEffect[TempNode] = AddSpecialEffectTarget(BUSER_LaserEffect(), udg_BUSE_PUnit[TempNode], BUSER_AttachmentPoint())
set udg_BUSE_PCurrentSize[TempNode] = BUSER_LaserStartSizeBase() + (rLevel * BUSER_LaserStartSizePerLevel())
set udg_BUSE_PGrowthTime[TempNode] = BUSER_LaserTimeBase() + (rLevel * BUSER_LaserTimePerLevel())
set udg_BUSE_PScaleSpeed[TempNode] = (((BUSER_LaserEndSizeBase() + (rLevel * BUSER_LaserEndSizePerLevel())) - udg_BUSE_PCurrentSize[TempNode]) / udg_BUSE_PGrowthTime[TempNode]) * BUSER_TimerSpeed()
call SetUnitScale(udg_BUSE_PUnit[TempNode], udg_BUSE_PCurrentSize[TempNode], 0.,0.)
set udg_BUSE_PDX[TempNode] = Cos(TempAngle2) * Cos(TempAngle3) * udg_BUSE_PAOE[TempNode]
set udg_BUSE_PDY[TempNode] = Sin(TempAngle2) * Cos(TempAngle3) * udg_BUSE_PAOE[TempNode]
set udg_BUSE_PDZ[TempNode] = Sin(TempAngle3) * udg_BUSE_PAOE[TempNode]
set udg_BUSE_PPanningTime[TempNode] = BUSER_PanningTimeBase() + (rLevel * BUSER_PanningTimePerLevel())
set udg_BUSE_PPan[TempNode] = BUSER_PanningBase() + (rLevel * BUSER_PanningPerLevel())
set udg_BUSE_PRange[TempNode] = BUSER_RangeBase() + (rLevel * BUSER_RangePerLevel())
set udg_BUSE_PGrowing[TempNode] = true
set udg_BUSE_PDoesPan[TempNode] = true
set udg_BUSE_PTimer[TempNode] = BUSER_EffectRemove()
set udg_BUSE_PRemove[TempNode] = false
if UnitAddAbility(udg_BUSE_PUnit[TempNode], 'Amrf') and UnitRemoveAbility(udg_BUSE_PUnit[TempNode], 'Amrf') then
endif
call SetUnitAnimationByIndex(udg_BUSE_PUnit[TempNode], R2I(Atan2(udg_BUSE_PDZ[TempNode], SquareRoot((udg_BUSE_PDX[TempNode] * udg_BUSE_PDX[TempNode]) + (udg_BUSE_PDY[TempNode] * udg_BUSE_PDY[TempNode]))) * bj_RADTODEG + 0.5) + 90)
call SetUnitFlyHeight(udg_BUSE_PUnit[TempNode], z, 0.)
set TempSin = TempSin + SinIncrement
endloop
endloop
return false
endfunction
////////////////////////////////////////////////////////////////////
// EnergySpikeStart: Function used to set up the channeling //
// for the ability //
////////////////////////////////////////////////////////////////////
function BUS_EnergySpikeStart takes nothing returns boolean
local unit u
if (GetSpellAbilityId() == BUSER_Ability()) then
set u = GetTriggerUnit()
set udg_BUSE_Cancel[BUS_CheckEnergySpike(u)] = true
call BUS_StartChannel(BUS_GetChannelByName(BUSER_ChannelType()), u, null, 0., 0., BUSER_ChannelDurationBase() + (GetUnitAbilityLevel(u, BUSER_Ability()) * BUSER_ChannelDurationPerLevel()), BUSER_Event(), BUSER_HaveHue())
set u = null
endif
return false
endfunction
////////////////////////////////////////////////////////////////////
// InitTrig BUS Energy Spike: Function used to set up the //
// event and starting functions of the ability as well as the //
// timer for the loop //
////////////////////////////////////////////////////////////////////
function InitTrig_BUS_Energy_Spike takes nothing returns nothing
local trigger t = CreateTrigger()
local integer index = 0
loop
call TriggerRegisterPlayerUnitEvent(t, Player(index),EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
set index = index + 1
exitwhen index >= bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddCondition(t, Condition(function BUS_EnergySpikeStart))
set t = CreateTrigger()
call TriggerRegisterVariableEvent(t, "udg_BUSC_Event", EQUAL, BUSER_Event())
call TriggerAddCondition(t, Condition(function BUS_EnergySpikeEvent))
set udg_BUSE_Timer = CreateTimer()
endfunction
////////////////////////////////////////////////////////////////////
// End of the spell //
////////////////////////////////////////////////////////////////////
function InitTrig_BUS_Register_Channels takes nothing returns nothing
set udg_BUSCR_Name[0] = "Arcane Charge"
set udg_BUSCR_Effect[0] = "Abilities\\Spells\\Human\\ManaFlare\\ManaFlareTarget.mdl"
set udg_BUSCR_MinAOE[0] = 200
set udg_BUSCR_MaxAOE[0] = 300.
set udg_BUSCR_AbsorbAOE[0] = 50.
set udg_BUSCR_MinSize[0] = 0.1
set udg_BUSCR_MaxSize[0] = 1.5
set udg_BUSCR_SpawnRate[0] = 50
set udg_BUSCR_SpawnCount[0] = 2
set udg_BUSCR_Power[0] = 60
set udg_BUSCR_HueRed[0] = 60
set udg_BUSCR_HueGreen[0] = 60
set udg_BUSCR_HueBlue[0] = 255
set udg_BUSCR_HueAlpha[0] = 255
set udg_BUSCR_HueSpeed[0] = 0.50
call BUS_RegisterChannel(0)
//Next Channel
set udg_BUSCR_Name[0] = "Burning Fury"
set udg_BUSCR_Effect[0] = "Abilities\\Weapons\\LordofFlameMissile\\LordofFlameMissile.mdl"
set udg_BUSCR_MinAOE[0] = 250
set udg_BUSCR_MaxAOE[0] = 250.
set udg_BUSCR_AbsorbAOE[0] = 50.
set udg_BUSCR_MinSize[0] = 0.3
set udg_BUSCR_MaxSize[0] = 0.6
set udg_BUSCR_SpawnRate[0] = 30
set udg_BUSCR_SpawnCount[0] = 2
set udg_BUSCR_Power[0] = 250
set udg_BUSCR_HueRed[0] = 255
set udg_BUSCR_HueGreen[0] = 0
set udg_BUSCR_HueBlue[0] = 0
set udg_BUSCR_HueAlpha[0] = 255
set udg_BUSCR_HueSpeed[0] = 0.25
call BUS_RegisterChannel(0)
//Next Channel
set udg_BUSCR_Name[0] = "Gravity"
set udg_BUSCR_Effect[0] = "Abilities\\Weapons\\AvengerMissile\\AvengerMissile.mdl"
set udg_BUSCR_MinAOE[0] = 500
set udg_BUSCR_MaxAOE[0] = 500.
set udg_BUSCR_AbsorbAOE[0] = 50.
set udg_BUSCR_MinSize[0] = 1.5
set udg_BUSCR_MaxSize[0] = 2.
set udg_BUSCR_SpawnRate[0] = 128
set udg_BUSCR_SpawnCount[0] = 1
set udg_BUSCR_Power[0] = 1100
set udg_BUSCR_HueRed[0] = 0
set udg_BUSCR_HueGreen[0] = 0
set udg_BUSCR_HueBlue[0] = 0
set udg_BUSCR_HueAlpha[0] = 255
set udg_BUSCR_HueSpeed[0] = 0.25
call BUS_RegisterChannel(0)
//Next Channel
set udg_BUSCR_Name[0] = "Holy Storm"
set udg_BUSCR_Effect[0] = "Abilities\\Spells\\NightElf\\Rejuvenation\\RejuvenationTarget.mdl"
set udg_BUSCR_MinAOE[0] = 200.
set udg_BUSCR_MaxAOE[0] = 250.
set udg_BUSCR_AbsorbAOE[0] = 50.
set udg_BUSCR_MinSize[0] = 0.25
set udg_BUSCR_MaxSize[0] = 0.5
set udg_BUSCR_SpawnRate[0] = 30
set udg_BUSCR_SpawnCount[0] = 2
set udg_BUSCR_Power[0] = 20
set udg_BUSCR_HueRed[0] = 255
set udg_BUSCR_HueGreen[0] = 255
set udg_BUSCR_HueBlue[0] = 0
set udg_BUSCR_HueAlpha[0] = 255
set udg_BUSCR_HueSpeed[0] = 1
call BUS_RegisterChannel(0)
endfunction
The knockback system used in the spellpack is fairly simplistic and easy to use though is not a main feature
Attributes of the system:
- Ground units can be "bounced" off the ground if a force pushes them down
- Flying units can be knocked back in 3D and will return to their original heights
- Flying units can be killed instantly if they are pushed into the floor
- Ground units (on the ground) can optionally kill or attempt to prevent going through, trees
- Ground knockback decay different from air knockback decay (flying ground units use the air knockback decay)
Using the system:
call BUS_StartKnockback(Target, Force, TargetX, OriginX, TargetY, OriginY, TargetZ, OriginZ)
- This is the only function required the run the knockback from a user perspective
- Target = Unit to knock back
- Force = The force to push the unit
- TargetX = The x co-ordinate of the Target
- OriginX = The x co-ordinate of the origin point of the knockback (used for angle calculation)
- TargetY = The y co-ordinate of the Target
- OriginY = The y co-ordinate of the origin point of the knockback (used for angle calculation)
- TargetZ = The z co-ordinate of the Target
- OriginZ = The z co-ordinate of the origin point of the knockback (used for angle calculation)
When calculating Target and Origin Z values, you should use the BUS_GetZ(x,y) function if you want greater accuracy
though this is optional, to use this effectively use the following formula
set TargetZ = GetUnitFlyHeight(Target) + BUS_GetZ(TargetX,TargetY) + OffsetMod
set OriginZ = GetUnitFlyHeight(Origin) + BUS_GetZ(OriginX,OriginY) + OffsetMod
- If there is no Origin Unit then simply leave out getting its fly height to achieve the same effect
- Offset modifiers can be used to achieve certain effects (assuming they are different from eachother)
such as causing the knockback angle to assume the Target is above the origin point or other similar scenarios
This user guide explains how to use the BUS Channel system for your own abilities.
Instructions:
1) You will need to define some channel types, to do this follow the layout of "BUS Register Channels"
- Set up all the variables which start with the acronym "BUSCR_" to the value you desire
- Follow "Channel Register Explanation" for a more in-depth coverage of this
- Do not set udg_BUSCR_HueSpeed[0] = 0 this will cause the channel to be unusable
- Make sure that they all have 0 as their index number and use the function below at the end.
call BUS_RegisterChannel(0)
- This will register your channel and give it an index number for you to refer to it by
- If you do not know its index number (they are assigned from 1+ in order of registering) use the below function
call BUS_GetChannelByName("Your Channel Name")
This is function is case insensitive
2) If you want to overwrite an existing channel or want to specify the index number specifically you can use these:
- call Bus_RegisterChannel(i) Where i is the index number you wish to register it by (i > 0)
- call BUS_RegisterChannel(BUS_GetChannelByName("Your Channel Name"))
3) If you wish to make an ability which uses the channel system and you have completed the above steps
- You need to initialise a trigger which activates when the ability begins being channeled
- You then need to initialise a trigger which activates when BUS_Event becomes equal to the ability event number
- This second trigger will only activate if the channel is completed, so interrupting and cancelling work as normal
- All abilities need a unique event number this can be any real number so long as only one ability uses it
- A completed JASS example can be found at Example 1, A completed GUI example can be found aT Example 1 & 2
- The Start channel function has many parameters that it can be passed, with quite a few of them being optional
call BUS_StartChannel(BUS_GetChannelByName("My Channel Type"), Caster, TargetUnit, TargetX., TargetY., ChannelDuration, EventNumber, HaveHueChange)
- It is not necessary to pass a Target unit, Target X or Target Y as some abilities may not have or use these things
- If the channel type requested does not exist (the string inputted is wrong) then the last defined channel will
be used by default, if you pass a number which does not correspond to any defined channel, there will be an error
so it is safer to use BUS_GetChannelByName
- Make sure the event number passed matches the event number defined to activate the right function
example 1 uses 5.00 and example 2 uses 6.00 for instance, if they used the same value then both triggers would fire
- While most parameters are self-explanatory the last one "HaveHueChange" is a bit less clear:
It is a boolean value (true/false)
It determines whether or not the caster has their hue (colour) changed while they are channeling the ability
It assumes that the caster has a color of 255/255/255/255 (Red/Green/Blue/Alpha) so if your caster is not then
you should always set this to false
4) Certain globals will have data which can be used by the event function (Example 1 first function, Example 3)
- udg_BUS_Unit Will contain the caster unit, it must be used
- udg_BUS_Target will contain the target unit, it should be null if not used
- udg_BUS_X will contain the X co-ordinate of the target point, it should be 0 if not used
- udg_BUS_Y will contain the Y co-ordinate of the target point, it should be 0 if not used
This section covers the different variables when setting up a channel and what they do
Lets take a look at the first channel from "BUS Register Channel"
set udg_BUSCR_Name[0] = "Arcane Charge"
set udg_BUSCR_Effect[0] = "Abilities\\Spells\\Human\\ManaFlare\\ManaFlareTarget.mdl"
set udg_BUSCR_MinAOE[0] = 200
set udg_BUSCR_MaxAOE[0] = 300.
set udg_BUSCR_AbsorbAOE[0] = 50.
set udg_BUSCR_MinSize[0] = 0.1
set udg_BUSCR_MaxSize[0] = 1.5
set udg_BUSCR_SpawnRate[0] = 50
set udg_BUSCR_SpawnCount[0] = 2
set udg_BUSCR_Power[0] = 60
set udg_BUSCR_HueRed[0] = 60
set udg_BUSCR_HueGreen[0] = 60
set udg_BUSCR_HueBlue[0] = 255
set udg_BUSCR_HueAlpha[0] = 255
set udg_BUSCR_HueSpeed[0] = 0.50
call BUS_RegisterChannel(0)
set udg_BUSCR_Name[0] = "Arcane Charge"
- This is the name the channel is given and used to locate it with BUS_GetChannelByName("Your Channel Name")
- Names are case insensitive so it does not matter if this is upper, lower or any mix of the few
- Remembering if there is spacing however is important
- This attribute exists as names are significantly easier to remember than ID numbers
set udg_BUSCR_Effect[0] = "Abilities\\Spells\\Human\\ManaFlare\\ManaFlareTarget.mdl"
- This is the filepath used for the effect of the channel - the particles that appear and are drawn toward the caster
- The double "\"s are important and if you are getting a string from the object editor it will only have one, be sure
to add the other ones in before you save (this may cause the progress bar to appear stuck, though correcting and
attempting to save again will work, even if it remains bugged
- Having an incorrect path may bug the system, as well as make no effect appear when you are channeling
set udg_BUSCR_MinAOE[0] = 200
set udg_BUSCR_MaxAOE[0] = 300.
- These both are very similar - they determine how far away from the caster effects may spawn
- The gap between these two values is the effective range (all effects will spawn in this range)
- Technically these can take negative values, but it is not recommended as the facing angle of effects will be wrong
set udg_BUSCR_AbsorbAOE[0] = 50.
- This is the distance from the caster that the effects must have (or be closer than) before they are destroyed
- Ideally this is close to melee range, and should be much lower then the MinAOE (effects may spawn which are
instantly removed which is essentially pointless, if they are the same)
set udg_BUSCR_MinSize[0] = 0.1
set udg_BUSCR_MaxSize[0] = 1.5
- These are scaling controls for the effects - determining the upper and lower bounds of their sizes
- They are done in terms of percentages (0.1 = 10%, 1.5 = 150%)
- Most models scale differently so you are unlikely to get the desired sizes first try if you estimate
- setting these values to negatives will invert the models (which may be desirable depending on the effect)
set udg_BUSCR_SpawnRate[0] = 50
- The spawn rate is a measure of how many sets of effects are made per second
- This is inherently limited by the timer speed used by the system (default 0.03125)
- The maximum amount of spawns per second is 32, so setting this value to 32 should reach these maximum but
due to inaccuracies in floating point numbers, it is safer to use a higher number to ensure all 32 sets are made
set udg_BUSCR_SpawnCount[0] = 2
- The spawn count is a measure of how many effects are created within each set
- Unlike the spawn rate this is not limited by the timer but rather by the Warcraft 3 engine with an approximate
maximum of 400 effects being able to be created at any given time, though to do this would cause massive amounts
of lag and lead to freezing, particularly if the spawn rate is also high
- The total amount of effects spawned can be calculated via (ChannelDuration * SpawnRate * SpawnCount) where the
duration is in seconds, so be mindful of this when setting up your channels
set udg_BUSCR_Power[0] = 60
- The power of a channel refers to how strongly the effects are pulled into the caster, the higher this value
the more visually powerful the channel looks (particularly if accompanied by a high spawn rate) conversely a
lower value leads to a more aura-like channel effect
set udg_BUSCR_HueRed[0] = 60
set udg_BUSCR_HueGreen[0] = 60
set udg_BUSCR_HueBlue[0] = 255
set udg_BUSCR_HueAlpha[0] = 255
- These values determine the Red/Green/Blue/Alpha extremes of a hue (colour) change respectively assuming the
instance of the channel is using them
- The system assumes that the default values are 255/255/255/255 respectively for any given caster, these are
the values that it will periodically oscillate to (go to and from) during a channel
- Alpha refers to the transparency of a unit, 0 leads to a completely invisible unit
set udg_BUSCR_HueSpeed[0] = 0.50
- This determines the time it takes for one oscillation to complete (go from default colours to the above hue values
- A complete oscillation is therefore double this time
- When creating a spell it is good to consider what the colour will be when the channel is over, in this case so long
as the channel duration is in complete seconds (1.00, 2.00, 3.00 etc.) then the caster will be at their original
colours when the channel is complete, conversely if ending at a half second (0.50, 1.50, 2.50, etc.) then they
will be at the extreme end of the colour change, however when a channel completes the unit is automatically
restored to default colouring, so this is only important to consider if you wish to avoid a sudden colour change
(this will still happen if the channel is cancelled)
You have reached the end of this explanation
//Channel Finished Event
function ExampleEvent takes nothing returns boolean
return false
endfunction
//Start Channel
function ExampleStart takes nothing returns boolean
local unit u
if (GetSpellAbilityId() == Example_Ability) then
set u = GetTriggerUnit()
call BUS_StartChannel(BUS_GetChannelByName("My Channel Type"), u, TargetUnit, TargetX., TargetY., ChannelDuration, 5.00, HaveHueChange)
set u = null
endif
return false
endfunction
//Init Trig
function InitTrig_Example_1 takes nothing returns nothing
local trigger t = CreateTrigger()
local integer index = 0
loop
call TriggerRegisterPlayerUnitEvent(t, Player(index),EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
set index = index + 1
exitwhen index >= bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddCondition(t, Condition(function ExampleStart))
set t = CreateTrigger()
call TriggerRegisterVariableEvent(t, "udg_BUSC_Event", EQUAL, 5.00)
call TriggerAddCondition(t, Condition(function ExampleEvent))
endfunction
// ********************************************************
// *
// * Infernal Collapse v1.4
// * by Quilnez
// *
// * Description:
// * Calls forth exploding magmatic shards all around the
// * target point. All enemy units around the explosion
// * site will receive fire damage.
// *
// * Requirement(s):
// * None
// *
// * How to import:
// * • Copy "Infernal Collapse" trigger group to your map
// * • Delete variable creator trigger
// * • Export all necessary import data to your map
// * (Except "TerrainArt\Outland\Outland_Dirt.blp")
// * • Copy dummy unit (Object Editor) to your map
// * • Copy main ability (Object Editor) to your map
// * • Configure the spell
// *
// * Credits:
// * • BTNEvaporate By M0rbid
// * • Explosion.mdx By JetFangInferno
// * • ExplosiveTornado.mdx By JetFangInferno
// * • FlameBomb.mdx By WILL THE ALMIGHTY
// * • Fire Low.mdx By Pyritie
// * • LightningSphere_FX.mdx By PeeKay
// * • Shockwave.mdx By Vestras
// * • dummy.mdx By Vexorian
// * (All models are edited to fulfill the
// * needs of this spell)
// *
// * Author's note:
// * If you need assistanance on installing this to your
// * map, or to request another form of this spell, just
// * contact me anytime
// *
// ********************************************************
// ********************************************************
// *
// * Configuration
// *
// * 1. Dummy unit's raw code at object editor
constant function ICol__DummyID takes nothing returns integer
return 'h001'
endfunction
// *
// * 2. Main ability's raw code at object editor
constant function ICol__SpellID takes nothing returns integer
return 'A01G'
endfunction
// *
// * 3. Just leave it as it is
constant function ICol__Interval takes nothing returns real
return 0.0312500
endfunction
// *
// * 4. Time given to special effects to decay before being removed
constant function ICol__SFXDecayTime takes nothing returns real
return 5.0
endfunction
// *
// * 5. If true, spell will become channeling:
// * The spell will be stopped whenever the caster is given another
// * order
constant function ICol__Channeling takes nothing returns boolean
return false
endfunction
// *
// * 6. Order id of the main ability, only useful when the spell is
// * channeling
constant function ICol__OrderID takes nothing returns integer
return 852218 // carrionswarm
endfunction
// *
// * 7. Core of the orb's model path
constant function ICol__CoreSFX takes nothing returns string
return "war3mapImported\\Fire Low.mdx"
endfunction
// *
// * 8. (i) Orb's minimum size (scale)
constant function ICol__CoreMinSize takes nothing returns real
return 1.0
endfunction
// *
// * (ii) Orb's maximum size (scale)
constant function ICol__CoreMaxSize takes nothing returns real
return 2.0
endfunction
// * * Orbs will be spawned at random starting size (scale)
// *
// * 9. Size of the orb when it's ready to explode
// * The grow rate of the orb will be automatically calculated
// * based on interval and orb's lifespan (configurable at the
// * dynamic configuration part below)
constant function ICol__CoreTargetSize takes nothing returns real
return 0.15
endfunction
// *
// * 10. Swirl effect's model path, will be attached to the orb
constant function ICol__SwirlSFX takes nothing returns string
return "war3mapImported\\ExplosiveTornado.mdx"
endfunction
// *
// * 11. Glow effect's model path, will be attached to the orb
constant function ICol__GlowSFX takes nothing returns string
return "war3mapImported\\LightningSphere_FX.mdx"
endfunction
// *
// * 12. Explosion effect's model path, will be used on explode event
constant function ICol__ExplosionSFX takes nothing returns string
return "war3mapImported\\FlameBomb.mdx"
endfunction
// *
// * 13. Wave effect's model path, will be used on explode event
constant function ICol__WaveSFX takes nothing returns string
return "war3mapImported\\Shockwave.mdx"
endfunction
// *
// * 14. Wave effect's model path, will be used on explode event
constant function ICol__SphereSFX takes nothing returns string
return "war3mapImported\\Explosion.mdx"
endfunction
// *
// * 15. Lifespan of the orb before exploded, may affects grow rate
constant function ICol__CoreLifespan takes integer level returns real
return 0.50
endfunction
// *
// * 16. (i) Orb's minimum distance from cast point
constant function ICol__MinDistance takes integer level returns real
return 50.0
endfunction
// *
// * (ii) Orb's maximum distance from cast point
constant function ICol__MaxDistance takes integer level returns real
return 150.0
endfunction
// * * Orbs will be spawned at random location around the cast point
// *
// * 17. (i) Orb's minimum fly height
constant function ICol__MinHeight takes integer level returns real
return 150.0
endfunction
// *
// * (ii) Orb's maximum fly height
constant function ICol__MaxHeight takes integer level returns real
return 300.0
endfunction
// * * Orbs will be spawned at random height
// *
// * 18. (i) Minimum delay before spawning another orb
constant function ICol__MinDelay takes integer level returns real
return 0.0
endfunction
// *
// * (ii) Maximum delay before spawning another orb
constant function ICol__MaxDelay takes integer level returns real
return 0.15
endfunction
// * * Orbs have random spawn rate
// *
// * 19. Maximum duration of the spell
// * Use 0 or lower to remove duration limit
constant function ICol__Duration takes integer level returns real
return 3.0
endfunction
// *
// * 20. Maximum count of spawned orbs per cast
// * Use 0 or lower to remove spawn limit
constant function ICol__Count takes integer level returns integer
return 0
endfunction
// *
// * 21. Maximum distance from target to the orb to take damage
constant function ICol__AoE takes integer level returns real
return 300.0
endfunction
// *
// * 22. If true, the AoE will become spherical
constant function ICol__3DAoE takes nothing returns boolean
return true
endfunction
// *
// * 23. Damage dealt to targets within explosion AoE
constant function ICol__Damage takes integer level returns real
return 5.0*level
endfunction
// *
// * 24. Attack type of dealt damage
constant function ICol__AttackType takes nothing returns attacktype
return ATTACK_TYPE_NORMAL
endfunction
// *
// * 25. Damage type of dealt damage
constant function ICol__DamageType takes nothing returns damagetype
return DAMAGE_TYPE_FIRE
endfunction
// *
// * 26. Weapon type of dealt damage
constant function ICol__WeaponType takes nothing returns weapontype
return WEAPON_TYPE_WHOKNOWS
endfunction
// *
// * 27. This part allows you to change spell's casting type, is it
// * point target or no target. For example if you want to change
// * it to no target (instant), you can modify this to
// * "return GetUnitX(caster)"
function ICol__GetCastTargetX takes unit caster returns real
return GetSpellTargetX()
endfunction
// *
// * 28. Same as above. For example if you want to change it to no
// * target (instant), you can modify this to
// * "return GetUnitY(caster)"
function ICol__GetCastTargetY takes unit caster returns real
return GetSpellTargetY()
endfunction
// * * Targeting unit cast type is not recommended
// *
// * 29. No need to touch this, used to check is unit alive or not
function ICol__isAlive takes unit id returns boolean
return GetWidgetLife(id) > 0.405 and not IsUnitType(id, UNIT_TYPE_DEAD)
endfunction
// *
// * 30. Classification of unit which can become a victim of the spell
function ICol__Targets takes unit target, player caster returns boolean
return ICol__isAlive(target) and IsUnitEnemy(target, caster) and not(IsUnitType(target, UNIT_TYPE_STRUCTURE) or IsUnitType(target, UNIT_TYPE_MAGIC_IMMUNE))
endfunction
// *
// * 31. This function will be called whenever a unit is damaged by this spell
function ICol__OnDamage takes unit target, unit caster, integer level returns nothing
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Items\\AIfb\\AIfbSpecialArt.mdl", target, "chest"))
// call BJDebugMsg(GetUnitName(target) + " took " + R2SW(ICol__Damage(level), 4, 1) + " damage from " + GetUnitName(caster) + ".")
endfunction
// *
// * 32. This function will be called whenever an orb is exploded
function ICol__OnExplode takes unit caster, integer level, real x, real y, real z returns nothing
// call BJDebugMsg("Alert! An orb (level " + I2S(level) + " from " + GetUnitName(caster) + " has been exploded at [x: " + R2SW(x, 4, 1) + ", y: " + R2SW(y, 4, 1) + ", z: " + R2SW(z, 4, 1) + "]")
endfunction
// *
// * 33. This function will be called whenever an orb is spawned
function ICol__OnSpawn takes unit caster, integer level, real x, real y, real z returns nothing
// call BJDebugMsg("Alert! An orb (level " + I2S(level) + " from " + GetUnitName(caster) + " has been spawned at [x: " + R2SW(x, 4, 1) + ", y: " + R2SW(y, 4, 1) + ", z: " + R2SW(z, 4, 1) + "]")
endfunction
// *
// * End of Configuration
// *
// ********************************************************
function ICol__getZ takes real x, real y returns real
call MoveLocation(udg_ICol__TempLoc, x, y)
return GetLocationZ(udg_ICol__TempLoc)
endfunction
function ICol__setZ takes unit u, real z returns nothing
call SetUnitFlyHeight(u, z - ICol__getZ(GetUnitX(u), GetUnitY(u)), 0)
endfunction
// Orb periodic callback
function ICol__orb__periodic takes nothing returns nothing
local integer i = 1
local boolean b
local unit u
local real d
local real x
local real y
local real z
loop
exitwhen i > udg_ICol__Orb__Count
// If still need to grow
if udg_ICol__Orb__Scale[i] > ICol__CoreTargetSize() then
set udg_ICol__Orb__Scale[i] = udg_ICol__Orb__Scale[i] - udg_ICol__Orb__ScaleRate[i]
call SetUnitScale(udg_ICol__Orb__Dummy[i], udg_ICol__Orb__Scale[i], 1, 1)
else
set udg_ICol__OCount[udg_ICol__Orb__Source[i]] = udg_ICol__OCount[udg_ICol__Orb__Source[i]] - 1
call UnitApplyTimedLife(udg_ICol__Orb__Dummy[i], 'BTLF', ICol__SFXDecayTime())
call DestroyEffect(udg_ICol__Orb__CoreFx[i])
call DestroyEffect(udg_ICol__Orb__GlowFx[i])
call DestroyEffect(udg_ICol__Orb__SwirlFx[i])
// If the caster is still alive then allow orb to explode
if ICol__isAlive(udg_ICol__Caster[udg_ICol__Orb__Source[i]]) then
call ICol__OnExplode(udg_ICol__Caster[udg_ICol__Orb__Source[i]], udg_ICol__Level[udg_ICol__Orb__Source[i]], udg_ICol__Orb__X[i], udg_ICol__Orb__Y[i], udg_ICol__Orb__Z[i])
// We need dummy to adjust explosion effects' height
set u = CreateUnit(udg_ICol__Owner[udg_ICol__Orb__Source[i]], ICol__DummyID(), udg_ICol__Orb__X[i], udg_ICol__Orb__Y[i], 0)
if UnitAddAbility(u, 'Amrf') and UnitRemoveAbility(u, 'Amrf') then
endif
call ICol__setZ(u, udg_ICol__Orb__Z[i])
call DestroyEffect(AddSpecialEffectTarget(ICol__ExplosionSFX(), u, "origin"))
call DestroyEffect(AddSpecialEffectTarget(ICol__WaveSFX(), u, "origin"))
call DestroyEffect(AddSpecialEffectTarget(ICol__SphereSFX(), u, "origin"))
call UnitApplyTimedLife(u, 'BTLF', ICol__SFXDecayTime())
call GroupEnumUnitsInRange(udg_ICol__TempGroup, udg_ICol__Orb__X[i], udg_ICol__Orb__Y[i], udg_ICol__AoE[udg_ICol__Orb__Source[i]], null)
loop
set u = FirstOfGroup(udg_ICol__TempGroup)
exitwhen u == null
call GroupRemoveUnit(udg_ICol__TempGroup, u)
if ICol__Targets(u, udg_ICol__Owner[udg_ICol__Orb__Source[i]]) then
set b = true
if ICol__3DAoE() then
// Spherical collision (AoE)
set x = GetUnitX(u)
set y = GetUnitY(u)
set z = udg_ICol__Orb__Z[i]-(ICol__getZ(x, y)+GetUnitFlyHeight(u))
set d = SquareRoot((udg_ICol__Orb__X[i] - x)*(udg_ICol__Orb__X[i] - x) + (udg_ICol__Orb__Y[i] - y)*(udg_ICol__Orb__Y[i] - y))
set b = (d*d)+(z*z) < udg_ICol__AoE[udg_ICol__Orb__Source[i]]*udg_ICol__AoE[udg_ICol__Orb__Source[i]]
endif
if b then
call UnitDamageTarget(udg_ICol__Caster[udg_ICol__Orb__Source[i]], u, udg_ICol__Damage[udg_ICol__Orb__Source[i]], false, false, ICol__AttackType(), ICol__DamageType(), ICol__WeaponType())
call ICol__OnDamage(u, udg_ICol__Caster[udg_ICol__Orb__Source[i]], udg_ICol__Level[udg_ICol__Orb__Source[i]])
endif
endif
endloop
endif
if i != udg_ICol__Orb__Count then
// Deindexing
set udg_ICol__Orb__Dummy[i] = udg_ICol__Orb__Dummy[udg_ICol__Orb__Count]
set udg_ICol__Orb__CoreFx[i] = udg_ICol__Orb__CoreFx[udg_ICol__Orb__Count]
set udg_ICol__Orb__SwirlFx[i] = udg_ICol__Orb__SwirlFx[udg_ICol__Orb__Count]
set udg_ICol__Orb__GlowFx[i] = udg_ICol__Orb__GlowFx[udg_ICol__Orb__Count]
set udg_ICol__Orb__Scale[i] = udg_ICol__Orb__Scale[udg_ICol__Orb__Count]
set udg_ICol__Orb__ScaleRate[i] = udg_ICol__Orb__ScaleRate[udg_ICol__Orb__Count]
set udg_ICol__Orb__Source[i] = udg_ICol__Orb__Source[udg_ICol__Orb__Count]
set udg_ICol__Orb__X[i] = udg_ICol__Orb__X[udg_ICol__Orb__Count]
set udg_ICol__Orb__Y[i] = udg_ICol__Orb__Y[udg_ICol__Orb__Count]
set udg_ICol__Orb__Z[i] = udg_ICol__Orb__Z[udg_ICol__Orb__Count]
endif
// Remove leaks
set udg_ICol__Orb__Dummy[udg_ICol__Orb__Count] = null
set udg_ICol__Orb__CoreFx[udg_ICol__Orb__Count] = null
set udg_ICol__Orb__SwirlFx[udg_ICol__Orb__Count] = null
set udg_ICol__Orb__GlowFx[udg_ICol__Orb__Count] = null
set udg_ICol__Orb__Count = udg_ICol__Orb__Count - 1
if udg_ICol__Orb__Count < 1 then
call PauseTimer(udg_ICol__Orb__Timer)
else
set i = i - 1
endif
endif
set i = i + 1
endloop
endfunction
// To create an orb at given coordinates
function ICol__orb__create takes integer source, real x, real y, real z returns nothing
set udg_ICol__Orb__Count = udg_ICol__Orb__Count + 1
set udg_ICol__Orb__Source[udg_ICol__Orb__Count] = source
set udg_ICol__Orb__Dummy[udg_ICol__Orb__Count] = CreateUnit(udg_ICol__Owner[source], ICol__DummyID(), x, y, 0)
set udg_ICol__Orb__CoreFx[udg_ICol__Orb__Count] = AddSpecialEffectTarget(ICol__CoreSFX(), udg_ICol__Orb__Dummy[udg_ICol__Orb__Count], "origin")
set udg_ICol__Orb__SwirlFx[udg_ICol__Orb__Count] = AddSpecialEffectTarget(ICol__SwirlSFX(), udg_ICol__Orb__Dummy[udg_ICol__Orb__Count], "origin")
set udg_ICol__Orb__GlowFx[udg_ICol__Orb__Count] = AddSpecialEffectTarget(ICol__GlowSFX(), udg_ICol__Orb__Dummy[udg_ICol__Orb__Count], "origin")
set udg_ICol__Orb__Scale[udg_ICol__Orb__Count] = GetRandomReal(ICol__CoreMinSize(), ICol__CoreMaxSize())
set udg_ICol__Orb__ScaleRate[udg_ICol__Orb__Count] = (udg_ICol__Orb__Scale[udg_ICol__Orb__Count]-ICol__CoreTargetSize())/(udg_ICol__Lifespan[source]/ICol__Interval())
// Update orb's coordinate in case it's created at different loc (exceed map boundaries/pathing issue)
set udg_ICol__Orb__X[udg_ICol__Orb__Count] = GetUnitX(udg_ICol__Orb__Dummy[udg_ICol__Orb__Count])
set udg_ICol__Orb__Y[udg_ICol__Orb__Count] = GetUnitY(udg_ICol__Orb__Dummy[udg_ICol__Orb__Count])
set udg_ICol__Orb__Z[udg_ICol__Orb__Count] = z+ICol__getZ(udg_ICol__Orb__X[udg_ICol__Orb__Count], udg_ICol__Orb__Y[udg_ICol__Orb__Count])
if UnitAddAbility(udg_ICol__Orb__Dummy[udg_ICol__Orb__Count], 'Amrf') and UnitRemoveAbility(udg_ICol__Orb__Dummy[udg_ICol__Orb__Count], 'Amrf') then
endif
call SetUnitFlyHeight(udg_ICol__Orb__Dummy[udg_ICol__Orb__Count], z, 0)
call SetUnitScale(udg_ICol__Orb__Dummy[udg_ICol__Orb__Count], udg_ICol__Orb__Scale[udg_ICol__Orb__Count], 1, 1)
call ICol__OnSpawn(udg_ICol__Caster[source], udg_ICol__Level[source], x, y, z)
if udg_ICol__Orb__Count == 1 then
call TimerStart(udg_ICol__Orb__Timer, ICol__Interval(), true, function ICol__orb__periodic)
endif
endfunction
// Main spell's periodic callback
function ICol__periodic takes nothing returns nothing
local integer h
local integer i = 1
local integer j
local real d
local real a
loop
exitwhen i > udg_ICol__Count
if not udg_ICol__Dispose[i] then
if udg_ICol__Duration[i] > 0 then
set udg_ICol__Duration[i] = udg_ICol__Duration[i] - ICol__Interval()
set udg_ICol__Dispose[i] = udg_ICol__Duration[i] <= 0
endif
// If current order still matches
if not udg_ICol__Dispose[i] then
set udg_ICol__Dispose[i] = not ICol__isAlive(udg_ICol__Caster[i]) or ICol__Channeling() and GetUnitCurrentOrder(udg_ICol__Caster[i]) != ICol__OrderID()
endif
if not udg_ICol__Dispose[i] then
if udg_ICol__Delay[i] > ICol__Interval() then
set udg_ICol__Delay[i] = udg_ICol__Delay[i] - ICol__Interval()
else
// If still able to spawn more orbs
if udg_ICol__SpawnCount[i] > 0 then
set udg_ICol__SpawnCount[i] = udg_ICol__SpawnCount[i] - 1
set udg_ICol__Dispose[i] = udg_ICol__SpawnCount[i] == 0
endif
set udg_ICol__Delay[i] = GetRandomReal(udg_ICol__DelayMin[i], udg_ICol__DelayMax[i])
// Create new orb at random coordinate around the cast point
set d = GetRandomReal(udg_ICol__DistanceMin[i], udg_ICol__DistanceMax[i])
set a = GetRandomReal(-bj_PI, bj_PI)
set udg_ICol__OCount[i] = udg_ICol__OCount[i] + 1
call ICol__orb__create(i, udg_ICol__X[i]+d*Cos(a), udg_ICol__Y[i]+d*Sin(a), GetRandomReal(udg_ICol__HeightMin[i], udg_ICol__HeightMax[i]))
endif
endif
endif
// If the spell is ended
if udg_ICol__Dispose[i] then
if udg_ICol__OCount[i] <= 0 then
set h = GetHandleId(udg_ICol__Caster[i])
if HaveSavedInteger(udg_ICol__Hashtable, h, 0) then
if ICol__Channeling() then
if LoadInteger(udg_ICol__Hashtable, h, 0) == i then
call RemoveSavedInteger(udg_ICol__Hashtable, h, 0)
endif
endif
endif
if i != udg_ICol__Count then
// Index correction
if ICol__Channeling() then
call SaveInteger(udg_ICol__Hashtable, GetHandleId(udg_ICol__Caster[udg_ICol__Count]), 0, i)
endif
// Deindexing
set udg_ICol__Caster[i] = udg_ICol__Caster[udg_ICol__Count]
set udg_ICol__Owner[i] = udg_ICol__Owner[udg_ICol__Count]
set udg_ICol__X[i] = udg_ICol__X[udg_ICol__Count]
set udg_ICol__Y[i] = udg_ICol__Y[udg_ICol__Count]
set udg_ICol__Level[i] = udg_ICol__Level[udg_ICol__Count]
set udg_ICol__Damage[i] = udg_ICol__Damage[udg_ICol__Count]
set udg_ICol__Dispose[i] = udg_ICol__Dispose[udg_ICol__Count]
set udg_ICol__OCount[i] = udg_ICol__OCount[udg_ICol__Count]
set udg_ICol__AoE[i] = udg_ICol__AoE[udg_ICol__Count]
set udg_ICol__Lifespan[i] = udg_ICol__Lifespan[udg_ICol__Count]
set udg_ICol__SpawnCount[i] = udg_ICol__SpawnCount[udg_ICol__Count]
set udg_ICol__Duration[i] = udg_ICol__Duration[udg_ICol__Count]
set udg_ICol__DistanceMin[i] = udg_ICol__DistanceMin[udg_ICol__Count]
set udg_ICol__DistanceMax[i] = udg_ICol__DistanceMax[udg_ICol__Count]
set udg_ICol__HeightMin[i] = udg_ICol__HeightMin[udg_ICol__Count]
set udg_ICol__HeightMax[i] = udg_ICol__HeightMax[udg_ICol__Count]
set udg_ICol__DelayMin[i] = udg_ICol__DelayMin[udg_ICol__Count]
set udg_ICol__DelayMax[i] = udg_ICol__DelayMax[udg_ICol__Count]
set udg_ICol__Delay[i] = udg_ICol__Delay[udg_ICol__Count]
// Source index corrections
set j = 1
loop
exitwhen j > udg_ICol__Orb__Count
if udg_ICol__Orb__Source[j] == udg_ICol__Count then
set udg_ICol__Orb__Source[j] = i
endif
set j = j + 1
endloop
endif
// Remove leak
set udg_ICol__Caster[udg_ICol__Count] = null
set udg_ICol__Count = udg_ICol__Count - 1
if udg_ICol__Count < 1 then
call PauseTimer(udg_ICol__Timer)
else
set i = i - 1
endif
endif
endif
set i = i + 1
endloop
endfunction
// On cast event
function ICol__onCast takes nothing returns boolean
local integer h
if GetSpellAbilityId() == ICol__SpellID() then
set udg_ICol__Count = udg_ICol__Count + 1
set udg_ICol__Caster[udg_ICol__Count] = GetTriggerUnit()
set udg_ICol__Owner[udg_ICol__Count] = GetTriggerPlayer()
set udg_ICol__Dispose[udg_ICol__Count] = false
set udg_ICol__OCount[udg_ICol__Count] = 0
// Get cast point coordinate (customizable by user)
set udg_ICol__X[udg_ICol__Count] = ICol__GetCastTargetX(udg_ICol__Caster[udg_ICol__Count])
set udg_ICol__Y[udg_ICol__Count] = ICol__GetCastTargetY(udg_ICol__Caster[udg_ICol__Count])
set udg_ICol__Level[udg_ICol__Count] = GetUnitAbilityLevel(udg_ICol__Caster[udg_ICol__Count], ICol__SpellID())
set udg_ICol__Damage[udg_ICol__Count] = ICol__Damage(udg_ICol__Level[udg_ICol__Count])
set udg_ICol__AoE[udg_ICol__Count] = ICol__AoE(udg_ICol__Level[udg_ICol__Count])
set udg_ICol__Lifespan[udg_ICol__Count] = ICol__CoreLifespan(udg_ICol__Level[udg_ICol__Count])
set udg_ICol__SpawnCount[udg_ICol__Count] = ICol__Count(udg_ICol__Level[udg_ICol__Count])
set udg_ICol__Duration[udg_ICol__Count] = ICol__Duration(udg_ICol__Level[udg_ICol__Count])
set udg_ICol__DistanceMin[udg_ICol__Count] = ICol__MinDistance(udg_ICol__Level[udg_ICol__Count])
set udg_ICol__DistanceMax[udg_ICol__Count] = ICol__MaxDistance(udg_ICol__Level[udg_ICol__Count])
set udg_ICol__HeightMin[udg_ICol__Count] = ICol__MinHeight(udg_ICol__Level[udg_ICol__Count])
set udg_ICol__HeightMax[udg_ICol__Count] = ICol__MaxHeight(udg_ICol__Level[udg_ICol__Count])
set udg_ICol__DelayMin[udg_ICol__Count] = ICol__MinDelay(udg_ICol__Level[udg_ICol__Count])
set udg_ICol__DelayMax[udg_ICol__Count] = ICol__MaxDelay(udg_ICol__Level[udg_ICol__Count])
set udg_ICol__Delay[udg_ICol__Count] = GetRandomReal(udg_ICol__DelayMin[udg_ICol__Count], udg_ICol__DelayMax[udg_ICol__Count])
if udg_ICol__Count == 1 then
call TimerStart(udg_ICol__Timer, ICol__Interval(), true, function ICol__periodic)
endif
// Use hashtable to avoid casting collision (if channeling)
if ICol__Channeling() then
set h = GetHandleId(udg_ICol__Caster[udg_ICol__Count])
if HaveSavedInteger(udg_ICol__Hashtable, h, 0) then
set udg_ICol__Dispose[LoadInteger(udg_ICol__Hashtable, h, 0)] = true
endif
call SaveInteger(udg_ICol__Hashtable, h, 0, udg_ICol__Count)
endif
endif
return false
endfunction
// Initialization
function InitTrig_Infernal_Collapse takes nothing returns nothing
if ICol__Channeling() then
set udg_ICol__Hashtable = InitHashtable()
endif
set udg_ICol__Timer = CreateTimer()
set udg_ICol__Orb__Timer = CreateTimer()
set udg_ICol__TempGroup = CreateGroup()
set udg_ICol__TempLoc = Location(0, 0)
set gg_trg_Infernal_Collapse = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(gg_trg_Infernal_Collapse, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(gg_trg_Infernal_Collapse, Condition(function ICol__onCast))
endfunction
//***********************************************************************************\\
//***********************************************************************************\\
// This spell is called: \\
// - D E S T R U T I V E S L A S H \\
// By: \\
// - Elphis - Nyuu \\
// Version: \\
// - v1.1 \\
// How to import: \\
// - Open this spell and copy Destructive Slash trigger, \\
// copy Destructive Slash, Destructive Slash \\
// ability, Destructive Slash buff, Dummy caster \\
// and change the rawcode \\
// (Ctrl + D to see the rawcode) if needed \\
// you may play with spell configuration below and have fun!\\
//***********************************************************************************\\
//***********************************************************************************\\
library DestructiveSlash
// S P E L L C O N F I G U R A T I O N \\
globals
//Spell rawcode, change if needed
private constant integer SPELL_ID = 'A01H'
//Dummy spell rawcode, change if needed
private constant integer DSPELL_ID = 'A01|'
//Spell buff rawcode, change if needed
private constant integer BUFF_ID = 'B006'
//Dummy rawcode, change if needed
private constant integer CASTER_DUMMY = 'e001'
//Spell periodic, decrease this value = fast ecxecution
private constant real PERIODIC = .031250000
//Caster speed animation, decrease this value = the caster play animation more slower
private constant real SPEED_ANIMATION = 1.
//Default scale of the caster when this spell end
private constant real DEFAULT_SCALE = 1.20
//Max scale of the caster when spell running
private constant real MAX_SCALE = 3.
//Min scale of the caster increase per periodic
private constant real MIN_SCALE = 0.13
//Damage radius
private constant real DAMAGE_RADIUS = 125.
//Spell damage base
private constant real DAMAGE_BASE = 70.
//Min distance per loop integer (100. distance = 1 integer = 1 efect, 1000. distance = 10 integer = 10 effect)
private constant real MIN_DISTANCE = 100.
//Effect when the caster fire the ground
private constant real SWORD_DISTANCE = 200.
//***************************Damage Weapon Settings***************************
private constant attacktype AT = ATTACK_TYPE_HERO
private constant damagetype DT = DAMAGE_TYPE_FIRE
private constant weapontype WT = WEAPON_TYPE_AXE_MEDIUM_CHOP
//****************************************************************************
//Animation of the caster play when this spell is actived
private constant string ANIMATION = "slam"
//Effect of the spell when the caster fire the ground
private constant string EFFECT = "Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl"
//Order id of the dummy spell
private constant string ORDER_ID = "doom"
// N O N - C O N F I G U R A T I O N \\
private constant timer TIMER = CreateTimer()
private constant group G = CreateGroup()
private integer M = -1
private integer array SM
private unit Dummy
//***********************************************************************************
endglobals
//*******************Damage Settings***********************************
/**/private constant function Damage takes integer lvl returns real
/**/ return DAMAGE_BASE*lvl
/**/endfunction
//*********************************************************************
//*******************Filter Function***********************************
/**/function filterFunc takes unit filterUnit,player playe returns boolean
/**/ //Assure a better death check//
/**/return not IsUnitType(filterUnit,UNIT_TYPE_DEAD) and /**/GetUnitTypeId(filterUnit) != 0/**/ and IsUnitEnemy(filterUnit,playe)
/**/endfunction
//********************************************************************
private struct DestructiveSlash
unit caster = null
unit dummy = null
boolean active = false
integer lvl
real scale = DEFAULT_SCALE
real dmg
real tx
real ty
real dec_scale = MIN_SCALE*2
static method onPeriodic takes nothing returns nothing
local integer i = 0
local integer ec
local real md
local real x
local real y
local real cx
local real cy
local real a
local real cos
local real sin
local integer distance
local unit f = null
local player p = null
local thistype this
loop
exitwhen i > M
set this = SM[i]
if scale < MAX_SCALE and not active then
set scale = scale + MIN_SCALE
else
if not active then
//Attention!: The code below just run once !
set active = true
set ec = 0
set a = Atan2(ty-GetUnitY(caster),tx-GetUnitX(caster))
set cos = Cos(a)
set sin = Sin(a)
set cx = GetUnitX(caster) + SWORD_DISTANCE * cos
set cy = GetUnitY(caster) + SWORD_DISTANCE * sin
set x = tx - cx
set y = ty - cy
set distance = R2I(SquareRoot(x*x+y*y))
set p = GetOwningPlayer(caster)
set md = 0.
loop
exitwhen ec > distance/MIN_DISTANCE
set x = cx + md * cos
set y = cy + md * sin
set md = md + MIN_DISTANCE
call DestroyEffect(AddSpecialEffect(EFFECT,x,y))
call GroupEnumUnitsInRange(G,x,y,DAMAGE_RADIUS,null)
call SetUnitAbilityLevel(Dummy,DSPELL_ID,lvl)
loop
set f = FirstOfGroup(G)
exitwhen f == null
if filterFunc(f,p) then
call UnitDamageTarget(caster,f,dmg,true,false,AT,DT,WT)
if GetUnitAbilityLevel(f,BUFF_ID) == 0 then
call SetUnitX(Dummy,GetUnitX(f))
call SetUnitY(Dummy,GetUnitY(f))
call IssueTargetOrder(Dummy,ORDER_ID,f)
endif
endif
call GroupRemoveUnit(G,f)
endloop
set ec = ec + 1
endloop
set p = null
elseif scale > DEFAULT_SCALE then
set scale = scale - dec_scale
else
call SetUnitTimeScale(caster,DEFAULT_SCALE)
set caster = null
set SM[i] = SM[M]
set SM[M] = -2
set M = M - 1
if M == -1 then
call PauseTimer(TIMER)
endif
endif
endif
call SetUnitScale(caster,scale,0.,0.)
set i = i + 1
endloop
endmethod
static method onCast takes nothing returns boolean
local thistype this
if GetSpellAbilityId() == SPELL_ID then
set this = allocate()
set M = M + 1
set SM[M] = this
set tx = GetSpellTargetX()
set ty = GetSpellTargetY()
set caster = GetTriggerUnit()
set lvl = GetUnitAbilityLevel(caster,SPELL_ID)
call SetUnitAnimation(caster,ANIMATION)
call SetUnitTimeScale(caster,SPEED_ANIMATION)
set dmg = Damage(lvl)
if M == 0 then
call TimerStart(TIMER,PERIODIC,true,function thistype.onPeriodic)
endif
endif
return false
endmethod
static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
local integer i = 0
loop
exitwhen i > 15
call TriggerRegisterPlayerUnitEvent(t,Player(i),EVENT_PLAYER_UNIT_SPELL_EFFECT,null)
set i = i + 1
endloop
call TriggerAddCondition(t,function thistype. onCast)
set Dummy = CreateUnit(Player(15),CASTER_DUMMY,0.,0.,0.)
endmethod
endstruct
endlibrary
// ********************************************************
// *
// * Chaosflare Orb v1.4
// * by Quilnez
// *
// * Description:
// * Summons the Chaosflare Orb at target point which
// * triggers the sky to periodically strike upon it
// * with powerful lightnings. The orb will convert it
// * into smaller electric pulses which will be released
// * at random direction. Enemy units got hit by these
// * pulses will receive minor damage and will be slowed
// * for a short duration.
// *
// * Requirement(s):
// * None
// *
// * How to import:
// * • Copy "Chaosflare Orb" trigger group to your map
// * • Delete variable creator trigger
// * • Export all necessary import data to your map
// * • Copy dummy unit (Object Editor) to your map
// * • Copy abilities and buff (Object Editor) to your map
// * • Configure the spell
// *
// * Credits:
// * • BTNDarkSphere By Darkfang
// * • Dark Lightning.mdx By JetFangInferno
// * • HydraLightingOrbGroundEffectV044.mdx By kellym0
// * • LightningStrikeLarge.mdx By Callahan
// * • Haunt.mdx By nGy
// * • Shockwave.mdx By Vestras
// * • VoidSkullAura_v5.mdx By xyzier_24
// * (All models are edited to fulfill the
// * needs of this spell)
// *
// ********************************************************
// ********************************************************
// * Configuration
// *
// * Dummy unit's raw code at object editor
constant function CfO__DummyID takes nothing returns integer
return 'h001'
endfunction
// *
// * Main ability's raw code at object editor
constant function CfO__SpellID takes nothing returns integer
return 'A01N'
endfunction
// *
// * Slow ability's raw code at object editor
constant function CfO__SlowSpellID takes nothing returns integer
return 'A01M'
endfunction
// *
// * Slow buff's raw code at object editor
constant function CfO__SlowBuffID takes nothing returns integer
return 'B007'
endfunction
// *
// * Main ability's order id
constant function CfO__OrderID takes nothing returns integer
return 852089 // blizzard
endfunction
// *
// * Slow ability's order id
constant function CfO__SlowSpellOrderID takes nothing returns integer
return 852096 // thunderclap
endfunction
// *
// * If true, the spell will be canceled if caster is given another order
constant function CfO__Channeling takes nothing returns boolean
return true
endfunction
// *
// * If true, the slow duration will be stackable
constant function CfO__Stacking takes nothing returns boolean
return true
endfunction
// *
// * Lightning strike effect model path
constant function CfO__LightningFX takes nothing returns string
return "war3mapImported\\DarkLightning.mdx"
endfunction
// *
// * Orb's aura effect model path
constant function CfO__AuraFX takes nothing returns string
return "war3mapImported\\VoidSkullAura_v5.mdx"
endfunction
// *
// * Wave effect model path (lightning strikes the ground)
constant function CfO__WaveFX takes nothing returns string
return "war3mapImported\\Shockwave.mdx"
endfunction
// *
// * Orb model path
constant function CfO__OrbFX takes nothing returns string
return "war3mapImported\\Haunt_v2.mdx"
endfunction
// *
// * Missile model path
constant function CfO__MissileFX takes nothing returns string
return "war3mapImported\\HydraLightingOrbGroundEffectV044.mdx"
endfunction
// *
// * Hit effect model path
constant function CfO__HitFX takes nothing returns string
return "war3mapImported\\ShockTarget.mdx"
endfunction
// *
// * Hit effect attachment point
constant function CfO__HitFXPt takes nothing returns string
return "origin"
endfunction
// *
// * Missile's launch Z height
constant function CfO__MissileHeight takes nothing returns real
return 15.0
endfunction
// *
// * Missile's scale
constant function CfO__MissileSize takes nothing returns real
return 1.0
endfunction
// *
// * Minimum delay for missiles to turn
constant function CfO__MissileTurnDelayMin takes nothing returns real
return 0.075
endfunction
// *
// * Maximum delay for missiles to turn
constant function CfO__MissileTurnDelayMax takes nothing returns real
return 0.5
endfunction
// *
// * Minimum turn amount (in radians) for missiles
constant function CfO__MissileTurnAmountMin takes nothing returns real
return 45.0*bj_DEGTORAD
endfunction
// *
// * Maximum turn amount (in radians) for missiles
constant function CfO__MissileTurnAmountMax takes nothing returns real
return 180.0*bj_DEGTORAD
endfunction
// *
// * How fast missiles may turn
constant function CfO__MissileTurnRate takes nothing returns real
return 10.0*bj_DEGTORAD
endfunction
// *
// * Orb's scale
constant function CfO__OrbSize takes nothing returns real
return 1.0
endfunction
// *
// * Orb's spawn Z height
constant function CfO__OrbHeight takes nothing returns real
return 150.0
endfunction
// *
// * Orb's aura's scale
constant function CfO__AuraSize takes nothing returns real
return 1.5
endfunction
// *
// * Orb's aura's Z height
constant function CfO__AuraHeight takes nothing returns real
return 0.0
endfunction
// *
// * Maximum range for misilles to hit a target
constant function CfO__HitRadius takes nothing returns real
return 100.0
endfunction
// *
// * Better to leave this one as it is
constant function CfO__Interval takes nothing returns real
return 0.03125
endfunction
// *
// * Spread factor for missile launching, must be between 0 - 1
constant function CfO__Accuracy takes nothing returns real
return 0.25
endfunction
// *
// * If true, each missile will home for one target
constant function CfO__Homing takes integer level returns boolean
return false
endfunction
// *
// * If true, each missile will look for another target after a hit
constant function CfO__SmartHoming takes nothing returns boolean
return false
endfunction
// *
// * Maximum range for missile to obtain a target
constant function CfO__DetectRadius takes integer level returns real
return 200.0
endfunction
// *
// * Delay before another lightning strikes the orb
constant function CfO__StrikeDelay takes integer level returns real
return 2.5
endfunction
// *
// * Delay between the strike and before the missiles are launched
constant function CfO__ReleaseDelay takes integer level returns real
return 0.375
endfunction
// *
// * Speed of missiles
constant function CfO__Velocity takes integer level returns real
return 30.0
endfunction
// *
// * Minimum wander distance for every missile
constant function CfO__DistanceMin takes integer level returns real
return 800.0
endfunction
// *
// * Maximum wander distance for every missile
constant function CfO__DistanceMax takes integer level returns real
return 1600.0
endfunction
// *
// * Damage dealt on hit
constant function CfO__Damage takes integer level returns real
return 20.0 * level
endfunction
// *
// * Orb's lifespan
constant function CfO__Duration takes integer level returns real
return 10.0
endfunction
// *
// * Number of missiles releashed per strike
constant function CfO__ReleaseCount takes integer level returns integer
return 8 + 0 * level
endfunction
// *
// * Slow duration
constant function CfO__SlowDuration takes integer level returns real
return 1.5
endfunction
// *
// * Attack type of dealt damage
constant function CfO__AttackType takes nothing returns attacktype
return ATTACK_TYPE_MAGIC
endfunction
// *
// * Damage type of dealt damage
constant function CfO__DamageType takes nothing returns damagetype
return DAMAGE_TYPE_LIGHTNING
endfunction
// *
// * Weapon type of dealt damage
constant function CfO__WeaponType takes nothing returns weapontype
return WEAPON_TYPE_WHOKNOWS
endfunction
// *
// * No need to touch this
function CfO__isAlive takes unit id returns boolean
return GetWidgetLife(id) > 0.405 and not IsUnitType(id, UNIT_TYPE_DEAD)
endfunction
// *
// * Classification of unit that can be a victim of the missiles
function CfO__Targets takes unit target, player source returns boolean
return CfO__isAlive(target) and IsUnitEnemy(target, source) and not(IsUnitType(target, UNIT_TYPE_STRUCTURE) or IsUnitType(target, UNIT_TYPE_MECHANICAL) or IsUnitType(target, UNIT_TYPE_FLYING) or IsUnitType(target, UNIT_TYPE_MAGIC_IMMUNE))
endfunction
// *
// * This is where you can do additional actions on damage event (missile hits a target)
function CfO__OnDamage takes unit target, unit caster, integer level returns nothing
endfunction
// *
// * This is where you can do additional actions when an orb is struck by lightning
// * caster = spell's caster, level = spell's level, x & y = location where the spell is located
function CfO__OnStrike takes unit caster, integer level, real x, real y returns nothing
endfunction
// *
// * This is where you can do additional actions when missiles are going to be released
// * caster = spell's caster, level = spell's level, x & y = location where the spell is located
function CfO__OnRelease takes unit caster, integer level, real x, real y returns nothing
endfunction
// *
// * This is where you can do additional actions before the spell is ended
// * caster = spell's caster, level = spell's level, x & y = location where the spell is located
function CfO__OnDispose takes unit caster, integer level, real x, real y returns nothing
endfunction
// *
// * This is where you can do additional actions before a missile is removed
// * caster = spell's caster, level = spell's level, x & y = location of the missile
function CfO__OnMissileDispose takes unit caster, integer level, real x, real y returns nothing
endfunction
// *
// * End of Configuration
// *
// ********************************************************
// Check whether passed coordinate is inside the world or not
function CfO__isInBound takes real x, real y returns boolean
return x > udg_CfO__WorldBounds[0] and x < udg_CfO__WorldBounds[1] and y > udg_CfO__WorldBounds[2] and y < udg_CfO__WorldBounds[3]
endfunction
// Allows custom filter by user to be used by unit enumeration filter
function CfO__filter takes nothing returns boolean
return CfO__Targets(GetFilterUnit(), udg_CfO__Owner[udg_CfO__Missile__Source[udg_CfO__TempInt]]) and not IsUnitInGroup(GetFilterUnit(), udg_CfO__Missile__Targets[udg_CfO__TempInt])
endfunction
function CfO__slow takes nothing returns nothing
local integer c
local integer h
local integer i = 1
local boolean dispose
loop
exitwhen i > udg_CfO__Slow__Count
set dispose = false
if CfO__isAlive(udg_CfO__Slow__Target[i]) then
set udg_CfO__Slow__Duration[i] = udg_CfO__Slow__Duration[i] - CfO__Interval()
if udg_CfO__Slow__Duration[i] <= 0 then
set h = GetHandleId(udg_CfO__Slow__Target[i])
if CfO__Stacking() then
set dispose = true
call SaveInteger(udg_CfO__Hashtable, h, 1, 0)
else
set c = LoadInteger(udg_CfO__Hashtable, h, 1) - 1
call SaveInteger(udg_CfO__Hashtable, h, 1, c)
if c == 0 then
set dispose = true
endif
endif
endif
else
set dispose = true
endif
if dispose then
call UnitRemoveAbility(udg_CfO__Slow__Target[i], CfO__SlowBuffID())
set udg_CfO__Slow__Target[i] = udg_CfO__Slow__Target[udg_CfO__Slow__Count]
set udg_CfO__Slow__Duration[i] = udg_CfO__Slow__Duration[udg_CfO__Slow__Count]
set udg_CfO__Slow__Target[udg_CfO__Slow__Count] = null
set udg_CfO__Slow__Count = udg_CfO__Slow__Count - 1
if udg_CfO__Slow__Count == 0 then
call PauseTimer(udg_CfO__Slow__Timer)
else
set i = i - 1
endif
endif
set i = i + 1
endloop
endfunction
function CfO__applySlow takes integer source, unit target returns nothing
local integer h
local integer c
set h = GetHandleId(target)
if CfO__Stacking() then
set c = LoadInteger(udg_CfO__Hashtable, h, 1)
if c == 0 then
set udg_CfO__Slow__Count = udg_CfO__Slow__Count + 1
set udg_CfO__Slow__Target[udg_CfO__Slow__Count] = target
set udg_CfO__Slow__Duration[udg_CfO__Slow__Count] = CfO__SlowDuration(udg_CfO__Level[source])
call SetUnitX(udg_CfO__Slow__Caster, GetUnitX(target))
call SetUnitY(udg_CfO__Slow__Caster, GetUnitY(target))
call IssueImmediateOrderById(udg_CfO__Slow__Caster, CfO__SlowSpellOrderID())
call SaveInteger(udg_CfO__Hashtable, h, 1, udg_CfO__Slow__Count)
else
set udg_CfO__Slow__Duration[c] = udg_CfO__Slow__Duration[c] + CfO__SlowDuration(udg_CfO__Level[source])
endif
else
set udg_CfO__Slow__Count = udg_CfO__Slow__Count + 1
set udg_CfO__Slow__Target[udg_CfO__Slow__Count] = target
set udg_CfO__Slow__Duration[udg_CfO__Slow__Count] = CfO__SlowDuration(udg_CfO__Level[source])
set c = LoadInteger(udg_CfO__Hashtable, h, 1) + 1
call SaveInteger(udg_CfO__Hashtable, h, 1, c)
if c == 1 then
call SetUnitX(udg_CfO__Slow__Caster, GetUnitX(target))
call SetUnitY(udg_CfO__Slow__Caster, GetUnitY(target))
call IssueImmediateOrderById(udg_CfO__Slow__Caster, CfO__SlowSpellOrderID())
endif
endif
if udg_CfO__Slow__Count == 1 then
call TimerStart(udg_CfO__Slow__Timer, CfO__Interval(), true, function CfO__slow)
endif
endfunction
// Periodic callback for missiles
function CfO__missile takes nothing returns nothing
local integer i = 1
local boolean dispose
local unit fog
loop
exitwhen i > udg_CfO__Missile__Count
set dispose = false
if udg_CfO__Missile__Distance[i] > udg_CfO__Velocity[udg_CfO__Missile__Source[i]] and CfO__isAlive(udg_CfO__Caster[udg_CfO__Missile__Source[i]]) then
// If don't have valid target
if udg_CfO__Missile__Target[i] == null or not CfO__isAlive(udg_CfO__Missile__Target[i]) then
if udg_CfO__Missile__TurnDelay[i] > CfO__Interval() then
set udg_CfO__Missile__TurnDelay[i] = udg_CfO__Missile__TurnDelay[i] - CfO__Interval()
else
set udg_CfO__Missile__TurnDelay[i] = GetRandomReal(CfO__MissileTurnDelayMin(), CfO__MissileTurnDelayMax())
set udg_CfO__Missile__AngleX[i] = udg_CfO__Missile__Angle[i] + GetRandomReal(CfO__MissileTurnAmountMin(), CfO__MissileTurnAmountMax()) * GetRandomInt(-1, 1)
endif
if CfO__Homing(udg_CfO__Level[udg_CfO__Missile__Source[i]]) then
set udg_CfO__TempInt = i
call GroupEnumUnitsInRange(udg_CfO__TempGroup, udg_CfO__Missile__X[i], udg_CfO__Missile__Y[i], CfO__DetectRadius(udg_CfO__Level[udg_CfO__Missile__Source[i]]), Filter(function CfO__filter))
set udg_CfO__Missile__Target[i] = GroupPickRandomUnit(udg_CfO__TempGroup)
call GroupClear(udg_CfO__TempGroup)
endif
else
// Set target angle to the location of target
set udg_CfO__Missile__AngleX[i] = Atan2(GetUnitY(udg_CfO__Missile__Target[i]) - udg_CfO__Missile__Y[i], GetUnitX(udg_CfO__Missile__Target[i]) - udg_CfO__Missile__X[i])
endif
// Adjust missile's angle to the target
if CfO__MissileTurnRate() > 0 and Cos(udg_CfO__Missile__Angle[i]-udg_CfO__Missile__AngleX[i]) < Cos(CfO__MissileTurnRate()) then
if Sin(udg_CfO__Missile__AngleX[i]-udg_CfO__Missile__Angle[i]) >= 0 then
set udg_CfO__Missile__Angle[i] = udg_CfO__Missile__Angle[i] + CfO__MissileTurnRate()
else
set udg_CfO__Missile__Angle[i] = udg_CfO__Missile__Angle[i] - CfO__MissileTurnRate()
endif
else
set udg_CfO__Missile__Angle[i] = udg_CfO__Missile__AngleX[i]
endif
set udg_CfO__Missile__X[i] = udg_CfO__Missile__X[i] + udg_CfO__Velocity[udg_CfO__Missile__Source[i]]*Cos(udg_CfO__Missile__Angle[i])
set udg_CfO__Missile__Y[i] = udg_CfO__Missile__Y[i] + udg_CfO__Velocity[udg_CfO__Missile__Source[i]]*Sin(udg_CfO__Missile__Angle[i])
set udg_CfO__Missile__Distance[i] = udg_CfO__Missile__Distance[i] - udg_CfO__Velocity[udg_CfO__Missile__Source[i]]
// Move missile and detect for reachable targets
if CfO__isInBound(udg_CfO__Missile__X[i], udg_CfO__Missile__Y[i]) then
call SetUnitX(udg_CfO__Missile__Dummy[i], udg_CfO__Missile__X[i])
call SetUnitY(udg_CfO__Missile__Dummy[i], udg_CfO__Missile__Y[i])
call GroupEnumUnitsInRange(udg_CfO__TempGroup, udg_CfO__Missile__X[i], udg_CfO__Missile__Y[i], CfO__HitRadius(), null)
loop
set fog = FirstOfGroup(udg_CfO__TempGroup)
exitwhen fog == null
call GroupRemoveUnit(udg_CfO__TempGroup, fog)
if CfO__Targets(fog, udg_CfO__Owner[udg_CfO__Missile__Source[i]]) and not IsUnitInGroup(fog, udg_CfO__Missile__Targets[i]) then
call GroupAddUnit(udg_CfO__Missile__Targets[i], fog)
call DestroyEffect(AddSpecialEffectTarget(CfO__HitFX(), fog, CfO__HitFXPt()))
call UnitDamageTarget(udg_CfO__Caster[udg_CfO__Missile__Source[i]], fog, udg_CfO__Damage[udg_CfO__Missile__Source[i]], false, false, CfO__AttackType(), CfO__DamageType(), CfO__WeaponType())
call CfO__OnDamage(fog, udg_CfO__Caster[udg_CfO__Missile__Source[i]], udg_CfO__Level[udg_CfO__Missile__Source[i]])
if CfO__isAlive(fog) then
call CfO__applySlow(udg_CfO__Missile__Source[i], fog)
endif
if CfO__SmartHoming() and CfO__Homing(udg_CfO__Level[udg_CfO__Missile__Source[i]]) then
set udg_CfO__Missile__Target[i] = null
endif
endif
endloop
else
set dispose = true
endif
else
set dispose = true
endif
if dispose then
call CfO__OnMissileDispose(udg_CfO__Caster[udg_CfO__Missile__Source[i]], udg_CfO__Level[udg_CfO__Missile__Source[i]], udg_CfO__Missile__X[i], udg_CfO__Missile__Y[i])
// Detach disposed missile from the system
call UnitApplyTimedLife(udg_CfO__Missile__Dummy[i], 'BTLF', 5.0)
call DestroyEffect(udg_CfO__Missile__Fx[i])
call DestroyGroup(udg_CfO__Missile__Targets[i])
set udg_CfO__MCount[udg_CfO__Missile__Source[i]] = udg_CfO__MCount[udg_CfO__Missile__Source[i]] - 1
if i != udg_CfO__Missile__Count then
// Deindex
set udg_CfO__Missile__Angle[i] = udg_CfO__Missile__Angle[udg_CfO__Missile__Count]
set udg_CfO__Missile__AngleX[i] = udg_CfO__Missile__AngleX[udg_CfO__Missile__Count]
set udg_CfO__Missile__X[i] = udg_CfO__Missile__X[udg_CfO__Missile__Count]
set udg_CfO__Missile__Y[i] = udg_CfO__Missile__Y[udg_CfO__Missile__Count]
set udg_CfO__Missile__Distance[i] = udg_CfO__Missile__Distance[udg_CfO__Missile__Count]
set udg_CfO__Missile__Source[i] = udg_CfO__Missile__Source[udg_CfO__Missile__Count]
set udg_CfO__Missile__Target[i] = udg_CfO__Missile__Target[udg_CfO__Missile__Count]
set udg_CfO__Missile__Targets[i] = udg_CfO__Missile__Targets[udg_CfO__Missile__Count]
set udg_CfO__Missile__TurnDelay[i] = udg_CfO__Missile__TurnDelay[udg_CfO__Missile__Count]
set udg_CfO__Missile__Dummy[i] = udg_CfO__Missile__Dummy[udg_CfO__Missile__Count]
set udg_CfO__Missile__Fx[i] = udg_CfO__Missile__Fx[udg_CfO__Missile__Count]
// Remove leaks
set udg_CfO__Missile__Dummy[udg_CfO__Missile__Count] = null
set udg_CfO__Missile__Target[udg_CfO__Missile__Count] = null
set udg_CfO__Missile__Targets[udg_CfO__Missile__Count] = null
set udg_CfO__Missile__Fx[udg_CfO__Missile__Count] = null
endif
set udg_CfO__Missile__Count = udg_CfO__Missile__Count - 1
if udg_CfO__Missile__Count == 0 then
call PauseTimer(udg_CfO__Missile__Timer)
exitwhen true
else
set i = i - 1
endif
endif
set i = i + 1
endloop
endfunction
// Launch an electric pulse to given direction
function CfO__launch takes integer source, real angle returns nothing
set udg_CfO__Missile__Count = udg_CfO__Missile__Count + 1
set udg_CfO__Missile__Angle[udg_CfO__Missile__Count] = angle*bj_DEGTORAD
set udg_CfO__Missile__AngleX[udg_CfO__Missile__Count] = udg_CfO__Missile__Angle[udg_CfO__Missile__Count] + GetRandomReal(CfO__MissileTurnAmountMin(), CfO__MissileTurnAmountMax()) * GetRandomInt(-1, 1)
set udg_CfO__Missile__X[udg_CfO__Missile__Count] = udg_CfO__X[source]
set udg_CfO__Missile__Y[udg_CfO__Missile__Count] = udg_CfO__Y[source]
set udg_CfO__Missile__Distance[udg_CfO__Missile__Count] = GetRandomReal(CfO__DistanceMin(udg_CfO__Level[source]), CfO__DistanceMax(udg_CfO__Level[source]))
set udg_CfO__Missile__Source[udg_CfO__Missile__Count] = source
set udg_CfO__Missile__Target[udg_CfO__Missile__Count] = null
set udg_CfO__Missile__Targets[udg_CfO__Missile__Count] = CreateGroup()
set udg_CfO__Missile__TurnDelay[udg_CfO__Missile__Count] = GetRandomReal(CfO__MissileTurnDelayMin(), CfO__MissileTurnDelayMax())
set udg_CfO__Missile__Dummy[udg_CfO__Missile__Count] = CreateUnit(udg_CfO__Owner[source], CfO__DummyID(), udg_CfO__X[source], udg_CfO__Y[source], angle)
set udg_CfO__Missile__Fx[udg_CfO__Missile__Count] = AddSpecialEffectTarget(CfO__MissileFX(), udg_CfO__Missile__Dummy[udg_CfO__Missile__Count], "origin")
if UnitAddAbility(udg_CfO__Missile__Dummy[udg_CfO__Missile__Count], 'Amrf') and UnitRemoveAbility(udg_CfO__Missile__Dummy[udg_CfO__Missile__Count], 'Amrf') then
endif
call SetUnitScale(udg_CfO__Missile__Dummy[udg_CfO__Missile__Count], CfO__MissileSize(), 1, 1)
call SetUnitFlyHeight(udg_CfO__Missile__Dummy[udg_CfO__Missile__Count], CfO__MissileHeight(), 0)
if udg_CfO__Missile__Count == 1 then
call TimerStart(udg_CfO__Missile__Timer, CfO__Interval(), true, function CfO__missile)
endif
endfunction
// Periodic callback for orbs
function CfO__periodic takes nothing returns nothing
local integer h
local integer i = 1
local integer j
local real space
loop
exitwhen i > udg_CfO__Count
// If the spell is still ongoing
if udg_CfO__Duration[i] > CfO__Interval() and CfO__isAlive(udg_CfO__Caster[i]) and (not CfO__Channeling() or GetUnitCurrentOrder(udg_CfO__Caster[i]) == CfO__OrderID()) then
set udg_CfO__Duration[i] = udg_CfO__Duration[i] - CfO__Interval()
if udg_CfO__StrikeDelay[i] > CfO__Interval() then
set udg_CfO__StrikeDelay[i] = udg_CfO__StrikeDelay[i] - CfO__Interval()
elseif udg_CfO__ReleaseDelay[i] > CfO__Interval() then
// Play "lightning strike" animation
if udg_CfO__ReleaseDelay[i] == udg_CfO__ReleaseDelayX[i] then
call DestroyEffect(AddSpecialEffectTarget(CfO__LightningFX(), udg_CfO__Orb[i], "origin"))
call DestroyEffect(AddSpecialEffect(CfO__WaveFX(), udg_CfO__X[i], udg_CfO__Y[i]))
call CfO__OnStrike(udg_CfO__Caster[i], udg_CfO__Level[i], udg_CfO__X[i], udg_CfO__Y[i])
endif
set udg_CfO__ReleaseDelay[i] = udg_CfO__ReleaseDelay[i] - CfO__Interval()
else
// Release electric pulses
set udg_CfO__StrikeDelay[i] = udg_CfO__StrikeDelayX[i]
set udg_CfO__ReleaseDelay[i] = udg_CfO__ReleaseDelayX[i]
call CfO__OnRelease(udg_CfO__Caster[i], udg_CfO__Level[i], udg_CfO__X[i], udg_CfO__Y[i])
set space = 360/udg_CfO__ReleaseCount[i]
set j = 0
loop
exitwhen j == udg_CfO__ReleaseCount[i]
set udg_CfO__MCount[i] = udg_CfO__MCount[i] + 1
call CfO__launch(i, space*j + GetRandomReal(-space*CfO__Accuracy(), space*CfO__Accuracy()))
set j = j + 1
endloop
endif
else
if udg_CfO__OrbFx[i] != null then
call CfO__OnDispose(udg_CfO__Caster[i], udg_CfO__Level[i], udg_CfO__X[i], udg_CfO__Y[i])
if CfO__Channeling() then
set h = GetHandleId(udg_CfO__Caster[i])
if LoadInteger(udg_CfO__Hashtable, h, 0) == i then
call SaveInteger(udg_CfO__Hashtable, h, 0, 0)
endif
endif
call UnitApplyTimedLife(udg_CfO__Orb[i], 'BTLF', 5)
call UnitApplyTimedLife(udg_CfO__Aura[i], 'BTLF', 5)
call DestroyEffect(udg_CfO__OrbFx[i])
call DestroyEffect(udg_CfO__AuraFx[i])
set udg_CfO__OrbFx[i] = null
endif
if udg_CfO__MCount[i] <= 0 then
if i != udg_CfO__Count then
// Index correction
if CfO__Channeling() then
call SaveInteger(udg_CfO__Hashtable, GetHandleId(udg_CfO__Caster[udg_CfO__Count]), 0, i)
endif
// Deindex
set udg_CfO__Caster[i] = udg_CfO__Caster[udg_CfO__Count]
set udg_CfO__Owner[i] = udg_CfO__Owner[udg_CfO__Count]
set udg_CfO__X[i] = udg_CfO__X[udg_CfO__Count]
set udg_CfO__Y[i] = udg_CfO__Y[udg_CfO__Count]
set udg_CfO__Orb[i] = udg_CfO__Orb[udg_CfO__Count]
set udg_CfO__OrbFx[i] = udg_CfO__OrbFx[udg_CfO__Count]
set udg_CfO__Aura[i] = udg_CfO__Aura[udg_CfO__Count]
set udg_CfO__AuraFx[i] = udg_CfO__AuraFx[udg_CfO__Count]
set udg_CfO__MCount[i] = udg_CfO__MCount[udg_CfO__Count]
set udg_CfO__Level[i] = udg_CfO__Level[udg_CfO__Count]
set udg_CfO__Velocity[i] = udg_CfO__Velocity[udg_CfO__Count]
set udg_CfO__Duration[i] = udg_CfO__Duration[udg_CfO__Count]
set udg_CfO__ReleaseDelayX[i] = udg_CfO__ReleaseDelayX[udg_CfO__Count]
set udg_CfO__StrikeDelayX[i] = udg_CfO__StrikeDelayX[udg_CfO__Count]
set udg_CfO__ReleaseDelay[i] = udg_CfO__ReleaseDelay[udg_CfO__Count]
set udg_CfO__StrikeDelay[i] = udg_CfO__StrikeDelay[udg_CfO__Count]
set udg_CfO__ReleaseCount[i] = udg_CfO__ReleaseCount[udg_CfO__Count]
// Remove leaks
set udg_CfO__Orb[udg_CfO__Count] = null
set udg_CfO__OrbFx[udg_CfO__Count] = null
set udg_CfO__Aura[udg_CfO__Count] = null
set udg_CfO__AuraFx[udg_CfO__Count] = null
set udg_CfO__Caster[udg_CfO__Count] = null
// Source index corrections
set j = 1
loop
exitwhen j > udg_CfO__Missile__Count
if udg_CfO__Missile__Source[j] == udg_CfO__Count then
set udg_CfO__Missile__Source[j] = i
endif
set j = j + 1
endloop
endif
set udg_CfO__Count = udg_CfO__Count - 1
if udg_CfO__Count == 0 then
call PauseTimer(udg_CfO__Timer)
else
set i = i - 1
endif
endif
endif
set i = i + 1
endloop
endfunction
// On cast event
function CfO__onCast takes nothing returns boolean
local integer h
local integer i
if GetSpellAbilityId() == CfO__SpellID() then
set udg_CfO__Count = udg_CfO__Count + 1
set udg_CfO__Caster[udg_CfO__Count] = GetTriggerUnit()
set udg_CfO__Owner[udg_CfO__Count] = GetTriggerPlayer()
set udg_CfO__X[udg_CfO__Count] = GetSpellTargetX()
set udg_CfO__Y[udg_CfO__Count] = GetSpellTargetY()
set udg_CfO__Orb[udg_CfO__Count] = CreateUnit(udg_CfO__Owner[udg_CfO__Count], CfO__DummyID(), udg_CfO__X[udg_CfO__Count], udg_CfO__Y[udg_CfO__Count], 0)
set udg_CfO__OrbFx[udg_CfO__Count] = AddSpecialEffectTarget(CfO__OrbFX(), udg_CfO__Orb[udg_CfO__Count], "origin")
set udg_CfO__Aura[udg_CfO__Count] = CreateUnit(udg_CfO__Owner[udg_CfO__Count], CfO__DummyID(), udg_CfO__X[udg_CfO__Count], udg_CfO__Y[udg_CfO__Count], 0)
set udg_CfO__AuraFx[udg_CfO__Count] = AddSpecialEffectTarget(CfO__AuraFX(), udg_CfO__Aura[udg_CfO__Count], "origin")
set udg_CfO__MCount[udg_CfO__Count] = 0
set udg_CfO__Level[udg_CfO__Count] = GetUnitAbilityLevel(udg_CfO__Caster[udg_CfO__Count], CfO__SpellID())
set udg_CfO__Velocity[udg_CfO__Count] = CfO__Velocity(udg_CfO__Level[udg_CfO__Count])
set udg_CfO__Damage[udg_CfO__Count] = CfO__Damage(udg_CfO__Level[udg_CfO__Count])
set udg_CfO__Duration[udg_CfO__Count] = CfO__Duration(udg_CfO__Level[udg_CfO__Count])
set udg_CfO__ReleaseDelayX[udg_CfO__Count] = CfO__ReleaseDelay(udg_CfO__Level[udg_CfO__Count])
set udg_CfO__StrikeDelayX[udg_CfO__Count] = CfO__StrikeDelay(udg_CfO__Level[udg_CfO__Count])
set udg_CfO__ReleaseDelay[udg_CfO__Count] = udg_CfO__ReleaseDelayX[udg_CfO__Count]
set udg_CfO__StrikeDelay[udg_CfO__Count] = udg_CfO__StrikeDelayX[udg_CfO__Count]
set udg_CfO__ReleaseCount[udg_CfO__Count] = CfO__ReleaseCount(udg_CfO__Level[udg_CfO__Count])
if UnitAddAbility(udg_CfO__Orb[udg_CfO__Count], 'Amrf') and UnitRemoveAbility(udg_CfO__Orb[udg_CfO__Count], 'Amrf') then
endif
call SetUnitScale(udg_CfO__Orb[udg_CfO__Count], CfO__OrbSize(), 1, 1)
call SetUnitFlyHeight(udg_CfO__Orb[udg_CfO__Count], CfO__OrbHeight(), 0)
if UnitAddAbility(udg_CfO__Aura[udg_CfO__Count], 'Amrf') and UnitRemoveAbility(udg_CfO__Aura[udg_CfO__Count], 'Amrf') then
endif
call SetUnitScale(udg_CfO__Aura[udg_CfO__Count], CfO__AuraSize(), 1, 1)
call SetUnitFlyHeight(udg_CfO__Aura[udg_CfO__Count], CfO__AuraHeight(), 0)
if CfO__Channeling() then
set h = GetHandleId(udg_CfO__Caster[udg_CfO__Count])
set i = LoadInteger(udg_CfO__Hashtable, h, 0)
if i != 0 then
set udg_CfO__Duration[i] = 0
endif
call SaveInteger(udg_CfO__Hashtable, h, 0, udg_CfO__Count)
endif
if udg_CfO__Count == 1 then
call TimerStart(udg_CfO__Timer, CfO__Interval(), true, function CfO__periodic)
endif
endif
return false
endfunction
function InitTrig_Chaosflare_Orb takes nothing returns nothing
// World bounds initialization
set udg_CfO__WorldBounds[0] = GetRectMinX(bj_mapInitialPlayableArea)
set udg_CfO__WorldBounds[1] = GetRectMaxX(bj_mapInitialPlayableArea)
set udg_CfO__WorldBounds[2] = GetRectMinY(bj_mapInitialPlayableArea)
set udg_CfO__WorldBounds[3] = GetRectMaxY(bj_mapInitialPlayableArea)
set udg_CfO__Timer = CreateTimer()
set udg_CfO__Slow__Timer = CreateTimer()
set udg_CfO__Missile__Timer = CreateTimer()
set gg_trg_Chaosflare_Orb = CreateTrigger()
set udg_CfO__Slow__Caster = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), CfO__DummyID(), 0, 0, 0)
call UnitAddAbility(udg_CfO__Slow__Caster, CfO__SlowSpellID())
call TriggerRegisterAnyUnitEventBJ(gg_trg_Chaosflare_Orb, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(gg_trg_Chaosflare_Orb, Condition(function CfO__onCast))
if CfO__Channeling() then
set udg_CfO__Hashtable = InitHashtable()
endif
endfunction