• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Fire Erruption v1.4

Fire Erruption v1.4

A Giant fireball comes out from the targeted point. When the fireball explodes it splits into 12 pcs, dealing damage to every enemy in a line.

|cffffcc00Level 1|r - Each fire deals 50 damage.
|cffffcc00Level 2|r - Each fire deals 100 damage.
|cffffcc00Level 3|r - Each fire deals 150 damage.
|cffffcc00Level 4|r - Each fire deals 200 damage.
|cffffcc00Level 5|r - Each fire deals 250 damage.

Originally Created by: [self=http://www.hiveworkshop.com/forums/members/defskull/]Defskull[/self] in GUI but I've decided to remake it in vJASS.

JASS:
/*
===Fire Erruption v1.4
===By: Mckill2009

INSTALLATION:
- Copy the "Fire Erruption" (see left) folder to your map
- Copy the custom units and abilities to your map
- Make sure you inputed the correct raw ID's of the custom units and abilities
- You can view raw ID's by pressing CTRL+D in the object editor
- Examples of raw ID's are 'A001', 'A003' etc... 
- See the Note below for more info

REQUIRES:
- RegisterPlayerUnitEvent by Magtheridon96
- SpellEffectEvent by Bribe

CREDITS:
- This spell was originally made by defskull in GUI (requested by me)
*/

scope FireErruption

/*
Note:
    - SPELL_ID and CHANNEL_ID must match/synchronize to each other
    - FE_DUMSPELLID and ORDER_ID must match/synchronize to each other.
    - If you create your FE_DUMMY manually from the object editor make
        sure that the "Animation - Cast Backswing/Point" is set to 0.
    - The cooldown and mana of your Breath of Fire must be 0.
*/
    
globals
    private constant integer         SPELL_ID = 'A001' //Main spell raw ID, Blizzard
    private constant integer    FE_DUMSPELLID = 'A003' //Dummy spell raw ID, Breath of Fire
    private constant integer       FE_DUMMYID = 'h000' //Dummy raw ID
    private constant integer      FIREBALL_ID = 'h002' //Fireball Dummy raw ID
    private constant integer       CHANNEL_ID = 852089 //Blizzard orderID (for hero)
    private constant integer         ORDER_ID = 852580 //Breath of Fire orderID (for dummy)
    //=============================================
    private constant boolean          PRELOAD = true
    //Sets how many times the fireball will spit fire
    private constant integer       CAST_COUNT = 12
    //This is the ground shaking SFX
    private constant string            FE_SFX = "Abilities\\Spells\\Orc\\EarthQuake\\EarthQuakeTarget.mdl"
    //This is the angle between spitting fire
    private constant real         FE_BALL_GAP = 30.
    //Sets how fast the fireball grows
    private constant real      SCALE_INTERVAL = 0.05 
    //Minimum 0.03, this is the speed of the rotating fire casted
    private constant real          CAST_SPEED = 0.03
    //Maximum size of the fireball
    private constant real           MAX_SCALE = 10
endglobals

private struct FireErruption extends array
    unit u
    unit fireball
    real x
    real y
    real scale
    real angle
    real castspeed
    integer castcount
    integer level
    effect sfx
    boolean isChanneling
    
    static constant real delay = 0.03125
    static unit dummy = null //used a global dummy for the fire casting
    static timer t
    static integer index = 0
    static integer array indexAR    
    
    //=====allocator and destructor for this struct
    static integer ins = 0
    static integer array insAR
    
    static method allocate takes nothing returns integer
        local thistype this = insAR[0]
        if this==0 then
            set ins = ins + 1
            set this = ins
        else
            set insAR[0] = insAR[this]
        endif  
        return this
    endmethod
    
    method deallocate takes nothing returns nothing
        set insAR[this] = insAR[0]
        set insAR[0] = this
    endmethod
    //=====
    
    static method periodic takes nothing returns nothing
        local thistype this
        local integer i = 0
        local real x1
        local real y1
        loop
            set i = i+1
            set this = indexAR[i]
            if not IsUnitType(.u, UNIT_TYPE_DEAD) and .isChanneling then
                if GetUnitCurrentOrder(.u)==CHANNEL_ID then
                    if MAX_SCALE > .scale then
                        set .scale = .scale + SCALE_INTERVAL
                        call SetUnitScale(.fireball, .scale, 0, 0)
        
                    elseif .fireball != null then
                        call DestroyEffect(.sfx)
                        call RemoveUnit(.fireball)   
                        set .fireball = null
        
                    elseif CAST_COUNT > .castcount then
                        set .castspeed = .castspeed + delay
                        if .castspeed > CAST_SPEED then
                            set .castspeed = 0
                            set .castcount = .castcount + 1       
                            set .angle = .angle + FE_BALL_GAP
                            call SetUnitOwner(dummy, GetOwningPlayer(.u), false)
                            call SetUnitPosition(dummy, .x, .y)
                            set x1 = .x + 100 * Cos(.angle*bj_DEGTORAD)
                            set y1 = .y + 100 * Sin(.angle*bj_DEGTORAD)
                            call SetUnitAbilityLevel(dummy, FE_DUMSPELLID, .level)             
                            call IssuePointOrderById(dummy, ORDER_ID, x1, y1)
                        endif
                    else
                        call IssueImmediateOrder(.u, "stop")
                        set .isChanneling = false
                    endif
                else
                    set .isChanneling = false
                endif
            else
                call DestroyEffect(.sfx)
                call RemoveUnit(.fireball)                
                set .u = null
                set .fireball = null
                set .sfx = null
                call .deallocate() 
                set indexAR[i] = indexAR[index]
                set indexAR[index] = this
                set index = index - 1
                set i = i - 1
                if index==0 then
                    call PauseTimer(t)
                    call DestroyTimer(t)
                    call RemoveUnit(dummy)
                endif              
            endif
            exitwhen i==index
        endloop
    endmethod

    static method cast takes nothing returns nothing
        local thistype this = allocate()
        set .u = GetTriggerUnit()
        set .x = GetSpellTargetX()
        set .y = GetSpellTargetY()
        set .fireball = CreateUnit(Player(15), FIREBALL_ID, .x, .y, 0)
        set .level = GetUnitAbilityLevel(.u, SPELL_ID) 
        set .sfx = AddSpecialEffect(FE_SFX, .x, .y)
        call SetUnitScale(.fireball, 0,0,0)
        set .scale = 0
        set .angle = 0
        set .castcount = 0
        set .castspeed = CAST_SPEED
        set .isChanneling = true
        call SetUnitFlyHeight(.fireball, 100, 0)
        if index==0 then
            set t = CreateTimer()
            call TimerStart(t, delay, true, function thistype.periodic)
            set dummy = CreateUnit(Player(15),FE_DUMMYID,0,0,0)
            call UnitAddAbility(dummy, FE_DUMSPELLID)
            call UnitRemoveAbility(dummy, 'Amov')
        endif        
        set index = index + 1
        set indexAR[index] = this   
    endmethod

    static method onInit takes nothing returns nothing
        //Setting up the spell effect        
        call RegisterSpellEffectEvent(SPELL_ID, function thistype.cast)
        static if PRELOAD then
            //Preloading dummies and abilities
            set dummy = CreateUnit(Player(15),FE_DUMMYID,0,0,0)
            call ShowUnit(dummy,false)
            call RemoveUnit(dummy)
            set dummy = CreateUnit(Player(15),FIREBALL_ID,0,0,0)
            call ShowUnit(dummy,false)
            call UnitAddAbility(dummy, FE_DUMSPELLID)
            call RemoveUnit(dummy)      
        endif
    endmethod
endstruct

endscope


v1.4
- Removing of dummies applied
- Global dummy applied so that no need to create dummies in every loop

v1.3a
- Added optional preload configuration
- Removed 'Arav' ability checking

v1.3
- Library changed to scope
- Added preloads
- T32 replaced by static timer

v1.2
- Remade into vJASS
- Supports Multi-level
- The hero is channeling
- Maker's review 99% done (except for the crow form added :)

v1.3
- The gound really 'raises'
- Trigger 2 has an 'off' status if the group is empty
- Save unit for itself in Hash is removed
- Description changed


Keywords:
fire, erruption, volcano, damage, dot, rotate, vortex, vjass, jass
Contents

Fire Erruption (Map)

Reviews
20:15 October 2, 2012 Magtheridon96: Approved. Tiny crazy perfectionist improvement: - You can reduce two lines of code by just keeping the timer in a static struct variable.

Moderator

M

Moderator

20:15 October 2, 2012
Magtheridon96: Approved.

Tiny crazy perfectionist improvement:
- You can reduce two lines of code by just keeping the timer in a static struct variable.
 
Level 37
Joined
Mar 6, 2006
Messages
9,240

The spell is okay, the triggering is not.


  • FE Dies
    • Events
      • Unit - A unit Dies
    • Conditions
    • Actions
      • Unit Group - Pick every unit in FE_Ugrp and do (Actions)
        • Loop - Actions
          • Hashtable - Save Handle Of(Picked unit) as (Key dummy) of (Key (Picked unit)) in Hash
          • Set FireballU = (Load (Key dummy) of (Key (Picked unit)) in Hash)
          • Set CasterFE = (Load (Key caster) of (Key (Picked unit)) in Hash)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Triggering unit) Equal to FireballU
            • Then - Actions
              • Set GroundShakeSFX = (Load (Key sfx) of (Key (Picked unit)) in Hash)
              • Special Effect - Destroy GroundShakeSFX
              • Unit - Remove (Triggering unit) from the game
              • Set FireballLoc = (Position of (Triggering unit))
              • Special Effect - Create a special effect at FireballLoc using Objects\Spawnmodels\Other\NeutralBuildingExplosion\NeutralBuildingExplosion.mdl
              • Special Effect - Destroy (Last created special effect)
              • Set Distance = (Integer((Facing of CasterFE)))
              • For each (Integer A) from 1 to 12, do (Actions)
                • Loop - Actions
                  • Set Distance = (Distance + 30)
                  • Unit - Create 1 Dummy for (Owner of CasterFE) at FireballLoc facing (Real(Distance)) degrees
                  • Set FireUnitLoc = (Position of (Last created unit))
                  • Set FireLoc = (FireUnitLoc offset by 0.00 towards (Real(Distance)) degrees)
                  • Unit - Add a 0.50 second Generic expiration timer to (Last created unit)
                  • Unit - Set level of Fire (Dummy) for (Last created unit) to (Level of Fire Erruption for CasterFE)
                  • Unit - Order (Last created unit) to Neutral Pandaren Brewmaster - Breath Of Fire FireLoc
                  • Custom script: call RemoveLocation(udg_FireUnitLoc)
                  • Custom script: call RemoveLocation(udg_FireLoc)
              • Custom script: call RemoveLocation(udg_FireballLoc)
              • Unit Group - Remove (Picked unit) from FE_Ugrp
              • Hashtable - Clear all child hashtables of child (Key (Picked unit)) in Hash
            • Else - Actions


