Spell Nature Wall

cr4xzZz

Also known as azwraith_ftL.
Reaction score
51
Nature Wall
nwkw9.jpg


A spell from my map - Mini Ashenvale Arena.

GUI/JASS/vJASS? vJASS.
MUI? Yes.
Leakless? Yes.
Lagless? Yes.
Follows JESP? No.
Requires?
- JASS NewGen Editor v1.5a
- ABCT v2.0
- PUI v5.1

Description:
Creates a wall of vines, branches and leaves across the landcape, creating a strong barrier. Units that pass through the wall will be caught in roots for one second. Released units have 1.5 seconds to get away from the wall or they are caught again. Lasts 15 seconds.
Level 1 - Deals 35 DPS.
Level 2 - Deals 55 DPS.
Level 3 - Deals 80 DPS.

Code:
JASS:
scope NatureWall
// Do not touch this textmacro line! It's PUI attaching!
//! runtextmacro PUI_PROPERTY("private", "boolean", "AGAIN", "false") 

//===========================================================================
//  CONFIGURATION MENU
//===========================================================================
globals
// Raw code of the Nature Wall ability.
    private constant integer AID_NATURE_WALL = 'A000'
// Raw code of the buff that comes with the aura.
    private constant integer BID_NATURE_WALL_AURA = 'B000'
// Raw code of the wall units.
    private constant integer UID_NATURE_WALL_UNIT = 'u000'
// Raw code of the dummy unit.
    private constant integer UID_DUMMY = 'u001'
// Raw code of the ability that is casted when a unit comes near the wall.
    private constant integer AID_NATURE_WALL_ENTANGLE = 'A002'
// String for casting the AID_NATURE_WALL_ENTANGLE ability.
    private constant string SID_ENTANGLE = "entanglingroots"
// Raw code of the destructibles created on the two sides of the wall (in this case - Ashenvale tree).
    private constant integer DID_NATURE_WALL_WOOD = 'ATtr'
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
// Period that is given for the unit to get away from the wall, or it will be entangled again.
    private constant real ENTANGLE_PERIOD = 1.5 
// Period between group picks and special effect creation.
    private constant real PICK_PERIOD = 1.
// Special effect created at each wall unit.
    private constant string SFX_EFFECT = "Objects\\Spawnmodels\\NightElf\\EntBirthTarget\\EntBirthTarget.mdl"
// Scale of the two destructibles created at the wall's sides.
    private constant real TREE_SCALE  = 1.
// Range between wall units (used for creation). 
    private constant integer RANGE = 75
endglobals
// Duration of the wall
    private function DURATION takes unit cast, integer lvl returns real
        // Included the caster because someone might want to base
        // duration on his attributes
        return lvl * 10.
    endfunction
// Number of wall units.
// More units means increased wall length.
    private function N_UNITS takes unit cast, integer lvl returns integer
        // Included the caster because someone might want to base
        // number of units on his attributes.
        return 4 + (lvl * 2)
    endfunction
//===========================================================================
//  END OF CONFIGURATION MENU
//=========================================================================== 

private struct Data
    unit caster
    integer level
    unit array wall[100]
    destructable array wood[3]
    integer ticks
    
    method onDestroy takes nothing returns nothing
        call KillDestructable(.wood[1])
        call KillDestructable(.wood[2])
    endmethod
endstruct

private struct Info
    unit picked
endstruct

private function Conditions takes nothing returns boolean
    return GetSpellAbilityId() == AID_NATURE_WALL
endfunction

private function Filterz takes nothing returns boolean
    return GetUnitAbilityLevel(GetFilterUnit(), BID_NATURE_WALL_AURA) > 0
endfunction

private function Wait takes nothing returns boolean
    local Info data = ABCT_GetData()
    set AGAIN[data.picked] = false
    call data.destroy()
    return true
endfunction

