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

Custom Script Fix

Status
Not open for further replies.
Level 14
Joined
Dec 29, 2009
Messages
931
  • FS Run
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Feared Strike
    • Actions
      • Set FS_TempLoc00 = (Position of (Target unit of ability being cast))
      • Set FS_TempUnit00 = (Target unit of ability being cast)
      • Wait 0.40 seconds
      • Unit - Cause (Triggering unit) to damage FS_TempUnit00, dealing ((Real((Level of (Ability being cast) for (Triggering unit)))) x 50.00) damage of attack type Spells and damage type Normal
      • Unit - Pause FS_TempUnit00
      • Unit - Move (Triggering unit) instantly to FS_TempLoc00
      • Animation - Play (Triggering unit)'s attack animation
      • Wait 0.25 seconds
      • Unit - Unpause FS_TempUnit00
      • Custom script: call RemoveUnit(udg_FS_TempUnit00)
      • Custom script: call RemoveLocation(udg_FS_TempLoc00)
That's my trigger. I have a problem with this part:

  • Custom script: call RemoveUnit(udg_FS_TempUnit00)
It seems it removes the unit, instead of just reseting the variable. How can I reset the WITHOUT removing the unit?

Or rather, do I even need to reset the variable?

~Go easy on me, this is the first ability I've ever made, and my first time using custom scripts.

+REP will be given to whoever helps me.
 
Level 33
Joined
Mar 27, 2008
Messages
8,035
Off-topic
You should NEVER use Wait action as this can cause errors and bugs
Why do you want to remove the unit ?
You want to clean the leaks or something ?
If you are, you should just use this:

  • Unit - Add a "value" second Generic expiration timer to (Your soon-to-die unit)
This action is from Unit - Add Expiration Timer
By adding this action, the trigger will automatically clean the leak
It doesn't need any custom script to clean it off
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
Timers take less than a minute to set up and are better in pretty much every way than waits are. There are very few situations which justify using waits.

That said, I think the OP of this thread is an excellent example of why you shouldn't just teach people to blindly call some function at the end of every trigger to "clean up leaks" somehow.

--

Alright, here's a crash course on leaks.

Object leaks (for example, the location in this trigger): Warcraft III has no garbage collection, so unused objects have to be explicitly gotten rid of. In the case of your trigger, you are creating a Location object and thus need to get rid of it (via RemoveLocation) to prevent leaks. However, in the case of the unit, getting rid of the unit is undesirable since the unit is interacting with the game (and units will be automatically cleaned up when they die/decay regardless).

Reference leaks (for example, setting a variable to null): If you don't dereference every reference to an object after it is destroyed, then the index will never free. This only really matters if you cause enough of these to run out of references, which will almost never happen, or if you are using GetHandleId() and hashtables. In the case of local variables, this means you will have to null object-related variables (assuming the object will be destroyed at some point in the game, which excludes things such as players/heroes/etc that generally persist) since they can never be assigned after the function exits, but in the case of global variables reassigning them will dereference the old reference and thus cause the index to eventually be freed regardless.

Hopefully that was somewhat understandable. The first part (object leaks) is far more important for GUI.
 
Level 33
Joined
Mar 27, 2008
Messages
8,035
MUI = Multi Unit-Instanceable
Meaning multiplayer units can cast the spel at the same time, without having bugs or errors
Usually, Wait action can cause the trigger to be non-MUI as Wait action should ONLY be use under certain circumstance like the trigger is meant for Single-player map

Another 1 is MPI = Multi Player-Instanceable
It allows the trigger to be used by multiple Player at a time
 
Level 33
Joined
Mar 27, 2008
Messages
8,035
You can create variable for Timer, but you must destroy it later by using Custom script: call DestroyTimer(udg_variable) !

However, you can also just create the timer without the use of variable:

  • Countdown Timer - Start (Last started timer) as a One-shot timer that will expire in 30.00 seconds
By using this method, you don't need the custom script and it's leakless
 
Level 14
Joined
Dec 29, 2009
Messages
931
Too late. :smile:

  • FS Run
  • Events
  • Unit - A unit Starts the effect of an ability
  • Conditions
  • (Ability being cast) Equal to Feared Strike
  • Actions
  • Set FS_TempLoc00 = (Position of (Target unit of ability being cast))
  • Set FS_TempUnit00 = (Target unit of ability being cast)
  • Countdown Timer - Start FS_WaitTimer00 as a One-shot timer that will expire in 0.40 seconds
That was the first trigger..
..Here is the second.

  • FS RunNext
    • Events
      • Time - FS_WaitTimer00 expires
    • Conditions
    • Actions
      • Unit - Cause (Triggering unit) to damage FS_TempUnit00, dealing ((Real((Level of (Ability being cast) for (Triggering unit)))) x 50.00) damage of attack type Spells and damage type Normal
      • Unit - Pause FS_TempUnit00
      • Unit - Move (Triggering unit) instantly to FS_TempLoc00
      • Special Effect - Create a special effect at FS_TempLoc00 using Abilities\Spells\Undead\AnimateDead\AnimateDeadTarget.mdl
      • Special Effect - Destroy (Last created special effect)
      • Animation - Play (Triggering unit)'s attack animation
      • Countdown Timer - Start FS_WaitTimer01 as a One-shot timer that will expire in 0.25 seconds