I've told you many times, in many threads of your spells, DON'T SAVE THE HANDLE OF THE UNIT FOR ITSELF!

You're saving it for nothing. You checking whether the dying unit is the dying unit. And in an unefficient, indirect way. A useless check made in an unefficient way.

Leak:
  • Set FireLoc = (FireUnitLoc offset by 0.00 towards (Real(Distance)) degrees)
You don't need the unit group at all.

I think the duration is too low because the unit has not time to complete the cast animation.

You should make the distance variable a real.

Dummies give visibility. And I don't think you need to remove the dying unit with Unit - remove. Set the dummies to can't revive, does not decay.

The tooltip isn't good.

Raises the ground at a targeted point
The ground doesn't raise.

then a giant fireball comes out from the center of the ground
Center of the ground? Use some other expression to describe the target point of ability being cast.

when the fireball explodes it splits into 360 degrees that deals damage to every enemy in a line.
that deals -> dealing
slipts into 360 degrees could be worded differently.

I'm going to rate it 1/5 until you fix the dying trigger and you finally understand not to save the units handle for itself for no reason. After fixing, I could give it a solid 3. Sorry if I sound too harsh.
 
Last edited:
That is pretty harsh if you think about it. I agree about the bad triggering, but when it comes to creativity, i'd give a solid 4

