Spell Wheel of Misfortune

ZiggyMcjoney

Data editor?! AAAHHHHH!
Reaction score
95
For lack of a better name, here is my first JASS spell (and first submitted spell ever o_O), Wheel of Misfortune!

GUI/JASS: JASS
MUI: Yes
Leakless: Hopefully
Lagless: Haven't noticed any lag, although it would if you used an immense amount of summons.
Requires: Jass NewGen (check the Useful Tools thread in World Editor Help to download this)

Importation Instructions:
1. Import the "Dummy Unit (Forcefield)" unit to your map.
2. Import the "Wheel of Misfortune" spell.
3. Import this trigger. It'll save alot of trouble if you name the trigger WheelofMisfortune when you import it.
4. Done!

The map is attached at the bottom of the post.

What it does:
The Wheel of Misfortune is a spell that creates 10 units around you (calling them "Beacons" for lack of a better name). A random beacon will then explode, dealing damage to all nearby units and adding them to a group. The units from that group will then move to the next beacon, and that next beacon will explode, adding all damaged units to the group. At the end of the spiral, all units that were picked up by the Wheel are let free (if they're still alive). It's difficult to explain, but you might be able to make sense of it by looking at this screenshot, or playing the map:

Screenshot:
Wheel of Misfortune.JPG

Code:
Those who are illiterate towards JASS can still edit using the block of globals at the top of the trigger.
JASS:
//*******************************************************************************
//*         Wheel of Misfortune by GG_Pope(Vantuex/Arche/ZiggyMcJoney)          *
//*******************************************************************************
//* Some quick notes:                                                           *
//*     # Give credit if you use this spell in your map.                        *
//*     # This spell is MUI, leakless (hopefully) and lagless.                  *
//*     # Written in vJass with Jass NewGen v1.4.0.1 (thanks Vexorian!)         *
//*     # Bugs can be reported to the thread on TheHelper.net where you got this*
//*       from or at my email, <a href="mailto:[email protected]">[email protected]</a> (note, I don&#039;t read this *
//*       frequently!)                                                          *
//*                                                                             *
//* Import Instructions:                                                        *
//*     # 1. Import the &quot;Dummy Unit (Forcefield)&quot; unit to your map.             *
//*     # 2. Import the &quot;Wheel of Misfortune&quot; spell.                            *
//*     # 3. Import this trigger. It&#039;ll save alot of trouble if you name the    *
//*     trigger WheelofMisfortune when you import it.                           *
//*     # 4. Done!                                                              *
//*******************************************************************************


scope WheelofMisfortune

globals
    //Customizable Options:

    private integer direction = GetRandomInt(0,1) // 0 = Anti-Clockwise, 1 = Clockwise. Changes the direction in which the beacons explode.
    private integer maxloops = 10 //This variable changes the amount of units created.
    private integer unitid = &#039;nWOM&#039; //The Unit ID of the dummy unit. You won&#039;t have to change this unless you change the unit this spell creates.
    private integer spellid = &#039;AWOM&#039; //The Order ID of the spell you&#039;re casting. You won&#039;t have to change this unless you change the spell this trigger fires off.
    private string effect1 = &quot;Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilSpecialArt.mdl&quot; //This is the first special effect, created when the beacon is destroyed. Defaulted as Death Coil.
    private string effect2 = &quot;Abilities\\Spells\\Human\\Thunderclap\\ThunderClapCaster.mdl&quot; //This is the second special effect, created when the beacon is destroyed. Defaulted as Thunder Clap. 
    private string orderstring = &quot;absorb&quot; //This is the order string of the spell you&#039;re using to trigger this. You won&#039;t have to change
    private real damage = 50 * (GetUnitAbilityLevel(GetTriggerUnit(), spellid)) //This variable changes the damage dealt by the spell.
    private real radius = 150 //This variable changes how big the radius of the explosions are.
    private real spellradius = 250 //This variable changes how far away the beacons are created from the caster.
    private real frequency = 0.30 //This variable changes how quickly the beacons explode. Values below 0.30 will likely be inaccurate.this unless you change the order string on the spell in the object editor.
    
    //For options not listed above:
    //In the object editor, change &quot;Data - Follow Through Time&quot; to customize the channeling time.
    //To change the order string if your hero uses another spell with the &#039;absorb&#039; string, change Data - Base Order ID to another string. You must also change the &quot;orderstring&quot; global variable in the globals block above if you do this.
    //To change the model of the beacon, change the model on the Dummy Unit.
    
    //It is unecessary to change this:
    private location l
endglobals

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

private function GroupConditions takes nothing returns boolean
    return GetWidgetLife(GetFilterUnit()) &gt; .405 and IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(GetTriggerUnit())) == true and IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) == false
