• 🏆 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!

Phoenix Spiral v1.2

A spell from my ORPG.

Calls down 5 phoenixes from the sky to defend the hero. The phoenixes move circulary burning nearby enemies and firing flames toward them.

Everything, except duration, can be configured in object editor.

  • Init
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Visibility - Disable fog of war
      • Visibility - Disable black mask
      • Set TempLoc = (Center of (Playable map area))
      • Unit - Create 1 Phoenix Dummy for Neutral Passive at TempLoc facing 0.00 degrees
      • Unit - Add Phoenix Spiral Ignite to (Last created unit)
      • Unit - Add Flames Damage to (Last created unit)
      • Unit - Explode (Last created unit)
      • Custom script: call RemoveLocation (udg_TempLoc)
  • Phoenix Spiral
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Phoenix Spiral
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • PSHas[PSLastRecycled] Equal to True
        • Then - Actions
          • Set PSMax = (PSMax + 1)
          • Set PSIndex = PSMax
        • Else - Actions
          • Set PSIndex = PSLastRecycled
          • Set PSLastRecycled = PSRecycledList[PSLastRecycled]
      • Set PSCaster[PSIndex] = (Triggering unit)
      • Set PSTimer[PSIndex] = (9.00 + (Real((Level of Phoenix Spiral for PSCaster[PSIndex]))))
      • Set PSHas[PSIndex] = True
      • Set PSReached[PSIndex] = False
      • Set PSCount = (PSCount + 1)
      • Set PSHeight[PSIndex] = 1450.00
      • Set PSAnglePlus[PSIndex] = 0.00
      • Set TempInt = (Level of Phoenix Spiral for PSCaster[PSIndex])
      • Custom script: set udg_PSPhoenixGroup[udg_PSIndex] = CreateGroup()
      • Set TempLoc = (Position of PSCaster[PSIndex])
      • For each (Integer A) from 1 to 5, do (Actions)
        • Loop - Actions
          • Set TempLoc2 = (TempLoc offset by 1400.00 towards (72.00 x (Real((Integer A)))) degrees)
          • Unit - Create 1 Phoenix Dummy for (Triggering player) at TempLoc2 facing ((Angle from TempLoc to TempLoc2) - 90.00) degrees
          • Set TempUnit = (Last created unit)
          • Unit - Turn collision for TempUnit Off
          • Unit Group - Add TempUnit to PSPhoenixGroup[PSIndex]
          • Animation - Change TempUnit flying height to PSHeight[PSIndex] at 0.00
          • Animation - Change TempUnit's size to (50.00%, 50.00%, 50.00%) of its original size
          • Unit - Add Phoenix Spiral Ignite to TempUnit
          • Unit - Set level of Phoenix Spiral Ignite for TempUnit to TempInt
          • Unit - Add Flames Damage to TempUnit
          • Unit - Set level of Flames Damage for TempUnit to TempInt
          • Custom script: call RemoveLocation (udg_TempLoc2)
      • Custom script: call RemoveLocation (udg_TempLoc)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Phoenix Spiral Loop <gen> is on) Equal to False
        • Then - Actions
          • Trigger - Turn on Phoenix Spiral Loop <gen>
        • Else - Actions
  • Phoenix Spiral Loop
    • Events
      • Time - Every 0.03 seconds of game time
    • Conditions
    • Actions
      • For each (Integer PSInteger) from 0 to PSMax, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • PSHas[PSInteger] Equal to True
            • Then - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • PSReached[PSInteger] Equal to False
                • Then - Actions
                  • Set TempLoc = (Position of PSCaster[PSInteger])
                  • Set PSHeight[PSInteger] = (PSHeight[PSInteger] - 70.00)
                  • Set PSAnglePlus[PSInteger] = (PSAnglePlus[PSInteger] + 5.00)
                  • Set TempReal2 = PSAnglePlus[PSInteger]
                  • Unit Group - Pick every unit in PSPhoenixGroup[PSInteger] and do (Actions)
                    • Loop - Actions
                      • Set TempUnit = (Picked unit)
                      • Set TempLoc2 = (Position of TempUnit)
                      • Set TempReal = ((Distance between TempLoc and TempLoc2) - 60.00)
                      • Set TempLoc3 = (TempLoc offset by TempReal towards TempReal2 degrees)
                      • Unit - Move TempUnit instantly to TempLoc3, facing (TempReal2 + 90.00) degrees
                      • Animation - Change TempUnit flying height to PSHeight[PSInteger] at 0.00
                      • Custom script: call RemoveLocation (udg_TempLoc2)
                      • Custom script: call RemoveLocation (udg_TempLoc3)
                      • Set TempReal2 = (TempReal2 + 72.00)
                  • Custom script: call RemoveLocation (udg_TempLoc)
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • TempReal Less than 101.00
                    • Then - Actions
                      • Set PSReached[PSInteger] = True
                    • Else - Actions
                • Else - Actions
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • PSTimer[PSInteger] Greater than 0.00
                    • Then - Actions
                      • Set PSTimer[PSInteger] = (PSTimer[PSInteger] - 0.03)
                      • Set TempLoc = (Position of PSCaster[PSInteger])
                      • Set PSAnglePlus[PSInteger] = (PSAnglePlus[PSInteger] + 5.00)
                      • Set TempReal = PSAnglePlus[PSInteger]
                      • Unit Group - Pick every unit in PSPhoenixGroup[PSInteger] and do (Actions)
                        • Loop - Actions
                          • Set TempUnit = (Picked unit)
                          • Set TempLoc2 = (Position of TempUnit)
                          • Set TempLoc3 = (TempLoc offset by 100.00 towards TempReal degrees)
                          • Unit - Move TempUnit instantly to TempLoc3, facing (TempReal + 90.00) degrees
                          • Custom script: call RemoveLocation (udg_TempLoc2)
                          • Custom script: call RemoveLocation (udg_TempLoc3)
                          • Set TempReal = (TempReal + 72.00)
                      • Custom script: call RemoveLocation (udg_TempLoc)
                    • Else - Actions
                      • Unit Group - Pick every unit in PSPhoenixGroup[PSInteger] and do (Unit - Explode (Picked unit))
                      • Custom script: call DestroyGroup (udg_PSPhoenixGroup[udg_PSInteger])
                      • Set PSCount = (PSCount - 1)
                      • Set PSHas[PSInteger] = False
                      • Set PSRecycledList[PSInteger] = PSLastRecycled
                      • Set PSLastRecycled = PSInteger
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • PSCount Equal to 0
                        • Then - Actions
                          • Trigger - Turn off (This trigger)
                          • Set PSMax = 0
                          • Set PSRecycledList[0] = 0
                          • Set PSLastRecycled = 0
                        • Else - Actions
            • Else - Actions