private function Root takes unit whichUnit, unit whichTarg returns nothing
    local unit dum = CreateUnit(GetOwningPlayer(whichUnit), UID_DUMMY, 0., 0., 0.)
    local Info data = Info.create()
    call UnitApplyTimedLife(dum, 'BTLF', 2.)
    call UnitAddAbility(dum, AID_NATURE_WALL_ENTANGLE)
    call SetUnitAbilityLevel(dum, AID_NATURE_WALL_ENTANGLE, GetUnitAbilityLevel(whichUnit, AID_NATURE_WALL))
    call IssueTargetOrder(dum, SID_ENTANGLE, whichTarg)
    call UnitRemoveAbility(whichTarg, BID_NATURE_WALL_AURA) // prevent aura bugs
    set AGAIN[whichTarg] = true
    set data.picked = whichTarg
    call ABCT_Start(function Wait, data, ENTANGLE_PERIOD)
    set dum = null
endfunction

private function Callback takes nothing returns boolean
    local Data d = ABCT_GetData()
    local group gru = CreateGroup()
    local unit pick
    local integer int
    local real x
    local real y
    call GroupEnumUnitsInRange(gru, 0., 0., 999999., Condition(function Filterz))
    loop    
        set pick = FirstOfGroup(gru)
        exitwhen pick == null
        if AGAIN[pick] == false then
            call Root.execute(d.caster, pick)
        endif
        call GroupRemoveUnit(gru, pick)
    endloop
    call DestroyGroup(gru)
    set int = 1
    loop    
        exitwhen int > N_UNITS(d.caster, d.level)
        set x = GetUnitX(d.wall[int])
        set y = GetUnitY(d.wall[int])
        call DestroyEffect(AddSpecialEffect(SFX_EFFECT, x, y))
        set int = int + 1
    endloop
    set d.ticks = d.ticks - 1
    set gru = null
    set pick = null
    if d.ticks <= 0 then
        call d.destroy()
        return true
    endif
    return false
endfunction
        
private function Actions takes nothing returns nothing
    local unit cast = GetTriggerUnit() 
    local location spell = GetSpellTargetLoc()
    local integer lvl = GetUnitAbilityLevel(cast, AID_NATURE_WALL)
    local Data d = Data.create()
    local integer int = 1
    local real x = GetUnitX(cast)
    local real y = GetUnitY(cast)
    local real tx = GetLocationX(spell)
    local real ty = GetLocationY(spell)
    local real angle = Atan2(ty - y, tx - x)
    local real dd = (N_UNITS(cast, lvl) +1) * RANGE
    set x = Cos(angle + bj_PI / 2) * dd
    set y = Sin(angle + bj_PI / 2) * dd
    set tx = tx + x / 2
    set ty = ty + y / 2
    set x = x / (N_UNITS(cast, lvl) + 1)
    set y = y / (N_UNITS(cast, lvl) + 1)
    set d.caster = cast
    set d.ticks = R2I(DURATION(cast, lvl) / PICK_PERIOD)
    set d.wood[1] = CreateDestructable(DID_NATURE_WALL_WOOD, tx, ty, 270., TREE_SCALE, GetRandomInt(0, 2))
    loop
        exitwhen int > N_UNITS(cast, lvl)
        set tx = tx - x
        set ty = ty - y
        set d.wall[int] = CreateUnit(GetOwningPlayer(d.caster), UID_NATURE_WALL_UNIT, tx, ty, 270.)
        call UnitApplyTimedLife(d.wall[int], 'BTLF', DURATION(cast, lvl))
        set int = int + 1
    endloop
    set tx = tx - x
    set ty = ty - y
    set d.wood[2] = CreateDestructable(DID_NATURE_WALL_WOOD, tx, ty, 270., TREE_SCALE, GetRandomInt(0, 2))
    set d.level = lvl
    call ABCT_Start(function Callback, d, PICK_PERIOD)
    call RemoveLocation(spell)
    set cast = null
    set spell = null
endfunction