endfunction
    
private function Move takes nothing returns nothing
    call SetUnitPositionLoc(GetEnumUnit(), l)
    call PauseUnit(GetEnumUnit(), true)
    call SetUnitVertexColor(GetEnumUnit(), 100, 100, 100, 50)
    call UnitDamageTarget(GetTriggerUnit(), GetEnumUnit(), damage, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_WHOKNOWS)
endfunction

private function End takes nothing returns nothing
    call PauseUnit(GetEnumUnit(), false)
    call SetUnitVertexColor(GetEnumUnit(), 255, 255, 255, 255)
endfunction

private function Actions takes nothing returns nothing
    local integer li = GetRandomInt(1,maxloops)
    local integer listatic = li
    local integer lia = 1
    local unit array wall
    local real x
    local real y
    local group ug = CreateGroup()
    local group move = CreateGroup()
    loop
    exitwhen lia &gt; maxloops
        set x = GetUnitX(GetTriggerUnit()) + spellradius * Cos(li * (360/maxloops) * bj_DEGTORAD)
        set y = GetUnitY(GetTriggerUnit()) + spellradius * Sin(li * (360/maxloops) * bj_DEGTORAD)
        set wall[lia] = CreateUnit(GetOwningPlayer(GetTriggerUnit()), unitid, x, y, 270)
        if li == maxloops then
            set li = 1
        else
            set li = li + 1
        endif
        set lia = lia + 1
    endloop
    if direction == 0 then
        set li = 1
    else
        set li = 10
    endif
    loop
    exitwhen li&gt;maxloops or GetUnitCurrentOrder(GetTriggerUnit()) != String2OrderIdBJ(orderstring)
        call TriggerSleepAction(frequency)
        set x = GetUnitX(wall[li])
        set y = GetUnitY(wall[li])
        call RemoveUnit(wall[li])
        set wall[li] = null
        call DestroyEffect(AddSpecialEffect(effect1,x,y))
        call DestroyEffect(AddSpecialEffect(effect2,x,y))
        set l = Location(x,y)
        set ug = GetUnitsInRangeOfLocMatching(radius, l, Condition(function GroupConditions))
        call GroupAddGroup(ug, move)
        call DestroyGroup(ug)
        call ForGroup(move, function Move)
        call RemoveLocation(l)
        if direction == 0 then
            set li = li + 1
        else
            set li = li - 1
        endif
    endloop
    call ForGroup(move, function End)
    call DestroyGroup(move)
    loop
    exitwhen li&gt;maxloops
        set x = GetUnitX(wall[li])
        set y = GetUnitY(wall[li])
        call RemoveUnit(wall[li])
        set wall[li] = null
        call DestroyEffect(AddSpecialEffect(effect1, x, y))
        set li = li + 1
    endloop
    set move = null
    set ug = null
    set l = null
endfunction

function InitTrig_WheelofMisfortune takes nothing returns nothing
    set gg_trg_WheelofMisfortune = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_WheelofMisfortune, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_WheelofMisfortune, Condition( function Conditions ) )
    call TriggerAddAction( gg_trg_WheelofMisfortune, function Actions )
endfunction

endscope


