Moderator
M
Moderator
[COLOR="gray" |
What is this?
The BUS is a set of spells (and systems). They are powerful spells designed for bosses with ranging degrees of "flashiness". Each is designed to be able to be imported without the others (though all of them require the channel system) so you only need to take what you want.
Contains:
- Boss Channel (System) (and some default channels to get you started)
- Boss Knockback (System)
- Boss Soul Release (Spell)
- Boss Scathe (Spell)
- Boss Sheer Force (Spell)
- Boss Energy Spike (Spell)
Notes
- Every Ability/System comes with a variable creator specific to that ability/system
- If you want the knockback system but NOT the channel system (why on earth you would) then you'll need to move some of the initialisation for the channel system into the initialisation of the knockback system (Map Bounds variables, ZLoc)
- In the test map abilities can target buildings, this is for demonstration purposes ONLY as they intentionally cannot affect buildings
- All code created in JASS
- Channel System is GUI-Friendly
Boss Channel
What is this? - The boss channel system is designed to make your bosses look more intimidating and powerful when they cast their strong spells by introducing a "charge up" stage to them, it will work with target unit, target point and no target spells. All of the spells included in the BUS start by using this system, so for an idea of how this looks you can skip to the GIFs of each ability in their specific sections
JASS://////////////////////////////////////////////////////////////////// // Boss Ultimate Spellpack Channel V1.02 // // 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 0.1 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 loop set Node = udg_BUSC_NextNode[Node] exitwhen (udg_BUSC_Unit[Node] == u) or (Node == 0) 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 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 exitwhen TempNode == 0 set TempNode = udg_BUSC_PNextNode[TempNode] endloop loop set Node = udg_BUSC_NextNode[Node] exitwhen Node == 0 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 iLoop = 0 loop set iLoop = iLoop + 1 exitwhen iLoop > 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_PPrevNode[0]] = TempNode set udg_BUSC_PPrevNode[TempNode] = udg_BUSC_PPrevNode[0] set udg_BUSC_PPrevNode[0] = TempNode set Angle = GetRandomReal(0, bj_PI * 2) if (IsUnitType(udg_BUSC_Unit[Node], UNIT_TYPE_GROUND)) then set Angle2 = GetRandomReal(BUSCR_GroundMinAngle(), bj_PI - BUSCR_GroundMinAngle()) else set Angle2 = GetRandomReal(-bj_PI, bj_PI) 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) set y2 = y + Distance * Sin(Angle) 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 * bj_RADTODEG + 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 EffectCount = 0 loop set TempNode = udg_BUSC_PNextNode[TempNode] exitwhen TempNode == 0 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]) 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] if (udg_BUSC_NextNode[0] + udg_BUSC_NextNode[0] == 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 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] if (udg_BUSC_NextNode[0] + udg_BUSC_NextNode[0] == 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_PrevNode[0]] = Node set udg_BUSC_PrevNode[Node] = udg_BUSC_PrevNode[0] set udg_BUSC_PrevNode[0] = Node 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_PrevNode[Node] == 0) 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 // ////////////////////////////////////////////////////////////////////
JASS: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
JASS: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
JASS://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 endfunction
- Example 2
- Events
- Unit - A unit Begins channeling an ability
- Conditions
- (Ability being cast) Equal to Channel
- Actions
- Custom script: set udg_BUSC_Cancel[BUS_CheckChannel(Caster)] = true
- Custom script: call BUS_StartChannel(BUS_GetChannelByName("My Channel Type"), Caster, TargetUnit, TargetX., TargetY., ChannelDuration, 6.00, HaveHueChange)
- Example 3
- Events
- Game - BUSC_Event becomes Equal to 6.00
- Conditions
- Actions
- -------- Do whatever you wish here --------
Boss Knockback
What is this? - The boss knockback system is used for the boss abilities that need it, rather it is not designed to be used by other abilities (and thus does not contain extra functionality) although it can be. The knockback is optionally 3D, works on flying units (in 3D) has different decays for units in the air and ground units (ground units that are presently in the air will be treated like air units) and destroys trees for ground units (when they're on the ground) but can optionally instead attempt to simply prevent them from being pushed into trees rather than kill trees they are pushed into.
JASS://////////////////////////////////////////////////////////////////// // 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 'u001' endfunction //----------------------------------------------------------------// // TreeCheckerId: 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 true 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 //----------------------------------------------------------------// // 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 //////////////////////////////////////////////////////////////////// // 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()) endfunction //////////////////////////////////////////////////////////////////// // End of the system // ////////////////////////////////////////////////////////////////////
JASS: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
Boss Soul Release
What is this? - Soul Release is an instant kill attack for your bosses - after targetting a unit the boss will begin to channel, once completed it checks if the unit is still within range, if yes then the unit is killed instantly (as well as doing a small AOE of instant death) though it is not a "true" death so gold rewards and the "kill" are not recorded
Recommended IconJASS://////////////////////////////////////////////////////////////////// // 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 'A000' 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 'u000' 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 // ////////////////////////////////////////////////////////////////////
The caster absorbs powerful magic lingering in the air and focuses it, fashioning it into an almighty strike. If the target does not flee in terror they and all enemies near them are struck down, extracting their souls leaving the lifeless corpses behind
GIF
Boss Scathe
What is this? - Scathe is a satisfying laser ability for bosses to blast away their enemies, after selecting a target the boss begins channeling, once completed the boss aims his laser at the target - after a brief delay (making the ability dodgeable) the laser fires and devestates all caught in the ray (3D Collision)
JASS://////////////////////////////////////////////////////////////////// // 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 'A002' 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 'u000' 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 900.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 250. 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 90. 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 3. 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 2.25 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 // ////////////////////////////////////////////////////////////////////
The caster absorbs powerful magic lingering in the air and focuses it, fashioning it into a powerful laser to blast back its target dealing 900 damage to all enemies caught in the light and throwing them away from the caster
GIF
Boss Sheer Force
What is this? - Sheer Force is a gravity based ability using the force of it to both damage and push enemies away from the caster, it has a fast charge up and use time being the most simple spell in the pack, the ability is instant-cast
JASS://////////////////////////////////////////////////////////////////// // 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 'A003' 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 'u000' 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 4000. 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 .33 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 // ////////////////////////////////////////////////////////////////////
The caster absorbs powerful magic lingering in the air and focuses it, fashioning it into an overwhelming blast, blowing enemies away from the caster dealing damage to enemies based on the amount of force pushing them
GIF
Boss Energy Spike
What is this? - Energy spike is an instant-cast high AOE damage ability with some strong effects to go with it being the most effect-intensive of the pack, after channeling the caster creates multiple giant swords to strike down its enemies, each sword has 3D collision and they slowly pan downward, strongly recommended to be used by flyers or large ground units as too many units being next to the centre of the swords causes lag (and lots and lots of damage) though lowering the amount of swords would help this.
Recommended IconJASS://////////////////////////////////////////////////////////////////// // 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 'A001' 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 'u000' 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 600.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 // ////////////////////////////////////////////////////////////////////
The caster absorbs powerful magic lingering in the air and focuses it, fashioning it into 40 large burning blades, dealing 600 damage per second to enemies that touch them, Casters on the ground have 24 blades and increased damage
GIF