Creativity: 4
Triggering: 2 and not 1 because my computer didn't explode :D
Tooltip: 1 - work on ur english dude :/
Overall: 2 - not being TOO harsh

edit - 2 years later
Boy was I silly ;_;
 
Last edited:
Level 29
Joined
Mar 10, 2009
Messages
5,016
At least credit, me dude, seriously you pissed me off.
I'm off your project, see ya.
This is my spell, and you..................................
Never mind, never mind, relax defskull ;D

I did credit you, see UP 'In Big Coloured Letters', and I put your name in the 'Author' in the map, also I cant +rep you coz I already did...so what more you want?...

How to change that?, Created by ???
 
Last edited:
Level 22
Joined
Nov 14, 2008
Messages
3,256
Nice spell kid! Just wonder why you are using TimerUtils and why in hell are you using purple? Blue is fine at the moment with hashtables or either way you can make it orange which will probably be faster than purple.

I even learned something from this spell :)

Also you should really learn to use T32 instead of TU, much better for periodical spells (well may not apply to this one but still better to run with one timer ).

Shouldn't the duration be configurable?

And btw you don't need the if in the loop because you can just fire the timer with 5 seconds wait time and then do your actions if the "caster" is not dead (alright you might need the if but still).
 
Level 29
Joined
Mar 10, 2009
Messages
5,016
Because they say it is the safest, see Im not really using the original TimerUtils but a modified one by Iron_Doors without using hashtables...I even tried converting your recycling timer into a small library and used hash, it worked but at the end I've decided to use this one instead (my taste at the moment)...