I'll accept any comments and constructive criticism with open arms, as I'm still a bit of a nublet when it comes to JASS.

Thanks, hopefully you find this useful :p.

Tell me if I've forgotten any information on this post.

Version 1.4: Nulled some variables, fixed some issues with the trigger using static values instead of the globals and made the spell not hit structures. View attachment Wheel of Misfortune v1.4 by GG_Pope.w3x
 

Flare

Stops copies me!
Reaction score
662
Screenshot looks... weird.

Anyway, to the code:
Leaks and BJ's...
JASS:
        set x = GetLocationX(GetUnitLoc(wall[li]))
        set y = GetLocationY(GetUnitLoc(wall[li]))

GetUnitLoc is leaking there.
And here it is again
JASS:
        set x = GetLocationX(GetUnitLoc(GetTriggerUnit())) + spellradius * Cos(li * (360/maxloops) * bj_DEGTORAD)
        set y = GetLocationY(GetUnitLoc(GetTriggerUnit())) + spellradius * Sin(li * (360/maxloops) * bj_DEGTORAD)

You should use coordinates only (there is a GetUnitX and GetUnitY function :p)

JASS:
IsUnitAliveBJ(GetFilterUnit()) == true
//can become
GetWidgetLife (GetFilterUnit ()) &gt; .405


Also, if you are calling a unit (like GetEnumUnit () or GetTriggerUnit () ) multiple times within a function, set it to a variable. It shortens your code since you can refer to 'u' instead of 'GetTriggerUnit ()' all the time, and I think variables are faster than function calls.

JASS:
        set e = AddSpecialEffect(effect1, x, y)
        call DestroyEffect(e)
        set e = AddSpecialEffect(effect2, x, y)
        call DestroyEffect(e)

//Too much effort <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" class="smilie smilie--sprite smilie--sprite7" alt=":p" title="Stick Out Tongue    :p" loading="lazy" data-shortname=":p" />
//Can become this (and same for effect2)
call DestroyEffect (AddSpecialEffect (effect1, x, y))
 

ZiggyMcjoney

Data editor?! AAAHHHHH!
Reaction score
95
doesnt work for me

More information?

EDIT: Ugh, just had a look, it isn't working now -_-. Let me fix that.

EDIT2: There we go, it works now. I think I'll stop fixing stuff on this spell now because my heads not very clear right now.
 

PurgeandFire

zxcvmkgdfg
Reaction score
509
hm... Waits in loops. Meh, timers are better but I guess if you want something like 0.3 then I guess it is fine.

Anywho, you forgot to null the groups and you should seperately create a group and inline this function:
JASS:
GetUnitsInRangeOfLocMatching(150, Location(x,y), Condition(function GroupConditions))


Well, because you leak a location thar and it is a BJ.

