Spell Fire Pillar

Larcenist

REP: Respect, Envy, Prosperity?
Reaction score
211
Fire Pillar:

Spell info:
GUI/JASS?: JASS
MUI?: Yes
Leaks: None
How to implement: Instructions inside the map.

Note: Requires NewGen World Editor and ABC struct attachment system.

Code:
[U][B]Description:[/B][/U]
Summons a fiery pillar at a targetted location. 
If an enemy unit walks into the pillar it will be struck by 10 fireballs, 
dealing damage and stunning for 0.1 seconds each. 
Lasts 12 seconds or until an enemy unit walks into the pillar. 
Level 1 - 30 damage per fireball. 
Level 2 - 40 damage per fireball. 
Level 3 - 50 damage per fireball.
Level 4 - 60 damage per fireball.
Cooldown 19/16/13/10 seconds.
Manacost 140/160/180/200.

Spell code:

JASS:
scope FirePillar

globals
    private constant integer SpellAID = 'A000'          //The hero spell ID
    private constant integer DummyAID = 'A001'         //The dummyspell ID
    private constant integer EffectDummyID = 'u001'   //The visible dummy's ID
    private constant integer DummyID = 'u000'        //The regular dummy's ID
    private constant real Duration = 12.0           //The duration of the spell
    private constant integer FireballCount = 10    //Number of fireballs spawned to strike the enemy unit that comes in range
    private constant real DetonationAoE = 150.0   //The detonation AoE for the Fire Pillar
    private constant string Effect = "Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl"    //The explosion effect when the Fire Pillar activates.
    private constant boolean AoEOn = false        //"true" = AoE, "false" = single target.
//Do not change anything below here unless you know what you're doing.
    private unit FPCaster = null
    private integer FPLevel = 0
endglobals

private struct SpellData
    unit caster
    unit dummy
    real x
    real y
    trigger inrange
    timer fptimer
    boolean check
    integer level
    triggeraction inrangeaction
    method onDestroy takes nothing returns nothing
        call ClearTriggerStructA(.inrange)
        call TriggerRemoveAction(.inrange, .inrangeaction)
        call DestroyTrigger(.inrange)
        call ClearTimerStructA(.fptimer)
        call DestroyTimer(.fptimer)
    endmethod
endstruct

private function TimerActions takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local SpellData data = GetTimerStructA(t)
    
    if GetWidgetLife(data.dummy) > .405 then
        call RemoveUnit(data.dummy)
        call DestroyEffect(AddSpecialEffect(Effect, data.x, data.y))
    endif
    call data.destroy()
    
    set t = null
endfunction

private function GroupFiltering takes nothing returns boolean
    return true
endfunction

private function InRangeActions takes nothing returns nothing
    local SpellData data = GetTriggerStructA(GetTriggeringTrigger())
    local unit Victim = GetTriggerUnit()
    local location Point
    local real x
    local real y
    local integer Loop = 0
    local unit Dummy
    local group UnitGroup = CreateGroup()
    local unit First
    
    if data.check == false then
        if IsPlayerEnemy(GetOwningPlayer(data.caster), GetOwningPlayer(Victim)) == true then
            set data.check = true
            call DestroyEffect(AddSpecialEffect(Effect, data.x, data.y))
            call RemoveUnit(data.dummy)
            loop
                exitwhen Loop >= FireballCount
                    set Loop = Loop + 1
                    if AoEOn == true then
                        call GroupEnumUnitsInRange(UnitGroup, data.x, data.y, DetonationAoE, Condition(function GroupFiltering))
                        loop
                            set First = FirstOfGroup(UnitGroup)
                            exitwhen First == null
                                if IsPlayerEnemy(GetOwningPlayer(data.caster), GetOwningPlayer(First)) == true and IsUnitType(First, UNIT_TYPE_FLYING) == false then
                                    set Point = GetUnitLoc(First)
                                    set x = GetLocationX(Point)
                                    set y = GetLocationY(Point)
                                    set Dummy = CreateUnit(GetOwningPlayer(data.caster), DummyID, x, y, 0)
                                
                                    call UnitAddAbility(Dummy, DummyAID)
                                    call SetUnitAbilityLevel(Dummy, DummyAID, data.level)
                                    call IssueTargetOrder(Dummy, "thunderbolt", First)
                                    call UnitApplyTimedLife(Dummy, 'BTLF', 1.0)
                                    call RemoveLocation(Point)
                                endif
                            call GroupRemoveUnit(UnitGroup, First)
                        endloop
                        call TriggerSleepAction(.1)
                    else
                        set Dummy = CreateUnit(GetOwningPlayer(data.caster), DummyID, data.x, data.y, 0)
                        call UnitAddAbility(Dummy, DummyAID)
                        call SetUnitAbilityLevel(Dummy, DummyAID, data.level)
                        call IssueTargetOrder(Dummy, "thunderbolt", Victim)
                        call UnitApplyTimedLife(Dummy, 'BTLF', 1.0)
                        call TriggerSleepAction(.1)
                    endif
            endloop
        endif
    endif
    
    call DestroyGroup(UnitGroup)
    
    set Victim = null
    set Dummy = null
    set UnitGroup = null
    set Point = null