v1.2
fixed system bug
v1.1
fixed system bug


Keywords:
phoenix, fire, flame, spell, damage, ignite, burn, BUUUUUUUUUUUUUURN, death, kill, destroy, ruin, lit, spellbreaker, warrior
Contents

Just another Warcraft III map (Map)

Reviews
18:34GMT, 25th Jun 2011 Bribe: Great work on this spell. It's now lag-free on the first cast and runs smoothly even on older computers like mine. I suggest changing the demo map's name from "Just another wc3 map" so that it's easier to find...

Moderator

M

Moderator

18:34GMT, 25th Jun 2011
Bribe:

Great work on this spell. It's now lag-free on the first cast and runs smoothly even on older computers like mine.

I suggest changing the demo map's name from "Just another wc3 map" so that it's easier to find when people are browsing their maps.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
Your indexing needs fixing:

  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
    • If - Conditions
      • PSHas[PSLastRecycled] Equal to True
    • Then - Actions
      • Set PSMax = (PSMax + 1)
      • Set PSLastRecycled = PSMax
      • -------- These next two lines should be deleted, and instead of the
      • -------- above line set "PSIndex" = PSMax.
      • Set PSIndex = PSLastRecycled
      • Set PSLastRecycled = PSRecycledList[PSLastRecycled]
    • Else - Actions
      • Set PSIndex = PSLastRecycled
      • Set PSLastRecycled = PSRecycledList[PSLastRecycled]
I've been looking at the indexing you use for a long time and finally figured out what the problem was with it. You should apply this fix to your existing systems as well.

The JASS code for it actually looks like this:

JASS:
function NewIndex takes nothing returns integer
    local integer this
    if lastRecycled == 0 then
        set indexCount = indexCount + 1
        set this = indexCount
    else
        set this = lastRecycled
        set lastRecycled = recycleList[this]
    endif
    set recycleList[this] = -1
    return this
endfunction

constant function HasIndex takes integer this returns boolean
    return recycleList[this] == -1
endfunction

function DelIndex takes integer this returns nothing
    if HasIndex(this) then
        set recycleList[this] = lastRecycled
        set lastRecycled = this
    endif
endfunction

You can keep iterating over instances the way you do from the timer-trigger, in most cases it will be efficient enough. Just loop from 1 to "indexCount" and check if the "recycleList" for that index is equal to "-1"
 
Last edited:
Level 16
Joined
Jun 24, 2009
Messages
1,409
Your indexing needs fixing:

  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
    • If - Conditions
      • PSHas[PSLastRecycled] Equal to True
    • Then - Actions
      • Set PSMax = (PSMax + 1)
      • Set PSLastRecycled = PSMax
      • -------- These next two lines should be deleted, and instead of the
      • -------- above line set "PSIndex" = PSMax.
      • Set PSIndex = PSLastRecycled
      • Set PSLastRecycled = PSRecycledList[PSLastRecycled]
    • Else - Actions
      • Set PSIndex = PSLastRecycled
      • Set PSLastRecycled = PSRecycledList[PSLastRecycled]
I've been looking at the indexing you use for a long time and finally figured out what the problem was with it. You should apply this fix to your existing systems as well.