Here is the final trigger.

  • FS RunFinal
    • Events
      • Time - FS_WaitTimer01 expires
    • Conditions
    • Actions
      • Unit - Unpause FS_TempUnit00
      • Custom script: call RemoveLocation(udg_FS_TempLoc00)
It doesn't look as cool and complicated, 'cuz it's in 3 smaller, seperate triggers... but... I suppose if it works correctly... :cry:
 
Level 14
Joined
Dec 29, 2009
Messages
931
I forgot to add in the custom script to remove the timer. Deos that help it any?

Here it is.

  • FS RunFinal
    • Events
      • Time - FS_WaitTimer01 expires
    • Conditions
    • Actions
      • Unit - Unpause FS_TempUnit00
      • Custom script: call RemoveLocation(udg_FS_TempLoc00)
      • Custom script: call DestroyTimer(udg_FS_WaitTimer00)
      • Custom script: call DestroyTimer(udg_FS_WaitTimer01)
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
No, don't destroy the timers, since you will want to use them more than once.

The issue is that you are trying to carry a value in a global variable over time, so if the trigger executes a second time while the first instance is still executing the values will be overwritten and thus the old values will be forgotten.
 
Level 33
Joined
Mar 27, 2008
Messages
8,035
Please use checking Conditions, like this:

  • Checking
    • Events
      • Time - Every 0.03 seconds of game time
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Integer((Remaining time for (*Your Timer*)))) Equal to 0
        • Then - Actions
          • *Here is your action*
        • Else - Actions
Relate this trigger with your initial trigger using Turn On Trigger action

@PurplePoot
No wonder I've had some bugs with my Timer, I've destroyed them and the old values are forgotten~
But, if the timer is not cleaned, it leaks, what about it ?
Leak is bad you know...
But like I said, if you didn't set your Timer as Variable, you would not need to destroy it as it doesn't naturally leaks
 
Level 14
Joined
Dec 29, 2009
Messages
931
Ugh... This is taking more than 0.0016 seconds.. Will it really matter all that much if I just use Wait actions?

I'm not trying to be lazy here... but.. I don't really need to wait... it just made it look more complex. Special Effect-wise. :grin:
 
Here is some info about waits:
  • Good use of wait
    • Events
      • Unit - A unit Acquires an item
    • Conditions
    • Actions
      • Wait 10.00 seconds
      • Unit - Kill (Triggering unit)
  • Bad use of wait
    • Events
      • Unit - A unit Acquires an item
    • Conditions
    • Actions
      • Set p = (Position of (Triggering unit))
      • Wait 5.00 seconds
      • Unit Group - Pick every unit in (Units in (Playable map area)) and do (Actions)
        • Loop - Actions
          • For each (Integer A) from 1 to 10, do (Actions)
            • Loop - Actions
              • Wait 5.00 seconds
              • For each (Integer A) from 1 to 10, do (Actions)
                • Loop - Actions
                  • Wait 5.00 seconds
                  • Unit - Kill u
                  • Custom script: call RemoveLocation(udg_p)
About timers: if you want MUI timers, you'll need to use Hashtables(arrays don't work as you can't detect the expired timer), as your above trigger won't be MUI. In this case, you might as well use waits.

So, to clarify things: use the bloody waits in that trigger!

@Post 22 by defskull: if you're gonna do that thing, you might as well make a periodic trigger.

Arkon Kaos, if you want, I can give you a demo map of all 3 different types of 'waits'.
 
Level 19
Joined
Feb 4, 2009
Messages
1,313
Here is some info about waits:
  • Good use of wait
    • Events
      • Unit - A unit Acquires an item
    • Conditions
    • Actions
      • Wait 10.00 seconds
      • Unit - Kill (Triggering unit)
use gametime wait since normal wait might disconnect players because of the inaccuracy of waits (and lags might fuck it up further)
the gametime wait waits until all players synced their stuff

arrays don't work as you can't detect the expired timer
for int i from to....
GetExpiredTimer() == timer

@topic
I'd use a periodic time event for that or use no wait at all
doubt that any player will care if it takes a few parts of a second to cast that spell or not
also you could avoid "pause unit" this way and you won't have to struggle with any other spells using "pause unit"
(e.g. you cast your spell, then an enemy casts a spell on you which pauses your hero for 10 seconds and makes him invulnerable for that duration but your spell unpauses your hero after 0.25 sec and you got an invulnerable hero for 9.75 seconds which would be lame)
 
Status
Not open for further replies.
Top