Spell Lightning Ward (GUI/JASS/VJASS)

Septimus

New Member
Reaction score
58
spells_2256_screenshot.jpg


Status

Coding Type : GUI/JASS/VJASS
Spell Type : MUI

Ability Description

Unleash a ward around the targeted unit that would attack it, the ward would also release a energy bolt that destroy the hp of nearby enemy unit. Targeted unit get stun for 5 seconds by this ability.

Level 1 - Lasts 10 seconds.
Level 2 - Lasts 15 seconds.
Level 3 - Lasts 20 seconds.

Version 1.07 Update

Create a VJASS version of it (Full credit for VJASS version goes to Dark Dragon).

Version 1.06

Add additional code in order to remove 16 memory leaks of type boolexpr cause by TriggerRegisterAnyUnitEventBJ

Version 1.05

Create a JASS version of it.

Version 1.04

Further optimize the maths to enable beginner to modify this spell easier.

Version 1.03

Fix minor flaw.

Version 1.02

Improve coding.

Version 1.01

Disable documentation sample.​

Trigger:
  • Lightning Ward GUI
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Lightning Ward (GUI)
    • Actions
      • Set LW_Target_Unit = (Target unit of ability being cast)
      • Set LW_Target_Point = (Target point of ability being cast)
      • Set LW_Target_Position = (Position of LW_Target_Unit)
      • Set LW_Level = (Level of Lightning Ward (GUI) for (Triggering unit))
      • Set LW_Duration = (5.00 + (5.00 x (Real(LW_Level))))
      • Set LW_Loop_Number = 5
      • For each (Integer LW_Integer) from 1 to LW_Loop_Number, do (Actions)
        • Loop - Actions
          • Set LW_Spawn_Point = (LW_Target_Position offset by 500.00 towards (360.00 x ((Real(LW_Integer)) / (Real(LW_Loop_Number)))) degrees)
          • Unit - Create 1 Lightning Ward for (Owner of (Triggering unit)) at LW_Spawn_Point facing LW_Target_Point
          • Unit - Add a LW_Duration second Generic expiration timer to (Last created unit)
          • Unit - Add Lightning Bolt to (Last created unit)
          • Unit - Order (Last created unit) to Undead Crypt Lord - Locust Swarm
          • Unit - Order (Last created unit) to Attack LW_Target_Unit
          • Custom script: call RemoveLocation(udg_LW_Spawn_Point)
      • Custom script: call RemoveLocation(udg_LW_Target_Point)
      • Custom script: call RemoveLocation(udg_LW_Target_Position)


JASS:
function Trig_Lightning_Ward_JASS_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A003'
endfunction

function Trig_Lightning_Ward_JASS_Actions takes nothing returns nothing
    local unit LTR = GetTriggerUnit()
    local unit LV = GetSpellTargetUnit()
    local location LP = GetSpellTargetLoc()
    local location LT = GetUnitLoc(LV)
    local location LSP
    local integer LL = GetUnitAbilityLevel(LTR, 'A003')
    local real LD = 5.00 + 5.00 * LL
    local integer LI = 1
    local unit LU
    local real FA = AngleBetweenPoints(LT, LP)
    local integer DU = 5
    local real Deg = 360/DU
    loop
        exitwhen LI > DU
        set LSP = PolarProjectionBJ(LT, 500.00, LI * Deg)
        set LU = CreateUnitAtLoc(GetOwningPlayer(LTR), 'o000', LSP, FA)
        call UnitApplyTimedLife(LU, 'BTLF', LD)
        call UnitAddAbility(LU, 'A002')
        call IssueImmediateOrder(LU, "locustswarm" )
        call IssueTargetOrder(LU, "attack", LV )
        call RemoveLocation(LSP)
        set LU = null
        set LI = (LI+1)
    endloop
    call RemoveLocation(LP)
    call RemoveLocation(LT)
    set LP = null
    set LT = null
    set LTR = null
    set LV = null
    set LSP = null
endfunction

constant function DummyFilter takes nothing returns boolean
    return true
endfunction

function Lightning_Ward_JASS takes nothing returns nothing
    local trigger T = CreateTrigger()
    local integer TI = 0
    local filterfunc FF = Filter(function DummyFilter)
    loop
    exitwhen (TI >= bj_MAX_PLAYER_SLOTS)
    call TriggerRegisterPlayerUnitEvent(T, Player(TI), EVENT_PLAYER_UNIT_SPELL_EFFECT, FF)
    set TI = TI + 1
    endloop
    call DestroyFilter(FF)
    set FF = null
    set T = null
endfunction