endfunction

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

private function Actions takes nothing returns nothing
    local SpellData data = SpellData.create()
    local location Point = GetSpellTargetLoc()
    local unit Caster = GetTriggerUnit()
    local real x = GetLocationX(Point)
    local real y = GetLocationY(Point)
    local integer Level = GetUnitAbilityLevel(Caster, SpellAID)
    
    set data.dummy = CreateUnit(GetOwningPlayer(Caster), EffectDummyID, x, y, 0)
    set data.fptimer = CreateTimer()
    set data.caster = Caster
    set data.inrange = CreateTrigger()
    set data.check = false
    set data.x = x
    set data.y = y
    set data.level = Level
    
    call SetTimerStructA(data.fptimer, data)
    call TimerStart(data.fptimer, Duration, false, function TimerActions)
    call SetTriggerStructA(data.inrange, data)
    call TriggerRegisterUnitInRangeSimple(data.inrange, DetonationAoE, data.dummy)
    set data.inrangeaction = TriggerAddAction(data.inrange, function InRangeActions)
    call RemoveLocation(Point)
    
    set Point = null
    set Caster = null
endfunction

//===========================================================================
public function InitTrig 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

Usage of the spell?:
It's exellent to just pop a Fire Pillar at your enemies escape route when he/she is running for his/her life. Also good for initializing an attack against someone who stands all alone with no creeps around. Also works great for harrassing with. Rather imba and could use either increased cooldown or higher manacost.

Special Thanks:
Ragnarok Online for giving me the inspiration for this spell.
Cohadar for the ABC struct attachment system.
Tinki3 for the testmap, saving me the trouble of showing people my insanely poor terrainingskills.
Flare for pointing out further customizablities.
You for reading the special thanks section for some unknown reason.

Version tracker and updates:
Version 1.1d: Fixed the TriggerAddAction leak and the spell now filters out flying units.
Version 1.1c: Now the unit is removed, not killed so it melts in better with the explosion.
Version 1.1b: Minor leakfix.
Version 1.1: Made struct private and added an easy way of making the fire pillars do AoE damage/stun.
Version 1.0b: Made the spell even easier to customize.
Version 1.0: Initial release.

Screenshot:

It's like extremely hard to get a good screenshot of this one, check it out ingame instead.

[URL=http://img230.imageshack.us/my.php?image=firepillaryn0.jpg][/URL]
 

Attachments

  • Fire Pillar v1.1d by Larcenist.w3x
    62 KB · Views: 587

Vestras

Retired
Reaction score
248
You should REALLY add a death animation to the "pillar". I mean, suddenly, it's just gone.
 

Flare

Stops copies me!
Reaction score
662
Code seems fine, I can't find any leaks, but one thing I noticed

JASS:
                exitwhen Loop >= 10


You should set that 10 to a constant, so that people can easily configure how many times a unit is hit by the fireball.

Along with the 'In Range' distance (possibly). Everything that makes the spell easy to manipulate makes it better (IMO at least).


I'll test the spell itself later though (don't have much time to test atm)
 

Larcenist

