function EnableScriptUsage takes nothing returns nothing
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 | |
BUS_Loc | location | No | |
BUS_MapMaxX | real | No | |
BUS_MapMaxY | real | No | |
BUS_MapMinX | real | No | |
BUS_MapMinY | real | No | |
BUS_Target | 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 | |
MPS_ACTIVE_EVENT | real | No | |
MPS_ACTIVE_NODE | integer | No | |
MPS_AmmoNumber | integer | No | |
MPS_AmmoType | integer | Yes | |
MPS_ATTACK_USED | real | No | |
MPS_AttackMasterAmmo | integer | Yes | |
MPS_AttackName | string | Yes | |
MPS_AttackNumber | integer | No | |
MPS_AttackSalvo | integer | Yes | |
MPS_AttackSlaveAmmo | 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_SALVO_FIRED | real | No | |
MPS_SalvoAngles | real | Yes | |
MPS_SalvoHeightOffset | real | Yes | |
MPS_SalvoMasterAmmoAmount | integer | Yes | |
MPS_SalvoName | string | Yes | |
MPS_SalvoNumber | integer | No | |
MPS_SalvoPower | real | Yes | |
MPS_SalvoSlaveAmmoAmount | integer | 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 |
////////////////////////////////////////////////////////////////////
// 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 'u000'
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 'u000'
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 'A000'
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 3
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 3.
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 40.
endfunction
// //
constant function AB_HealthDamagePerLevel takes nothing returns real
return 40.
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 0.
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 600.
endfunction
// //
constant function AB_AOEPerLevel takes nothing returns real
return 100.
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 2.
endfunction
// //
constant function AB_DurationPerLevel takes nothing returns real
return 1.
endfunction
//----------------------------------------------------------------//
// FireRate: This is the amount of projectiles that are fired //
// per second //
constant function AB_FireRateBase takes nothing returns real
return 3.
endfunction
// //
constant function AB_FireRatePerLevel takes nothing returns real
return 1.
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 //
////////////////////////////////////////////////////////////////////