I really need the if for the loop coz what if the caster dies, then the fire flame will still fire...and yeah, next time I will configure the duration...


Are you kidding?, you a mighty coder learned from this?...hehe, in that case thank you!...
I'm still learning the heart of structs and I never though this was going to be easy ofc thanks to you guys!...
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
loopindexstart should be a local variable (i) not a struct member. Struct members are arrays and wow they are slow compared to what you could do with this.

loopindexend should be a constant, not a struct member.

x1, y1, x2, y2 are also temporary (could be locals) and not dynamic array members.

So far you could trim out 6 arrays! ;)
 
Level 29
Joined
Mar 10, 2009
Messages
5,016
I really dont know who to heed although Bribe's suggestion is OK also the customizable thing...

Bribe said:
loopindexend should be a constant, not a struct member.

baassee said:
loopindexend should be a member and it should be customizeable :D

As far as I know, the term 'member' (unless I'm wrong) reffers to structs...
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
integer loopindexend = 12 //Loop maximum, you may adjust this

Yeah look at this guy, it actually creates an array just to make something that should just be a configurable constant. Instead of this:

JASS:
constant integer LOOP_INDEX_END = 12

It compiles to this:

JASS:
integer array s_struct__loopindexend

// And where the "allocate" function is found:
set s_struct__loopindexend[this] = 12
 

Dr Super Good

Spell Reviewer
Level 63
Joined
Jan 18, 2005
Messages
27,188
KillUnit leaks as much as RemoveUnit or natural unit death due to combat damage. The unit leak is a WarCraft III internal bug.

KillUnit can fool people in that it does what is says. It kills the unit, running death animation and decay process. Even if a dummy unit has no model it can still have a decay process as specified in the object editor. You can remove this by changing the units death type to cannot rise and cannot decay or something similar to that which will cause it to immediatly dissapear on death. Decay can be a big problem for dummies with art as the art will remain until the decay completes which can degrade performance in intense battles although it will be restored after the decay time passes.

RemoveUnit instantly removes the unit thus has no problem with decay. Alternativly you can also set a unit to explode on death which will play the explosion animation but instantly remove the unit.

For simple tasks you should try and recycle dummy units. Create a pool of them once and then re-use the same dummy units on demand instead of making and removing old ones. For generic ability casting dummies this is very effective as you can add the abilites as required via script. Such a dummy system would be best provided as a sharable resource so many systems (abilities in this case) could share the same dummy pool further improving the efficiency gain. Hidding dummies usually invlovles placing them off the edge of the map or into areas no one can visit to avoid mini-map artifacts. As dummies use Locust it might not be advisable to hide them as that might cause strange behaviour with the locust ability.
 
even if you remove the dummy from the game it will not be removed completely...other 2 suggestions Ima do...pls add more before I update this...

But if you have the dummy unit's death type set to "Can't raise, does not decay", (which it MUST have), then the unit will never decay and occupy a handle id.

If the handle ids start to get too high, Warcraft III will begin to lag heavily.
 
Top