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.
  • Monovertex Monovertex:
    How are you all? :D
    +1
  • Ghan Ghan:
    Howdy
  • Ghan Ghan:
    Still lurking
    +3
  • The Helper The Helper:
    I am great and it is fantastic to see you my friend!
    +1
  • The Helper The Helper:
    If you are new to the site please check out the Recipe and Food Forum https://www.thehelper.net/forums/recipes-and-food.220/
  • Monovertex Monovertex:
    How come you're so into recipes lately? Never saw this much interest in this topic in the old days of TH.net
  • Monovertex Monovertex:
    Hmm, how do I change my signature?
  • tom_mai78101 tom_mai78101:
    Signatures can be edit in your account profile. As for the old stuffs, I'm thinking it's because Blizzard is now under Microsoft, and because of Microsoft Xbox going the way it is, it's dreadful.
  • The Helper The Helper:
    I am not big on the recipes I am just promoting them - I use the site as a practice place promoting stuff
    +2
  • Monovertex Monovertex:
    @tom_mai78101 I must be blind. If I go on my profile I don't see any area to edit the signature; If I go to account details (settings) I don't see any signature area either.
  • The Helper The Helper:
    You can get there if you click the bell icon (alerts) and choose preferences from the bottom, signature will be in the menu on the left there https://www.thehelper.net/account/preferences
  • The Helper The Helper:
    I think I need to split the Sci/Tech news forum into 2 one for Science and one for Tech but I am hating all the moving of posts I would have to do
  • The Helper The Helper:
    What is up Old Mountain Shadow?
  • The Helper The Helper:
    Happy Thursday!
    +1
  • Varine Varine:
    Crazy how much 3d printing has come in the last few years. Sad that it's not as easily modifiable though
  • Varine Varine:
    I bought an Ender 3 during the pandemic and tinkered with it all the time. Just bought a Sovol, not as easy. I'm trying to make it use a different nozzle because I have a fuck ton of Volcanos, and they use what is basically a modified volcano that is just a smidge longer, and almost every part on this thing needs to be redone to make it work
  • Varine Varine:
    Luckily I have a 3d printer for that, I guess. But it's ridiculous. The regular volcanos are 21mm, these Sovol versions are about 23.5mm
  • Varine Varine:
    So, 2.5mm longer. But the thing that measures the bed is about 1.5mm above the nozzle, so if I swap it with a volcano then I'm 1mm behind it. So cool, new bracket to swap that, but THEN the fan shroud to direct air at the part is ALSO going to be .5mm to low, and so I need to redo that, but by doing that it is a little bit off where it should be blowing and it's throwing it at the heating block instead of the part, and fuck man
  • Varine Varine:
    I didn't realize they designed this entire thing to NOT be modded. I would have just got a fucking Bambu if I knew that, the whole point was I could fuck with this. And no one else makes shit for Sovol so I have to go through them, and they have... interesting pricing models. So I have a new extruder altogether that I'm taking apart and going to just design a whole new one to use my nozzles. Dumb design.
  • Varine Varine:
    Can't just buy a new heatblock, you need to get a whole hotend - so block, heater cartridge, thermistor, heatbreak, and nozzle. And they put this fucking paste in there so I can't take the thermistor or cartridge out with any ease, that's 30 dollars. Or you can get the whole extrudor with the direct driver AND that heatblock for like 50, but you still can't get any of it to come apart
  • Varine Varine:
    Partsbuilt has individual parts I found but they're expensive. I think I can get bits swapped around and make this work with generic shit though

      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