//===========================================================================
function InitTrig_Lightning_Ward_JASS takes nothing returns nothing
    set gg_trg_Lightning_Ward_JASS = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Lightning_Ward_JASS, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_Lightning_Ward_JASS, Condition( function Trig_Lightning_Ward_JASS_Conditions ) )
    call TriggerAddAction( gg_trg_Lightning_Ward_JASS, function Trig_Lightning_Ward_JASS_Actions )
endfunction


JASS:
library_once LightningWard initializer Init

globals
    private constant integer LIGHTNING_WARD = 'A004'
    private constant integer DUMMY_RAWCODE  = 'o000'
    private constant integer SWARM_RAWCODE  = 'A002'
    private constant real    OFFSET_DISTANCE = 500.
    private constant integer MAX_WARDS = 5
endglobals

private function LightningWard takes nothing returns boolean
    local unit LTU
    local unit LV
    local player P
    local real X
    local real Y
    local real LD
    local integer LI
    local unit LU
    local real RAD
    if (GetSpellAbilityId() == LIGHTNING_WARD) then
    set LTU = GetTriggerUnit()
    set LV = GetSpellTargetUnit()
    set X = GetUnitX(LV)
    set Y = GetUnitY(LV)
    set LD = (GetUnitAbilityLevel(LTU, LIGHTNING_WARD)*5)+5.
    set RAD = (2.*bj_PI)/MAX_WARDS
    set P = GetOwningPlayer(LTU)
    set LI = 0
    loop
    exitwhen (LI >= MAX_WARDS)
        set LU = CreateUnit(P, DUMMY_RAWCODE, X+OFFSET_DISTANCE*Cos(RAD*LI), Y+OFFSET_DISTANCE*Sin(RAD*LI), 0.)
        call UnitApplyTimedLife(LU, 'BTLF', LD)
        call UnitAddAbility(LU, SWARM_RAWCODE)
        call IssueImmediateOrder(LU, "locustswarm" )
        call IssueTargetOrder(LU, "attack", LV)
        set LI = LI + 1
    endloop
    set LU = null
    set P = null
    set LTU = null
    set LV = null
    endif
    return (FALSE)
endfunction

// ===========================================================================
private constant function DummyFilter takes nothing returns boolean
    return true
endfunction

private function Init takes nothing returns nothing
    local trigger T = CreateTrigger()
    local integer I = 0
    local filterfunc FF = Filter(function DummyFilter)
    loop
    exitwhen (I >= bj_MAX_PLAYER_SLOTS)
        call TriggerRegisterPlayerUnitEvent(T, Player(I), EVENT_PLAYER_UNIT_SPELL_EFFECT, FF)
        set I = I + 1
    endloop
    call TriggerAddCondition(T, Condition(function LightningWard))
    call DestroyFilter(FF)
    set FF = null
    set T = null
endfunction

endlibrary
 

Attachments

  • Lightning Ward v1.07.w3x
    22.5 KB · Views: 278

WolfieeifloW

WEHZ Helper
Reaction score
372
The vJASS version should be a scope, not a library.
And a lot of those locals look like they could be set at initialization, could they not?
The whole vJASS trigger looks weird actually :p .

Spell looks good though;
Nice job!


EDIT: Locations in the vJASS too;
Why not X/Y, it's JASS, c'mon :p .
(And if normal JASS can do X/Y, why not in that one too)

EDITEDIT: Explain the globals with a commented line.
 

simonake

New Member
Reaction score
72
Trigger:
  • Set LW_Loop_Number = 5


If the number always stay 5, you should put, in the loop, the number "5", it will save you place, time and energy. And in this case, it's useless. (Maybe I'm wrong) Am I?
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
Your coding style so weird, boolexpr no need to care about. U only do double work to get 1 only result.Y u pt whole spell trigger in Condition???? It is bad, becauz it generate lots of variables and slow down whole spells trigger in ur game, i think.... You should follow the usual way. AddAction to trigger.
 

Kenny

Back for now.
Reaction score
202
Use this for your vJass one, it should work:

Note: It Requires GTrigger by Jesus4Lyf, found in the systems section here on thehelper.