//===========================================================================
function InitTrig_NatureWall takes nothing returns nothing
    local trigger trig = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(trig, Condition(function Conditions))
    call TriggerAddAction(trig, function Actions)
endfunction

endscope

Screenshots:
naturewalldb2.jpg


Also credits to Tinki3 for the map template.

Changelog:
JASS:
// - - - - - - - - - - - - - - - - - - - - - v1.0 - - - - - - - - - - - - - - - - - - - - - - -
- Release
// - - - - - - - - - - - - - - - - - - - - - v2.0 - - - - - - - - - - - - - - - - - - - - - - -
- Fixed a little location leak
- Fixed a bug that made the unit created on the target point of ability being cast
   to be always counted as array 7 ( d.wall[7] ), thus bugging the loop in Callback() action.
- Added a better implementation instruction.
// - - - - - - - - - - - - - - - - - - - - - v3.0 - - - - - - - - - - - - - - - - - - - - - - -
- Removed a few unnecessary lines
- Variables are now properly nulled
// - - - - - - - - - - - - - - - - - - - - - v4.0 - - - - - - - - - - - - - - - - - - - - - - -
- Removed a location or two and moved some stuff to reals
- Period between entangles no longer uses TriggerSleepAction() so you can be
  sure that it will wait an exact amount of time. 
- Ticks are now properly calculated (had a bug with more frequent group checks)
// - - - - - - - - - - - - - - - - - - - - - v4.1 - - - - - - - - - - - - - - - - - - - - - - -
- Edited a little the math on creating the wall.
- Now uses latest PUI - v5.1.
- Edited a little the Configuration Menu. Now it's more understandable (I think).
 

Attachments

  • [Spell]Nature Wall v4[1].1.w3x
    56.3 KB · Views: 559

Joker(Div)

Always Here..
Reaction score
86
I'll take a look, gonna edit with comments.

Edit: It seems like a pretty stable spell. Kinda heavy on animations don't ya think? I think the treant birth is fine itself, but thats my opinion. I don't have the time to go through your trigger, but after briefing scanning it, it seems fine.

Awesome job!
 

Tinki3

Special Member
Reaction score
418
I like this spell, good job.

Though, you should increase the level of the spell tester hero.
I had to spam "Esc" to heal myself continuously.

There was no "Read Me" included in the test map.
You'll need one for approval (a decent one :p).

The "loc" variable in the function "Actions" is not removed in the 2nd loop.

Apart from those few things, all else seems to be fine at this stage;
you seem to have used ABCT correctly, and PUI as well.

Nice overall.
 

cr4xzZz

Also known as azwraith_ftL.
Reaction score
51
> There was no "Read Me" included in the test map.
Well, there's one at the end of the trigger. But if it's not extended enough then I'll add a new one ^^

> The "loc" variable in the function "Actions" is not removed in the 2nd loop.

Will fix.

> Kinda heavy on animations don't ya think?
No. :)

> you should increase the level of the spell tester hero.

Will fix that one too.

> Nice overall.
> Awesome job!

Thanks :)

EDIT:
New version. Fixed the location leak and also saw a minor bug with the array stored wall units
( the unit created on the target spell of ability being cast was always counted as array 7 d.wall[7] and that
could bug the loop in Callback() function).
 

Cohadar

master of fugue
Reaction score
209
LoL the code looks like I wrote it :eek:

Very good. Very good indeed.

This spell would be great in some altered melee.
 

cr4xzZz

Also known as azwraith_ftL.
Reaction score
51
> LoL the code looks like I wrote it :eek:

Omg, thanks. :D


Just a few questions, quys:

Is this needed?
JASS:

   if whichTarg == null then
        return
    endif


And should the nulling part be replaced?
JASS:

    if d.ticks <= 0 then
        call d.destroy()
        return true
    endif
    set gru = null
    set pick = null
    return false
endfunction

//===========
Becomes:

    set gru = null
    set pick = null
    if d.ticks <= 0 then
        call d.destroy()
        return true
    endif
    return false

