Spell Heat Cyclone

Sim

Forum Administrator
Staff member
Reaction score
534
I present thee Heat Cyclone:

heatcycloneimproved.jpg


It is a long time since I coded my last spell, especially in vJASS. So, the other day, I decided to make sure I remember how by coding a new spell. ^^

It is rather simple really, I just wanted to make an efficient spell with an efficient timer system.

Anyways.

Here's the code:

JASS:
scope HeatCyclone initializer Init

//¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
//¤
//¤ ***************** 
//¤ - Heat Cyclone v2.0 - 
//¤ *****************
//¤ 
//¤ By: Daxtreme
//¤ 
//¤ --> How to implement in your map:
//¤                           
//¤     1. Copy the spell "Heat Cyclone" into your map.
//¤     2. Copy the spell named "Heat cyclone dummy" into your map.
//¤     3. (Optional, if you haven't a dummy unit already) Copy the unit "Dummy unit" into your map.
//¤     4. Copy this trigger into your map.
//¤     5. Import the FireTornado.mdx model into your map.
//¤     6. Import the Tornado2b.blp texture into your map.
//¤     7. Copy the trigger named "KT" into your map.
//¤     8. Copy the trigger named "GT" into your map.
//¤     9. Change the rawcodes in the configuration section so they fit with your map's.
//¤
//¤ --> How to customize it:
//¤
//¤     1. You can configure the spell using the few globals just below. Change their values.
//¤     2. The main editing happens in the object editor. The spell "Heat cyclone dummy" is the one that's
//¤        editable. Damage, Fireball speed, and distance are all examples of editable stuff.
//¤
//¤ CREDITS:
//¤
//¤     - JetFangInferno's Fire Tornado.
//¤     - Jesus4Lyf's KeyTimers2 and GTrigger Events sytems.
//¤     - Tinki3's spell map test template.
//¤
//¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

//¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
//
// ***      Configuration Section      ***
//
//¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

globals

private constant integer RawCode = 'A000' // The spell's rawcode in the editor
private constant integer dummyid = 'u001' // The dummy's id
private constant integer dummyspell = 'A002' // The dummy spell's id
private constant string effectpath = "war3mapImported\\FireTornado.mdx" // Path of the custom effect
private constant string orderstring = "carrionswarm" // Order string of the dummy spell
private constant real dummylife = 5. // If you want to increase the spell's duration, increasing the dummy's lifespan is
                                     // important.
private constant real angle = 18. // Angle increment between each fireball. The smaller the laggier.
private constant real period = 0.035 // Time between each instance of the dummy spell. Do not reduce this below 0.01
                                      // as the lag will increase
endglobals

//¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
//
// ***       Spell Code       ***
//
// --> I highly recommend editing the following only if you know what you're doing.
//
//¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

private struct data
    unit c
    integer lvl
    integer i = 0
    integer id
    effect fireww
    unit dummy
    real x
    real y
endstruct

private function Timer takes nothing returns boolean
    local data d = KT_GetData()
    local real x2
    local real y2
    if ( GetUnitCurrentOrder(d.c) != d.id ) then
        call DestroyEffect(d.fireww)
        call data.destroy(d)
        set d.c = null
        set d.fireww = null
        set d.dummy = null
        return true
    endif 
    set d.i = d.i + 1
    set x2 = d.x + 50. * Cos((angle * I2R(d.i)) * bj_DEGTORAD) // The 50. is to ensure the dummy correctly turns.
    set y2 = d.y + 50. * Sin((angle * I2R(d.i)) * bj_DEGTORAD) // Else, the spell does not make a perfect cyclone.
    call SetUnitFacing(d.dummy, bj_RADTODEG * Atan2(y2 - d.y, x2 - d.x))
    call IssuePointOrder(d.dummy, orderstring, x2, y2)
    return false
endfunction


private function Actions takes nothing returns boolean
    local data d = data.create()
    
    set d.c = GetTriggerUnit()
    set d.lvl = GetUnitAbilityLevel(d.c, RawCode)
    set d.x = GetUnitX(d.c)
    set d.y = GetUnitY(d.c)
    set d.fireww = AddSpecialEffectTarget(effectpath, d.c, "origin")
    set d.id = GetUnitCurrentOrder(d.c)
    set d.dummy = CreateUnit(GetOwningPlayer(d.c), dummyid, d.x, d.y, 0.)
    call UnitAddAbility(d.dummy, dummyspell)
    call SetUnitAbilityLevel(d.dummy, dummyspell, d.lvl)
    call UnitApplyTimedLife(d.dummy, 'BTLF', dummylife)
    call KT_Add(function Timer, d, period)
    return false
endfunction

//===========================================================================
private function Init takes nothing returns nothing
    call GT_AddActionToStartsEffectEvent(RawCode, function Actions)
endfunction

endscope


I'm a bit rusty with all this, and so I will gladly accept comments!

Thanks to JetFangInferno for the FireWhirlwind model, to Jesus4Lyf for his system KeyTimers2 and GTrigger, and to Tinki3 for the map template.

Enjoy!

EDIT: Small tweaks
EDIT2: Removed the order Id from configurable section. It now checks directly for the correct id.
EDIT3: struct is now private. Removed useless configuration. Made the effect path configurable.
EDIT4: MAJOR changes done to the spell. Removed lag almost entirely. Changed the missile effect and the base dummy spell.
EDIT5: Few tweaks updated.
EDIT6: Last update! Everything should be quite good now, and stable.
EDIT7: Version 2.0 (optional version) includes Jesus4Lyf's GTrigger system.
EDIT8: Update!
 