REP: Respect, Envy, Prosperity?
Reaction score
211
Made it even easier to customize, thanks for pointing that out Flare.

Also did I use the onDestroy method correctly? I really had no idea how to do it so I just read a few spells in the spell section then guessed from there.

You should REALLY add a death animation to the "pillar". I mean, suddenly, it's just gone.

It's a doodad <base> crap, it hasn't gotten any death animation.
 

Larcenist

REP: Respect, Envy, Prosperity?
Reaction score
211
Oh bummer, I always keep my structs private since I always use the struct Spelldata. Guess I forgot it this time, fixing right away.
 

Vestras

Retired
Reaction score
248
> It's a doodad <base> crap, it hasn't gotten any death animation.

Take another model? Or get Hatebreeder or someone else to animate it.
 

Larcenist

REP: Respect, Envy, Prosperity?
Reaction score
211
I provide the spell code, if you don't like the model then take those 10 seconds changing the model in the object editor.

Version 1.1 added, one question though. Will turning the AoE on result in the spell not being MUI anymore? I was just wondering since there's a wait in there, though the globals are redeclared inside the loop too so I do not know if it's MUI or not.
 

Flare

Stops copies me!
Reaction score
662
You mean here?

JASS:
            loop
                exitwhen Loop &gt;= FireballCount
                    set Loop = Loop + 1
                    if AoEOn == true then
                        set FPCaster = data.caster
                        set FPLevel = data.level
                        call GroupEnumUnitsInRange(UnitGroup, data.x, data.y, DetonationAoE, Condition(function GroupFiltering))
                        call ForGroup(UnitGroup, function GroupActions)
                        call TriggerSleepAction(.1)
                    else
                        set Dummy = CreateUnit(GetOwningPlayer(data.caster), DummyID, data.x, data.y, 0)
                        call UnitAddAbility(Dummy, DummyAID)
                        call SetUnitAbilityLevel(Dummy, DummyAID, data.level)
                        call IssueTargetOrder(Dummy, &quot;thunderbolt&quot;, Victim)
                        call UnitApplyTimedLife(Dummy, &#039;BTLF&#039;, 1.0)
                        call TriggerSleepAction(.1)
                    endif
            endloop


If you are using locals (or redeclaring globals at the start of the loop), it's still MUI. Just try repeated casts and see if it works as intended.

If you are worried about it not being MUI, you could use a FirstOfGroup loop within the function that has all your locals/struct data
JASS:
loop
exitwhen FirstOfGroup (g) == null
set u = FirstOfGroup (g)
//Actions using u
call GroupRemoveUnit (u)
endloop

//When all units have been removed from the group, u will have to be null
 

Larcenist

REP: Respect, Envy, Prosperity?
Reaction score
211
Yeh it works as intended, though I should destroy that group inside the loop, not outside.

I'll just stick to this until someone jumps in saying that it's not MUI, I somehow feel more comfortable using callback functions rather than using FirstOfGroup loops.
 

GoGo-Boy

You can change this now in User CP
Reaction score
40
Hmm I like the idea and I really like the model you took for this:thup:

However as ELSKER suggested I'd add one (best one that fits :D) minor explosion effect to this Pillar when it disappears. Another thing I'd prefer is making the pillar taking a random target or multiple. Because it looks kinda weird when many units are close to it and only one gets damaged.
 

Larcenist

REP: Respect, Envy, Prosperity?
Reaction score
211
Change the constant variable AoEOn to true and it will deal damage to all nearby units.

Also it's quite difficult timing an explosion to fit when the unit dies, since it dissapears around 1-2 seconds after it's killed.
 

GoGo-Boy

You can change this now in User CP
Reaction score
40
Oh should have read what you wrote about the AOE^^

Remove the doodad then instead of destroying. That way you can time it perfeclty.
 

Tinki3

Special Member
Reaction score
418
Neat Spell.

In the "Actions" function, you are leaking a triggeraction with:
JASS:
call TriggerAddAction(data.inrange, function InRangeActions)


I would suggest adding a triggeraction struct variable and using that to define/set the action for the trigger:
JASS:
set data.trigaction = TriggerAddAction(data.inrange, function InRangeActions)


And then you'd obviously need to remove the triggeraction from the trigger inside your onDestroy method:
JASS:
call TriggerRemoveAction(.inrange, .trigaction)

(Remember to do this before destroying + clearing the trigger variable).


I also noticed that you were just filtering units that were enemies of the caster.
This means air units can trigger the effects, so filter them out.
 

SanKakU

Member
Reaction score
21
sounds interesting, but what does it look like? i might try updating this one if the original poster doesn't get to it first.
 
General chit-chat
Help Users
  • No one is chatting at the moment.
  • The Helper The Helper:
    The bots will show up as users online in the forum software but they do not show up in my stats tracking. I am sure there are bots in the stats but the way alot of the bots treat the site do not show up on the stats
  • Varine Varine:
    I want to build a filtration system for my 3d printer, and that shit is so much more complicated than I thought it would be
  • Varine Varine:
    Apparently ABS emits styrene particulates which can be like .2 micrometers, which idk if the VOC detectors I have can even catch that
  • Varine Varine:
    Anyway I need to get some of those sensors and two air pressure sensors installed before an after the filters, which I need to figure out how to calculate the necessary pressure for and I have yet to find anything that tells me how to actually do that, just the cfm ratings
  • Varine Varine:
    And then I have to set up an arduino board to read those sensors, which I also don't know very much about but I have a whole bunch of crash course things for that
  • Varine Varine:
    These sensors are also a lot more than I thought they would be. Like 5 to 10 each, idk why but I assumed they would be like 2 dollars
  • Varine Varine:
    Another issue I'm learning is that a lot of the air quality sensors don't work at very high ambient temperatures. I'm planning on heating this enclosure to like 60C or so, and that's the upper limit of their functionality
  • Varine Varine:
    Although I don't know if I need to actually actively heat it or just let the plate and hotend bring the ambient temp to whatever it will, but even then I need to figure out an exfiltration for hot air. I think I kind of know what to do but it's still fucking confusing
  • The Helper The Helper:
    Maybe you could find some of that information from AC tech - like how they detect freon and such
  • Varine Varine:
    That's mostly what I've been looking at
  • Varine Varine:
    I don't think I'm dealing with quite the same pressures though, at the very least its a significantly smaller system. For the time being I'm just going to put together a quick scrubby box though and hope it works good enough to not make my house toxic
  • Varine Varine:
    I mean I don't use this enough to pose any significant danger I don't think, but I would still rather not be throwing styrene all over the air
  • The Helper The Helper:
    New dessert added to recipes Southern Pecan Praline Cake https://www.thehelper.net/threads/recipe-southern-pecan-praline-cake.193555/
  • The Helper The Helper:
    Another bot invasion 493 members online most of them bots that do not show up on stats
  • Varine Varine:
    I'm looking at a solid 378 guests, but 3 members. Of which two are me and VSNES. The third is unlisted, which makes me think its a ghost.
    +1
  • The Helper The Helper:
    Some members choose invisibility mode
    +1
  • The Helper The Helper:
    I bitch about Xenforo sometimes but it really is full featured you just have to really know what you are doing to get the most out of it.
  • The Helper The Helper:
    It is just not easy to fix styles and customize but it definitely can be done
  • The Helper The Helper:
    I do know this - xenforo dropped the ball by not keeping the vbulletin reputation comments as a feature. The loss of the Reputation comments data when we switched to Xenforo really was the death knell for the site when it came to all the users that left. I know I missed it so much and I got way less interested in the site when that feature was gone and I run the site.
  • Blackveiled Blackveiled:
    People love rep, lol
    +1
  • The Helper The Helper:
    The recipe today is Sloppy Joe Casserole - one of my faves LOL https://www.thehelper.net/threads/sloppy-joe-casserole-with-manwich.193585/
  • The Helper The Helper:
    Decided to put up a healthier type recipe to mix it up - Honey Garlic Shrimp Stir-Fry https://www.thehelper.net/threads/recipe-honey-garlic-shrimp-stir-fry.193595/
  • The Helper The Helper:
    Here is another comfort food favorite - Million Dollar Casserole - https://www.thehelper.net/threads/recipe-million-dollar-casserole.193614/

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top