o_O
Is that generates a problem? All my spells using this system is tested and soetimes when I create a spell I think quite awesome I just spawn it with 10-15 units ~.~ Never found any problem.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
Please check my post again, I edited it ;)

Basically your indexing was not remembering the recycled instances. Of course by playing the game you won't usually come across this problem, but what you have set up will break the spell after you casted it 8190 times. This also affects performance - after 1000 or so casts, you'll be iterating over 1000 dead instances each time you cast the spell.
 
Level 16
Joined
Jun 24, 2009
Messages
1,409
Oh now I see. When it creates a new instance because maximum is reached it also sets the last recycleable instance on the new one, so when it got cast again it will create a max again and again ...
I fix this in my spells ~.~
Edit: I also try to add a func to reset the Max number of instances.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
The code just needs one change - preload the unit in a map initializer function (or use a special effect attached to the dummy.mdx model and preload that). Just do:

  • Preload
    • Events
      • Map Initialization
    • Conditions
    • Actions
      • Set TempLoc = (Center of (Playable map area))
      • Unit - Create 1 Dummy Unit for (Neutral passive) at TempLoc facing 0 degrees
      • Unit - Explode (Last created unit)
      • Custom script: call RemoveLocation(udg_TempLoc)
If you notice, the phoenix effects don't display correctly the first time. Making this change would fix said problem.

The effects look really great!
 
IMO locals read faster than globals...TriggeringUnit/PickedUnit/LastCreatedUnit works as locals...

they actually call functions so they're slower than the variables... and that's why we set them to variables when we use them a lot on a trigger...
sample:
TriggeringUnit = GetTriggerUnit() //which is a function not a variable

On the spell - hmmm... looks cool... though not a fan of damage set on the OE as its not flexible... ^_^
 
Level 5
Joined
Jul 7, 2010
Messages
69
Or.... does the size of the map affect the spell (for example the map is 9mb)?... some times when i cast it only 1 bird comes in, after when i cast it again the birds are high up from the ground... then after when i cast i again it runs better... then again the bug repeats t.t
 
Level 5
Joined
Jul 7, 2010
Messages
69
9MB map?? Seems like it's your laggy map that's the problem.

Yes I thought so... I'll reduce and remove unwanted triggers and junk... that could solve the problem...

the test map size is under 100kb, if you imported the spell to your map then re-check the triggers, sometimes copy can mess up everything

Sorry for that... I just didn't anticipate that, that could happen sorry...
 
Level 39
Joined
Feb 27, 2007
Messages
4,992
Okay, here's how I figured this out:
  1. Look at the spell triggers in the description at the top, so I didn't have to open the WE. If they weren't visible or I wanted to make sure they were accurate to what's in the map I could download an open it or click the Preview Triggers button in the map info panel at the bottom of the description.
  2. Look at the events for each trigger to determine when they run/guess about what they might be for:
    • First trigger is for initialization of variables and other map specific things
    • Second trigger runs when a unit casts the spell, so it probably sets things up for whatever happens periodically (I never ran the spell and there's no video so IDK what this spell actually does)
    • Third trigger runs periodically, so it must control the motion of things and therefore the height of things and therefore how fast that height changes
  3. Take a moment to think about how a unit's height would be changed. WC3 is effectively a 2D game in the XY dimension, where the Z dimension is just used visually to differentiate flying units and add additional detail to the game. You're either flying or you're not, and at any height you can pass 'over' any destructable as long as it's not set to block air pathing or has pathing blockers. In this regard, motion in the Z direction must be controlled by the Animation - Change unit fly heightfunction, which has a couple little quirks:
    • Units don't actually have to be flying to use this function on them. They just have to have been given, at one point in their existence (it can be removed immediately), Medivh's Crow Form ability. This tricks them into being movable in the z direction like flying units without being flying units)!
    • You can set fly height over time using a number to control the rate of change, or you can set it instantly using 0 as the rate of change.
  4. From 3. I conclude that I must be looking for an Animation - Change unit fly height line somewhere, and that it either occurs once when the phoenixes are created or periodically throughout the trigger.
  5. Begin my search in the cast trigger, looking for Unit - Create lines. It creates phoenixes and sets their fly heights inside the loop! ...but it instantly sets it ("at 0.00") to the initial value of 1450. Conclude it must be in the periodic trigger.
  6. In the periodic trigger, I get confused because I thought the phoenixes were never stored in variables. They aren't! They're stored in a group and I missed that.
  7. Copy the name of the group, do a search in the page for the name of the variable to see where it's used in the periodic trigger. Another loop! I see an fly height setting line! It's instant! It sets it to... the fly height it already is? That doesn't make sense. Oh, the fly height variable must be changed somewhere up above, duh! So I look there.
  8. I start looking upwards from the loop I'm in and eventually see the line I quoted to you, inferring that since it goes down by 70 each iteration that must control the descent rate.
 
Last edited:
Top