Attachments

  • Heat Cyclone v2.w3x
    88.9 KB · Views: 513

Tom Jones

N/A
Reaction score
437
Neat. Though you could probably get d.c's current order, and assign that to a variable and then check for that, instead of relying on a user defined orderid.
 

Sim

Forum Administrator
Staff member
Reaction score
534
Neat. Though you could probably get d.c's current order, and assign that to a variable and then check for that, instead of relying on a user defined orderid.

That's a nice idea. Working on that!
 

WolfieeifloW

WEHZ Helper
Reaction score
372
Just two things I saw:
  • Make "init" a private function.
  • And make "origin" customizable in the globals.
Otherwise, cool spell.
 

Sim

Forum Administrator
Staff member
Reaction score
534
Init is now private.

I actually made the effect path customizable, but its attachment point I didn't touch because it looks bad anyway if positioned otherwise.
 

Sim

Forum Administrator
Staff member
Reaction score
534
Thanks for the comments guys. :)
 

Sim

Forum Administrator
Staff member
Reaction score
534
Major update!

The spell's lag has been drastically decreased, and I think it looks wayyyy better now. Have a look at it!
 

Jesus4Lyf

Good Idea™
Reaction score
397
Hey, that's one brilliant looking spell. It really suits a bloodmage character, because the channel animation fits the cyclone model so well.

May I say though...

private constant real period = 0.0384

You should really change that to 0.035 or 0.04. The reason is Key Timers 2 doesn't support accuracy beyond 0.005. If it actually matters, I may be able to modify KT2 to allow more specific periods like 0.038. I just assumed people didn't need it. (See the "Cons" section of KT2.)

PS. Naturally I spammed the spell button and got about 10 instances going before it kinda lagged. XD
 

Sim

Forum Administrator
Staff member
Reaction score
534
> PS. Naturally I spammed the spell button and got about 10 instances going before it kinda lagged. XD

That's what's awesome with KT2 ;)

> You should really change that to 0.035 or 0.04

For sure. I chose randomly.

EDIT: updated! Period is set to 0.035. Nulled the handles within the struct. Fixed a boolexpr leak in the event.
 

BlackRose

Forum User
Reaction score
239
1. Hotkey don't work.
2. Map seems kinda small, I never liked the template anyway :(... it's too small.
3. Does inmporting the tornado.blp thingy affect the original spin?... or other Elemental Spins....

JASS:
        call DestroyEffect(d.fireww)
        call data.destroy(d)
        set d.c = null
        set d.p = null
        set d.fireww = null
        set d.dummy = null
        return true


I'm not that great at JASS, but you don't need to null them do you? I thought they were global arrays... and can't you put them into an onDestroy method?

---------------------------------------------

Otherwise, it's fancy :)
 

Jesus4Lyf

Good Idea™
Reaction score
397
BlackRose is indeed correct. Since stucts are stored in global arrays, they will be overwritten, so long as you destroy the struct. If the spell is only to be cast once in a map, then yes, null the struct data at the end. But if lets say if you don't null instance #3, then the next time you reach 3 instances, the old unnulled values will be overwritten anyway. :) (The condition for that is that you DO destroy the old structs, so the integer value can be re-used.)

So obviously they need not be in an onDestroy method either.
 

Sim

Forum Administrator
Staff member
Reaction score
534
Updated! In short, got rid of boolexpr leak and nulled globals handle. Why not. :)
 

Romek

Super Moderator
Reaction score
963
In the Init function, you set a boolexpr variable to null.
Then use it.
Then destroy null.
And null, null.

I think it'd be wise to just remove that local boolexpr. :p
 

Kenny

Back for now.
Reaction score
202
EDIT:

Haha, didn't realise you updated the spell without updating the script on your first post. :p (had crap about boolexpr in my original post)

Anywho, this spell is really cool, and looks really good. Had a lot of fun testing it out. +rep.

EDIT 2:

Your struct member for GetOwningPlayer() seems a little useless, you only really use it once. And im pretty sure player variables don't need to be nulled.
 

Romek

Super Moderator
Reaction score
963
> Some dude on HiveWorkshop told me this boolexpr usage method is the only way to get rid of the boolexpr expression leak.
I don't see how using a variable with the value of null is any better than using null itself.
(And then destroying the null, and nulling the null).

I heard that boolexprs in events don't leak anyway.
 

Sim

Forum Administrator
Staff member
Reaction score
534
Dude said:
well answer is all again blizzard's coding of it, boolexpr is like a table with condition you typed ~via Filter() or Condition() well since script does not know what pointer null is since it will not have table, the leak in memory is created because it will allocate something because you typed null and that something is some part of memory which can contain some data as well but will never again, until you leave the game.

Anyhow, I did it because I had nothing else to do. Right or wrong, it really does not matter as we can't be 100% sure it really leaks. Even if it does, it's 1 leak in the whole game, not 1 leak every time the spell is cast.

> Your struct member for GetOwningPlayer() seems a little useless, you only really use it once.

The struct member sure is useless.

> And im pretty sure player variables don't need to be nulled.

JASS:
type player             extends     handle  // a single player reference


It is an handle. Therefore, it must be nulled. (As a global variable in a struct, it leaks only once. But, why not remove it?)
I removed the player variable anyways.

EDIT: Updated the code above to fit the current version, and the player struct member removal. But that player removal is still not implemented in the map.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      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