So this can null all the variables... Or does it already null them?
 

Cohadar

master of fugue
Reaction score
209
JASS:
    
if whichTarg == null then
    return
endif

This is not needed since you call it on units from group.


This is correct.
JASS:

    set gru = null
    set pick = null
    if d.ticks <= 0 then
        call d.destroy()
        return true
    endif
    return false


You should null variables before any and all return statements or it will leak.
 

cr4xzZz

Also known as azwraith_ftL.
Reaction score
51
> You should null variables before any and all return statements or it will leak.
Thanks. I made that. Removed that if statement too.
This should be the last update.
 

Joker(Div)

Always Here..
Reaction score
86
JASS:

This is correct.
<div class="bbCodeBlock bbCodeBlock--screenLimited bbCodeBlock--code"><div class="bbCodeBlock-title">JASS:</div><div class="bbCodeBlock-content"><pre class="bbCodeCode"><code class="jass">
    <span class="keyword">set</span> <span>gru</span> <span class="symbol">=</span> <span class="value">null</span>
    <span class="keyword">set</span> <span>pick</span> <span class="symbol">=</span> <span class="value">null</span>
    <span class="keyword">if</span> <span>d</span>.<span>ticks</span> &<span>lt</span>;<span class="symbol">=</span> <span class="number">0</span> <span class="keyword">then</span>
        <span class="keyword">call</span> <span>d</span>.<span>destroy</span><span class="symbol">(</span><span class="symbol">)</span>
        <span class="keyword">return</span> <span class="value">true</span>
    <span class="keyword">endif</span>
    <span class="keyword">return</span> <span class="value">false</span></code></pre></div></div>

You should null variables before any and all return statements or it will leak.
JASS:

Woah, you have to destroy the struct in ABCT? I thought it did it itself when returned true. <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" class="smilie smilie--sprite smilie--sprite3" alt=":(" title="Frown    :(" loading="lazy" data-shortname=":(" />
 

cr4xzZz

Also known as azwraith_ftL.
Reaction score
51
> Woah, you have to destroy the struct in ABCT? I thought it did it itself when returned true.
Structs must be destroyed every time or you can quickly reach the 8191 limit.
When you return true the timer just stops ticking. It does nothing to the attached struct.
So you have to destroy it manually or it will leak :)

> Approved.
Thanks ^^
 

cr4xzZz

Also known as azwraith_ftL.
Reaction score
51
Just saw a small issue in the code while I was checking all my triggers in my map.

JASS:
    set d.ticks = R2I(DURATION)

This is supposed to be
JASS:
    set d.ticks = R2I(DURATION / PERIOD)


I don't have time now to fix it but it'll be done tomorrow.
 

cr4xzZz

Also known as azwraith_ftL.
Reaction score
51
Well, probably this wasn't tomorrow ... xD

Anyway, another update. Fixed the ticks that would screw the whole group pick. Wait between entangles no longer uses TriggerSleepAction() and now it works properly for period < 0.3 seconds. Also removed a few locations and moved to reals. Well, that's it. I hope this is the last update... :)
 

cr4xzZz

Also known as azwraith_ftL.
Reaction score
51
Short update.

JASS:

// - - - - - - - - - - - - - - - - - - - - - v4.1 - - - - - - - - - - - - - - - - - - - - - - -
- Edited a little the math on creating the wall.
- Now uses latest PUI - v5.1.
- Edited a little the Configuration Menu. Now it&#039;s more understandable (I think).


Have fun mapping guys.
 

hoihoi8

New Member
Reaction score
0
Great spell, but the comments for the unit/spell abilities are horrid. Why don't you just put the exact name of the unit/spell there instead of a vague description? Made importing it a guessing game.

Edit: finally got it working. Works perfectly. Look for it in hoihoi8's Amazing Race :)
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Staff online

      • Ghan
        Administrator - Servers are fun

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top