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

Phase shift

Status
Not open for further replies.
Level 7
Joined
Nov 19, 2015
Messages
283
I've got this substitution spell based on phase shift and a dummy casting wand of illusion. However the illusion does not move unless I move my hero first. It also bugs up randomly.

When the unit is attacked, it also doesn't work the way it should between alternating hits. I think this is due to the phase shift firing off normally. Every other hit still damages my hero before the illusion is made.

I also use a movement system to detect when a unit is moving. Please tell me what is going wrong

  • Substitution
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Substitution
    • Actions
      • Set Player = (Owner of (Triggering unit))
      • Set unit[0] = (Triggering unit)
      • Set TempLoc[0] = (Position of (Triggering unit))
      • Unit Group - Add unit[0] to substitution_group
      • Unit - Turn collision for unit[0] Off
      • Unit - Create 1 Dummy for Player at TempLoc[0] facing Default building facing degrees
      • Unit - Add a 0.50 second Generic expiration timer to (Last created unit)
      • Set unit[1] = (Last created unit)
      • Unit - Add Substitution illusion to (Last created unit)
      • Custom script: set udg_key[0] = GetHandleId(udg_unit[1])
      • Hashtable - Save Handle Ofunit[0] as (Key substitution) of key[0] in spell_hash
      • Hashtable - Save UnitMoving[(Custom value of unit[0])] as (Key substitution moving) of key[0] in spell_hash
      • Custom script: call IssueTargetOrderById(udg_unit[1],852274,udg_unit[0])
      • Custom script: call RemoveLocation(udg_TempLoc[0])
  • Substitution illusion swap
    • Events
      • Unit - A unit Spawns a summoned unit
    • Conditions
      • ((Summoned unit) is an illusion) Equal to True
    • Actions
      • Set unit[0] = (Summoning unit)
      • Custom script: set udg_key[0] = GetHandleId(udg_unit[0])
      • Set unit[3] = (Load (Key substitution) of key[0] in spell_hash)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (unit[3] has buff Substitution ) Equal to True
          • (Name of (Summoned unit)) Equal to (Name of unit[3])
        • Then - Actions
          • Game - Display to (All players) the text: poof
          • Set unit[1] = (Summoned unit)
          • Set TempLoc[0] = (Position of unit[0])
          • Set TempLoc[1] = (Center of Region 000 <gen>) <<< (Disabled for testing)
          • Set TempLoc[1] = (TempLoc[0] offset by 256.00 towards ((Facing of unit[1]) + 180.00) degrees) <<< (For testing)
          • Unit - Turn collision for unit[1] Off
          • Custom script: call SetUnitX(udg_unit[1],GetLocationX(udg_TempLoc[0]))
          • Custom script: call SetUnitY(udg_unit[1],GetLocationY(udg_TempLoc[0]))
          • Unit - Turn collision for unit[1] On
          • Custom script: call SetUnitX(udg_unit[3],GetLocationX(udg_TempLoc[1]))
          • Custom script: call SetUnitY(udg_unit[3],GetLocationY(udg_TempLoc[1]))
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Load (Key substitution moving) of key[0] from spell_hash) Equal to True
            • Then - Actions
              • Game - Display to (All players) the text: moving
              • Set TempLoc[2] = (TempLoc[0] offset by 500.00 towards (Facing of unit[1]) degrees)
              • Unit - Order unit[1] to Move To TempLoc[2]
              • Unit - Order unit[1] to Set Rally Point To TempLoc[3]
              • Custom script: call RemoveLocation(udg_TempLoc[2])
            • Else - Actions
          • Custom script: call RemoveLocation(udg_TempLoc[0])
          • Custom script: call RemoveLocation(udg_TempLoc[1])
        • Else - Actions
          • Game - Display to (All players) the text: No buff
          • Set TempLoc[3] = (Position of unit[3])
          • Special Effect - Create a special effect at TempLoc[3] using Abilities\Spells\Human\ThunderClap\ThunderClapCaster.mdl
          • Special Effect - Destroy (Last created special effect)
  • Substitution auto
    • Events
      • Unit - A unit Is issued an order with no target
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Issued order) Equal to (Order(phaseshifton))
        • Then - Actions
          • Unit Group - Add (Triggering unit) to substitution_group
        • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Issued order) Equal to (Order(phaseshiftoff))
        • Then - Actions
          • Unit Group - Remove (Triggering unit) from substitution_group
        • Else - Actions
  • Substitution attack
    • Events
      • Unit - A unit Is attacked
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • ((Triggering unit) is in substitution_group) Equal to True
        • Then - Actions
          • Set unit[0] = (Attacked unit)
          • Set unit[1] = (Attacking unit)
          • Set TempLoc[0] = (Position of unit[0])
          • Unit - Order unit[0] to Night Elf Faerie Dragon - Phase Shift
          • Unit - Order unit[1] to Stop
          • Unit - Order unit[1] to Attack-Move To TempLoc[0]
          • Unit Group - Remove unit[0] from substitution_group
          • Custom script: call RemoveLocation(udg_TempLoc[0])
        • Else - Actions
 
I haven't looked into the code that much, but here is a quick recommendation:

Copy the spell and all its dependencies/triggers over into a separate test map, and test it there. Report back whether it works, has fewer bugs, or whether it still doesn't work. My thinking is this: you're reusing a lot of globals--and that can cause really weird bugs that are very difficult to track down.

For example, in your code you do three things that can potentially fire other triggers: create a unit (unit enters region), set a unit's position (unit enters region), and several orders. If you have any triggers that use those globals, then the data could potentially be overwritten/tampered with. While wc3 is single-threaded, it doesn't execute the way most people would assume it would. If you call a function that fires an event in the middle of the trigger, it'll pause execution for that trigger, jump over to the event trigger, complete that, and then jump back.

Good luck, and let me know if you get any progress!
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,202
If you call a function that fires an event in the middle of the trigger, it'll pause execution for that trigger, jump over to the event trigger, complete that, and then jump back.
Hence why local variables are so useful.

If this is happening you can detect the problem causers using some form of lock. When using certain variables you set a boolean global to true while they are used and false once a trigger finishes using them. If it is true and another trigger, in response to the mentioned events, wants to use the variables then you can print out an error message and know you have variable use overlap occurring.

This is one of the problems with using global variables as registers.

There are many ways to solve such a problem. Easiest is to use JASS where you have access to local variables which by nature cannot conflict with other threads. Another approach is to define a calling convention where by you push the used register values to a stack before running anything that fires another trigger. After the other trigger has finished running you can pull the values from the stack back into the register globals.
 
Level 7
Joined
Nov 19, 2015
Messages
283
Here is my test map that I remade.

View attachment Substitution test.w3x

For some reason I had a problem when adding the phase shift ability at first. It didn't show up on the hero but when I deleted it and re-added it, it worked.

Also the special effect doesn't go away like it does in my map, this test map has the sparkly gold effect at the position of the caster which is not supposed to happen.

It works after I move my hero. It doesn't work if I cast it repeatedly however not really an issue since I will have a longer cooldown but would like to know why it doesn't work when the units collide.
 
Level 7
Joined
Nov 19, 2015
Messages
283
Can anyone tell me why this doesn't work the first time I cast it.

I think it may have to do with the collision as casting it multiple times also fails
 
Status
Not open for further replies.
Top