JASS:
scope LightningWard initializer Init

    globals
        private constant integer LIGHTNING_WARD  = 'A004'
        private constant integer DUMMY_RAWCODE   = 'o000'
        private constant integer SWARM_RAWCODE   = 'A002'
        private constant integer MAX_WARDS       = 5
        private constant real    OFFSET_DISTANCE = 500.00
    endglobals

    private function Actions takes nothing returns boolean
        local unit    cast  = GetTriggerUnit()
        local unit    targ  = GetSpellTargetUnit()
        local player  owner = GetOwningPlayer(cast)
        local real    targx = GetUnitX(targ)
        local real    targy = GetUnitY(targ)
        local real    life  = (GetUnitAbilityLevel(cast,LIGHTNING_WARD) * 5.00) + 5.00
        local real    rad   = (2.00 * bj_PI) / MAX_WARDS
        local unit    dummy = null
        local integer i     = 0

        loop
            exitwhen i >= MAX_WARDS
            set dummy = CreateUnit(owner,DUMMY_RAWCODE,targx + OFFSET_DISTANCE * Cos(rad * i),targy + OFFSET_DISTANCE * Sin(rad * i),0.00)
            call UnitApplyTimedLife(dummy,'BTLF',life)
            call UnitAddAbility(dummy,SWARM_RAWCODE)
            call IssueImmediateOrder(dummy,"locustswarm")
            call IssueTargetOrder(dummy,"attack",targ)
            set i = i + 1
        endloop
        
        set cast  = null
        set targ  = null
        set dummy = null
        // set owner = null players don't need to be nulled.
        
        return false
    endfunction

    private function Init takes nothing returns nothing
        call GT_AddStartsEffectAction(function Actions,LIGHTNING_WARD)
    endfunction

endscope


@ kingkingyyk3:

Putting your script inside a condition does not matter that much, many people do it as conditions are safer than actions.
 

Septimus

New Member
Reaction score
58
EDIT: Locations in the vJASS too;
Why not X/Y, it's JASS, c'mon .
(And if normal JASS can do X/Y, why not in that one too)

GUI and JASS version are made by me, the vjass are made by Dark Dragon. I have request him to make a simple version of vjass to enable newbie in jass to import it without having much problem (Unless they are too lazy to figure out how to use vjass, then they could use jass).

If the number always stay 5, you should put, in the loop, the number "5", it will save you place, time and energy. And in this case, it's useless. (Maybe I'm wrong) Am I?

Design for user friendly (For those who are too freaking noob to use JASS and GUI). If you read the documentation, you would know how detail the information had been provided.

Your coding style so weird, boolexpr no need to care about. U only do double work to get 1 only result.Y u pt whole spell trigger in Condition???? It is bad, becauz it generate lots of variables and slow down whole spells trigger in ur game, i think.... You should follow the usual way. AddAction to trigger.

According to dark dragon, it would leak if you do not fix it. Also condition work faster than action.

Use this for your vJass one, it should work:

Note: It Requires GTrigger by Jesus4Lyf, found in the systems section here on thehelper.

The purpose of this spells coding was set this way is to make it easy, efficient and does not require any system (So it would be convenient.)

This spells was highly recommended at hiveworkshop.com for the efficiency and user friendly.

http://www.hiveworkshop.com/forums/resource.php?t=125624&prev=u=Septimus
 

Azlier

Old World Ghost
Reaction score
461

wraithseeker

Tired.
Reaction score
122
The BJ for EVENT_PLAYER_UNIT_SPELL_EFFECT do not leak a boolexpr.

I don't understand why people from THW always say it's highly recommended there though, it's weird when it still have rooms for improvement but yeah it's neat still.

X and Y for locations are good.

EDIT: *rants* azlier.
 

RMX

New Member
Reaction score
8
Great Spell love the effects........
And the coding is hmmmmmmmm Priceless ..... VERY GREAT ....... still learning vJASS thought ....... THW RULES !!! .

Keep the Ideas flow coming :p
 

Kenny

Back for now.
Reaction score
202
Using action would just increase the handle.

First off, no. Secondly, if your worried about the handle count, then import GTrigger into your maps and use the script I posted.

Or use this:

JASS:
scope LightningWard initializer Init

    globals
        private constant integer LIGHTNING_WARD  = 'A004'
        private constant integer DUMMY_RAWCODE   = 'o000'
        private constant integer SWARM_RAWCODE   = 'A002'
        private constant integer MAX_WARDS       = 5
        private constant real    OFFSET_DISTANCE = 500.00
        private boolexpr         True_filt       = null // Do not touch!
    endglobals

    private function Actions takes nothing returns nothing
        local unit    cast  = GetTriggerUnit()
        local unit    targ  = GetSpellTargetUnit()
        local player  owner = GetOwningPlayer(cast)
        local real    targx = GetUnitX(targ)
        local real    targy = GetUnitY(targ)
        local real    life  = (GetUnitAbilityLevel(cast,LIGHTNING_WARD) * 5.00) + 5.00
        local real    rad   = (2.00 * bj_PI) / MAX_WARDS
        local unit    dummy = null
        local integer i     = 0

        loop
            exitwhen i >= MAX_WARDS
            set dummy = CreateUnit(owner,DUMMY_RAWCODE,targx + OFFSET_DISTANCE * Cos(rad * i),targy + OFFSET_DISTANCE * Sin(rad * i),0.00)
            call UnitApplyTimedLife(dummy,'BTLF',life)
            call UnitAddAbility(dummy,SWARM_RAWCODE)
            call IssueImmediateOrder(dummy,"locustswarm")
            call IssueTargetOrder(dummy,"attack",targ)
            set i = i + 1
        endloop
        
        set cast  = null
        set targ  = null
        set dummy = null
        // set owner = null players don't need to be nulled.
    endfunction

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

    private function True_filter takes nothing returns boolean
        return true
    endfunction

    private function Init takes nothing returns nothing
        local trigger trig = CreateTrigger()
        local integer i    = 0

        set True_filt = Filter(function True_filter)
  
        loop
            call TriggerRegisterPlayerUnitEvent(trig,Player(i),EVENT_PLAYER_UNIT_SPELL_EFFECT,True_filt)
            set i = i + 1
            exitwhen i == bj_MAX_PLAYER_SLOTS
        endloop

        call TriggerAddCondition(trig,Condition(function Conditions))
        call TriggerAddAction(trig,function Actions)
    endfunction

endscope


Its quite similar to yours, just neater. And this doesn't require GTrigger.
 

Viikuna

No Marlo no game.
Reaction score
265
vJass version looks good.
Player variables dont have to be nulled ( but you can null them if you want, Im not complaining ).
You could use TriggerRegisterAnyUnitEventBJ ( There is nothing wrong with that, it seems that null boolexprs only malfunctions with GroupEnum for some weird reason )

And yes, you should use only condition, because actions are slow and usually pretty useless. ( Like in this case )



JASS:
set LD = (GetUnitAbilityLevel(LTU, LIGHTNING_WARD)*5)+5.


You could use some constant function for this, like: function DURATION takes integer level returns real

Its easier for people to modify spell, when you use constants for stuff like this. ( I see you already have stuff like MAX_WARDS there, which is exactly how it should be )
 

BlackRose

Forum User
Reaction score
239
That is pretty electrical. The weird bolt moving along looks weird, when the target dies -.- Make a channeling version?
 
General chit-chat
Help Users
  • Blackveiled Blackveiled:
    I wouldn't know, I'm in Joliet, Illinois right now working. I left Houston area about 2 weeks ago lol
  • Blackveiled Blackveiled:
    Not permanently of course, just a temporary job.
    +1
  • jonas jonas:
    Glad you're ok @tom_mai78101
  • jonas jonas:
    @Blackveiled you know another word for permanent? temporary
    +1
  • Varine Varine:
    Briefly, he'll only be there for the interim. Like a stopgap of sorts, he'll be back home in short time
  • O Old Mountain Shadow:
    Hurray! Tom has reappeared!
  • The Helper The Helper:
    Happy Thursday!
  • Blackveiled Blackveiled:
    Yep. Just another fun night at work.
  • Varine Varine:
    Broke the nozzle on my 3d printer and I don't have another heater block. So... I guess I'm fucked on that this weekend
  • The Helper The Helper:
    that sucks i bet they are expensive
  • Varine Varine:
    Not really
  • Varine Varine:
    The entire hot end is like 20 dollars, I just can't get anymore until next week
  • Varine Varine:
    I ordered like five blocks for 15 dollars. They're just little aluminum blocks with holes drilled into them
  • Varine Varine:
    They are pretty much disposable. I have shitty nozzles though, and I don't think these were designed for how hot I've run them
  • Varine Varine:
    I tried to extract it but the thing is pretty stuck. Idk what else I can use this for
  • Varine Varine:
    I'll throw it into my scrap stuff box, I'm sure can be used for something
  • Varine Varine:
    I have spare parts for like, everything BUT that block lol. Oh well, I'll print this shit next week I guess. Hopefully it fits
  • Varine Varine:
    I see that, despite your insistence to the contrary, we are becoming a recipe website
  • Varine Varine:
    Which is unique I guess.
  • The Helper The Helper:
    Actually I was just playing with having some kind of mention of the food forum and recipes on the main page to test and see if it would engage some of those people to post something. It is just weird to get so much traffic and no engagement
  • The Helper The Helper:
    So what it really is me trying to implement some kind of better site navigation not change the whole theme of the site

      The Helper Discord

      Staff online

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top