But other than that the coding is pretty good. (I haven't checked all of it though, I will return o_O)
 

ZiggyMcjoney

Data editor?! AAAHHHHH!
Reaction score
95
hm... Waits in loops. Meh, timers are better but I guess if you want something like 0.3 then I guess it is fine.

Anywho, you forgot to null the groups and you should seperately create a group and inline this function:
JASS:
GetUnitsInRangeOfLocMatching(150, Location(x,y), Condition(function GroupConditions))


Well, because you leak a location thar and it is a BJ.

But other than that the coding is pretty good. (I haven't checked all of it though, I will return o_O)

Hrm, how would I go about changing it to use a timer instead of a wait?

Null the groups? You mean call DestroyGroup isn't enough? Where do I put the nulls?

Don't quite understand your last suggestion. Although I was looking for a non-bj version of GetUnitsInRangeOfLocMatching. What can I change there?
 

Flare

Stops copies me!
Reaction score
662
Null the groups? You mean call DestroyGroup isn't enough? Where do I put the nulls?

After you are completely finished using it (i.e. once you have destroyed that group, and don't use it again within that function)

you need to null all local handles when you are done within (here is a link to the common.j if you dont wanna extract if from the MPQ, it tells you everything that extends to handle (and thus, what needs to be nulled))
 

ZiggyMcjoney

Data editor?! AAAHHHHH!
Reaction score
95
After you are completely finished using it (i.e. once you have destroyed that group, and don't use it again within that function)

you need to null all local handles when you are done within (here is a link to the common.j if you dont wanna extract if from the MPQ, it tells you everything that extends to handle (and thus, what needs to be nulled))

Ah, thanks for that. I'll get to work on fixing those in a sec.
 
1

131ackout

Guest
Nice spell, even thought I'm not a JASS type person
Wish i could borrow that.
 

Flare

Stops copies me!
Reaction score
662
Nice spell, even thought I'm not a JASS type person
Wish i could borrow that.

Borrow what? You mean use the spell? It's not that difficult to alter the stuff that can be changed (without major consequences)

JASS:
    private integer direction = GetRandomInt(0,1) // 0 = Anti-Clockwise, 1 = Clockwise. Changes the direction in which the beacons explode.
    private integer maxloops = 10 //This variable changes the amount of units created.
    private integer unitid = &#039;nWOM&#039; //The Unit ID of the dummy unit. You won&#039;t have to change this unless you change the unit this spell creates.
    private integer spellid = &#039;AWOM&#039; //The Order ID of the spell you&#039;re casting. You won&#039;t have to change this unless you change the spell this trigger fires off.
    private string effect1 = &quot;Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilSpecialArt.mdl&quot; //This is the first special effect, created when the beacon is destroyed. Defaulted as Death Coil.
    private string effect2 = &quot;Abilities\\Spells\\Human\\Thunderclap\\ThunderClapCaster.mdl&quot; //This is the second special effect, created when the beacon is destroyed. Defaulted as Thunder Clap.
    private string orderstring = &quot;absorb&quot; //This is the order string of the spell you&#039;re using to trigger this. You won&#039;t have to change
    private real damage = 50 * (GetUnitAbilityLevel(GetTriggerUnit(), spellid)) //This variable changes the damage dealt by the spell.
    private real radius = 150 //This variable changes how big the radius of the explosions are.
    private real spellradius = 250 //This variable changes how far away the beacons are created from the caster.
    private real frequency = 0.30 //This variable changes how quickly the beacons explode. Values below 0.30 will likely be inaccurate.this unless you change the order string on the spell in the object editor.


Just change those values and you can alter the stats of the spell anyway you want.

EDIT: You could've made those globals constant (except damage) so that the values aren't accidently changed for some reason.
 

ZiggyMcjoney

Data editor?! AAAHHHHH!
Reaction score
95
Don't get what you mean by constant. I've heard the term thrown around but I don't really know what it means.

Explain? :p
 

Flare

Stops copies me!
Reaction score
662
Constant = won't change. The way you have it, you -could- possibly alter the value of your configuration values (you probably haven't done so, but there is the possibility that it could occur in other codes you make :p)

If the value is a constant, there's nothing that can change it I think, meaning that it won't be changed.

Not 100% sure though :p
 

PurgeandFire

zxcvmkgdfg
Reaction score
509
You leak a group:
JASS:
    local group ug = CreateGroup()


Don't initially create it since you are going to set it in the loop to a new value. (It is pointless since you don't use the group "ug" in the first place, until the loop where you create it all over again)

:thup:
 

ZiggyMcjoney

Data editor?! AAAHHHHH!
Reaction score
95
You leak a group:
JASS:
    local group ug = CreateGroup()


Don't initially create it since you are going to set it in the loop to a new value. (It is pointless since you don't use the group "ug" in the first place, until the loop where you create it all over again)

:thup:

Don't you have to initially created though? It didn't work before when I didn't have it that way.
 

PurgeandFire

zxcvmkgdfg
Reaction score
509
It works fine unless there is some sort of mistake in the code. GetUnits...blahblah creates the group for you as it is a BJ that returns "group".

Initially creating it shouldn't cause errors as it is pointless right now. ;)
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top