Flare
Stops copies me!
- Reaction score
- 662
A new spin on the Force of Nature ability
Technical details
Made with vJASS
Requires NewGen WE
Uses Vexorian's TimerUtils and a custom function library I made
Lagless
Leakless (to my knowledge)
Description:
Fires an orb filled with natural energy towards a target point - any trees in the way will be converted into a Treant. Each level increases the maximum Treants spawnable. If the maximum number of Treants isn't reached when the orb is destroyed, new trees will be spawned and converted to Treants when fully grown
Screenshots:
Importing:
Code:
Spell code
GAC library code
(if you want me to bundle the GAC library in with the spell's code, let me know)
Credits:
The usual - if you use this spell in your map, please credit me for making it
The rest:
If you find any bugs/leaks/suggestions/lack of configuration anywhere in the spell, let me know, or if I've left anything out of the thread
Updates:
Technical details
Made with vJASS
Requires NewGen WE
Uses Vexorian's TimerUtils and a custom function library I made
Lagless
Leakless (to my knowledge)
Description:
Fires an orb filled with natural energy towards a target point - any trees in the way will be converted into a Treant. Each level increases the maximum Treants spawnable. If the maximum number of Treants isn't reached when the orb is destroyed, new trees will be spawned and converted to Treants when fully grown
Screenshots:
Importing:
Code:
(1) Copy the FON and GAC triggers into your map
(2) If you don't already have a variant of TimerUtils in your map, copy the TimerUtils trigger into your map
(3) Copy the FoN dummy unit (h000) into your map
(4) Copy the Force of Nature (new) ability (A000) into your map
(5) Modify the SID and DID constants within the FON trigger to match the rawcodes of the FoN dummy unit and the Force of Nature (new) ability
(6) Modify the available constants in the FON/GAC triggers to suit your needs
(7) Enjoy!
Code:
Spell code
JASS:
//Force of Nature (New)
//By Flare
//Requires: This trigger
// GAC library
// Vexorian's TimerUtils
// The FoN dummy unit ('h000')
// The Force of Nature (new) ability ('A000')
// NewGen World Editor
//NOTE: Change the Stats - Duration field in the Object Editor to change the number of Treants per level in the tooltip (this doesn't affect actual number spawned)
scope FON initializer FONInit
private keyword FONData
globals
//Configurable arrays (not using constants since it'd be insane)
//Use the ArraySetup function to alter this stuff
//Rawcodes of all trees usable by this spell
private integer array TREES
//Rawcodes of the spawned treants
private integer array SPAWNS
//Constant configurables
//Ability rawcode
private constant integer SID = 039;A000039;
//Dummy rawcode
private constant integer DID = 039;h000039;
//Set this to the total number of applicable targets (i.e. ID's defined in the TREES array)
private constant integer TOTALTREES = 9
//Rawcode of trees spawned specifically for conversion
private constant integer TREESPAWNID = 039;ATtr039;
//Time taken for the birth animation of the above tree
private constant real BIRTHTIME = 3.
//Determines whether spawned trees are removed when converted, or left as stumps (true = remove, false = leave as stumps)
private constant boolean REMOVESPAWNED = true
//Timer interval (for dummy movement)
private constant real INTERVAL = 0.03125
//Speed/sec of the dummy
private constant real SPEEDPERSEC = 800.
//Speed/timer interval of the dummy
private constant real MOVEDIST = SPEEDPERSEC*INTERVAL
//Collision radius of projectile - determines how far away from a tree you must be to convert
//DOES NOT AFFECT END RADIUS
private constant real COLLRAD = 150
//Determines whether treants should be spawned at the end, if the total treant count hasn't been reached from colliding with trees/end effect
private constant boolean SPAWNREM = true
//SFX string used for destroying trees
private constant string FXSTRING = ""//"Abilities\\Spells\\Undead\\AnimateDead\\AnimateDeadTarget.mdl"
//Animation string played when Treants are created
private constant string ANIMSTRING = "birth"
//Queued animation string after above animation is played
private constant string NEXTANIM = "stand"
//Expiration timer ID
private constant integer EXPID = 039;BTLF039;
//Spawned tree's offset
private constant real OFFSET = 75
endglobals
//Determines end radius of the spell
private function GetRadius takes unit u returns real
local real base = 150
local real m1 = I2R (GetUnitAbilityLevel (u, SID))
local real m2 = 50
return base + m1*m2
endfunction
//Determines the maximum number of Treants per level
private function GetTotalTreants takes unit u returns integer
local integer base = 1
local integer m1 = GetUnitAbilityLevel (u, SID)
local integer m2 = 1
return base + m1 * m2
endfunction
//Determines the duration of spawned Treants
private function GetDuration takes unit u returns real
local real base = 30
local real m1 = I2R (GetUnitAbilityLevel (u, SID))
local real m2 = 10
return base + m1 * m2
endfunction
//This is for setting up the destructables which are applicable for conversion, and the spawn ID's (for each level)
private function ArraySetup takes nothing returns nothing
//Spawned unit ID's (I'm being lazy, so I'm just gonna use default FoN treant for all levels)
set SPAWNS[0] = 039;efon039;
set SPAWNS[1] = 039;efon039;
set SPAWNS[2] = 039;efon039;
//I'm only adding some of the trees (since I honestly can't be arsed to add every single possible tree that's available
//Anyway, it's not too difficult to add them
//Just add this
//set TREES[X] = rawcode
//where X is the next number available to be used in the arrays
//and update the value for TOTALTREES to match the number of values set in the list
//TOTALTREES should be LASTARRAYVALUE + 1 (if you're doing things correctly)
//In this case, it's (8 + 1 =) 9
set TREES[0] = 039;ATtr039;
set TREES[1] = 039;BTtw039;
set TREES[2] = 039;KTtw039;
set TREES[3] = 039;YTft039;
set TREES[4] = 039;JTct039;
set TREES[5] = 039;YTst039;
set TREES[6] = 039;YTct039;
set TREES[7] = 039;YTwt039;
set TREES[8] = 039;JTtw039;
endfunction
//End of configuration
//-------------------------
globals
private FONData z
endglobals
private function SetUnitXY takes unit u,real x,real y returns nothing
if x<GetRectMaxX(bj_mapInitialPlayableArea) and x>GetRectMinX(bj_mapInitialPlayableArea) and y<GetRectMaxY(bj_mapInitialPlayableArea) and y>GetRectMinY(bj_mapInitialPlayableArea) then
call SetUnitX(u,x)
call SetUnitY(u,y)
endif
endfunction
private struct FONData
unit caster
unit dummy
real cos
real sin
real ticks
integer treants = 0
integer maxtreants
endstruct
private function DestructFilter takes nothing returns boolean
local integer i = 0
//call BJDebugMsg ("A DESTRUCTABLE HAS ENTERED THE FILTER OLIOLIOLIOLIO!!! .treants is equal to " + I2S (z.treants))
loop
exitwhen i >= TOTALTREES
if GetDestructableTypeId (GetFilterDestructable ()) == TREES<i> and GetWidgetLife (GetFilterDestructable ()) > .405 then
return true
endif
set i = i + 1
endloop
return false
endfunction
private function DestructActions takes nothing returns nothing
local destructable d = GetEnumDestructable ()
local real x = GetWidgetX (d)
local real y = GetWidgetY (d)
local integer i = GetUnitAbilityLevel (z.caster, SID) - 1
local unit u
if z.treants < z.maxtreants then
call KillDestructable (d)
set u = CreateUnit (GetOwningPlayer (z.caster), SPAWNS<i>, x, y, bj_UNIT_FACING)
call SetUnitX (u, x)
call SetUnitY (u, y)
call UnitApplyTimedLife (u, EXPID, GetDuration (z.caster))
call DestroyEffect (AddSpecialEffect (FXSTRING, x, y))
call SetUnitAnimation (u, ANIMSTRING)
call QueueUnitAnimation (u, NEXTANIM)
set z.treants = z.treants + 1
endif
set u = null
set d = null
endfunction
private function TimerCallback takes nothing returns nothing
local timer t = GetExpiredTimer ()
local FONData a = GetTimerData (t)
local real x = GetUnitX (a.dummy)
local real y = GetUnitY (a.dummy)
local real endradius
local rect r
local rect r2
local integer i = 0
local real angle = GetRandomReal (0, bj_PI * 2)
local real nx
local real ny
set x = x + a.cos * MOVEDIST
set y = y + a.sin * MOVEDIST
call SetUnitXY (a.dummy, x, y)
set a.ticks = a.ticks - MOVEDIST
set r = Rect(x - COLLRAD, y - COLLRAD, x + COLLRAD, y + COLLRAD)
set z = a
call EnumDestructablesInRect (r, Condition (function DestructFilter), function DestructActions)
call RemoveRect (r)
if a.ticks <= 0 then
set endradius = GetRadius (a.caster)
set r = Rect (x - endradius, y - endradius, x + endradius, y + endradius)
call EnumDestructablesInRect (r, Condition (function DestructFilter), function DestructActions)
call RemoveRect (r)
call ReleaseTimer (t)
call KillUnit (a.dummy)
call ShowUnit (a.dummy, false)
if a.treants < a.maxtreants and SPAWNREM then
loop
exitwhen i >= a.maxtreants - a.treants
set nx = x + Cos (angle) * OFFSET
set ny = y + Sin (angle) * OFFSET
call GAC_Start (TREESPAWNID, SPAWNS[GetUnitAbilityLevel (a.caster, SID) - 1], BIRTHTIME, GetOwningPlayer (a.caster), nx, ny, REMOVESPAWNED, FXSTRING, GetDuration (a.caster))
set angle = angle + ((bj_PI*2)/(a.maxtreants - a.treants))
set i = i + 1
endloop
endif
call a.destroy ()
endif
set r = null
set t = null
endfunction
private function Conditions takes nothing returns boolean
return GetSpellAbilityId () == SID
endfunction
private function Actions takes nothing returns nothing
local FONData a = FONData.create ()
local timer t = NewTimer ()
local location l = GetSpellTargetLoc ()
local real cx = GetUnitX (GetTriggerUnit ())
local real cy = GetUnitY (GetTriggerUnit ())
local real tx = GetLocationX (l)
local real ty = GetLocationY (l)
local real x = tx-cx
local real y = ty-cy
local real angle = Atan2 (y, x)
call RemoveLocation (l)
set a.ticks = SquareRoot ((x*x) + (y*y))
set a.caster = GetTriggerUnit ()
set a.dummy = CreateUnit (GetOwningPlayer (a.caster), DID, cx, cy, angle * bj_RADTODEG)
set a.cos = Cos (angle)
set a.sin = Sin (angle)
set a.maxtreants = GetTotalTreants (a.caster)
call SetTimerData (t, a)
call TimerStart (t, INTERVAL, true, function TimerCallback)
set t = null
set l = null
endfunction
private function FONInit takes nothing returns nothing
local trigger t = CreateTrigger ()
call TriggerRegisterAnyUnitEventBJ (t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition (t, Condition (function Conditions))
call TriggerAddAction (t, function Actions)
call ArraySetup ()
endfunction
endscope</i></i>
GAC library code
JASS:
//Grow And Convert library
//By Flare
//Made for Force of Nature (new)
library GAC requires TimerUtils
globals
//Timer interval
private constant real TIMERINT = 0.25
//Tree/spawn facing
private constant real FACING = bj_UNIT_FACING
//Tree variation
private constant integer VARIATION = 1
//Tree scale
private constant real SCALE = 1
//Timed life ID
private constant integer EXPID = 039;BTLF039;
//Animation played by the tree
private constant string TREEANIM = "birth"
//Animation played by spawn when spawned
private constant string SPAWNANIM1 = "birth"
//Animation played by spawn after SPAWNANIM1
private constant string SPAWNANIM2 = "stand"
endglobals
private struct GrowData
integer spawnId
destructable tree
player owner
real ticks
boolean removeOnConv
string sfx
real duration
real t
endstruct
private function TimerCallback takes nothing returns nothing
local GrowData a = GetTimerData (GetExpiredTimer ())
local real x = GetWidgetX (a.tree)
local real y = GetWidgetY (a.tree)
local unit u
set a.ticks = a.ticks - 1
if a.ticks <= 0 then
if a.removeOnConv then
call RemoveDestructable (a.tree)
else
call KillDestructable (a.tree)
endif
call DestroyEffect (AddSpecialEffect (a.sfx, x, y))
set u = CreateUnit (a.owner, a.spawnId, x, y, FACING)
call SetUnitAnimation (u, SPAWNANIM1)
call QueueUnitAnimation (u, SPAWNANIM2)
call UnitApplyTimedLife (u, EXPID, a.duration)
call ReleaseTimer (GetExpiredTimer ())
call a.destroy ()
endif
set u = null
endfunction
public function Start takes integer treeId, integer convertId, real growTime, player convertOwner, real x, real y, boolean remove, string fxString, real spawnDur returns nothing
local GrowData a = GrowData.create ()
local timer t = NewTimer ()
set a.tree = CreateDestructable (treeId, x, y, FACING, SCALE, VARIATION)
call SetDestructableAnimation (a.tree, TREEANIM)
set a.owner = convertOwner
set a.ticks = growTime / TIMERINT
set a.t = a.ticks
set a.removeOnConv = remove
set a.spawnId = convertId
set a.sfx = fxString
set a.duration = spawnDur
call SetTimerData (t, a)
call TimerStart (t, TIMERINT, true, function TimerCallback)
set t = null
endfunction
endlibrary
(if you want me to bundle the GAC library in with the spell's code, let me know)
Credits:
The usual - if you use this spell in your map, please credit me for making it
The rest:
If you find any bugs/leaks/suggestions/lack of configuration anywhere in the spell, let me know, or if I've left anything out of the thread
Updates:
Code:
v1 - Initial release
v2 - Fixed spawned trees spawning if they died before fully grown, added the option to make grown trees invulnerable, spell no longer affects invulnerable trees