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

[Spell] Double click casting

Status
Not open for further replies.
Hello, I made this thing for my map and I want to consult to you guys if I made this right or if there is a much better way to do this. Basically what I am trying to achieve is to make the hero cast the spell everytime it double clicks the same spot. It works 90% of the time but sometimes - rarely - it doesn't.

  • Global Left Clicked Attack A
    • Events
      • Player - Player 1 (Red) issues Mouse Down event
    • Conditions
      • (Trigger Mouse Button) Equal to Left Mouse Button
    • Actions
      • Set Global_MousePoint = (Point((Mouse Position X for Triggered Mouse Event), (Mouse Position Y for Triggered Mouse Event)))
      • Wait 0.03 seconds
      • Trigger - Turn on Global Left Clicked Attack B <gen>
      • Trigger - Turn off (This trigger)
  • Global Left Clicked Attack B
    • Events
      • Player - Player 1 (Red) issues Mouse Down event
    • Conditions
      • (Trigger Mouse Button) Equal to Left Mouse Button
    • Actions
      • Set Global_MousePointB = (Point((Mouse Position X for Triggered Mouse Event), (Mouse Position Y for Triggered Mouse Event)))
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Distance between Global_MousePoint and Global_MousePointB) Less than or equal to 100.00
        • Then - Actions
          • Unit - Order Global_MainHero to Neutral Pandaren Brewmaster - Breath Of Fire Global_MousePointB
          • Special Effect - Create a special effect at (Point((Mouse Position X for Triggered Mouse Event), (Mouse Position Y for Triggered Mouse Event))) using war3mapImported\NewConfirmationRed.mdx
          • Special Effect - Destroy (Last created special effect)
        • Else - Actions
          • Do nothing
      • Custom script: call RemoveLocation(udg_Global_MousePoint)
      • Custom script: call RemoveLocation(udg_Global_MousePointB)
      • Trigger - Turn on Global Left Clicked Attack A <gen>
      • Trigger - Turn off (This trigger)
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,543
You're going to leak Global_MousePoint in trigger A if you click again before the 0.03 seconds is up. Plus you'll have multiple instances of the trigger firing.

Also check to see if Global_MousePoint exists BEFORE setting it in the first trigger. If it already exists then remove it before setting it again. You can keep track of the point using a Boolean like "PointIsActive = true/false". Set it to True after creating the point and set it to False after removing the Point.

You also probably want to start a second Timer in Trigger A that serves as a way to reset (Turn off B, Turn on A) everything if the Player doesn't click twice within a certain time frame. Because as it is now once you turn on Trigger B it will remain active forever until you click again. That would seem weird when clicking your ability once, waiting 10 seconds, then clicking again to trigger the ability. But then again you might want it to work that way.

Edit: Tested it by clicking rapidly and it appears that with your current setup and a wait of 0.03 seconds you can at the very least fire this trigger twice before it turns.
  • mouse
    • Events
      • Player - Player 1 (Red) issues Mouse Down event
    • Conditions
      • (Trigger Mouse Button) Equal to Left Mouse Button
    • Actions
      • Create Point at mouse position
      • Game - Display to (All players) for 30.00 seconds the text: Click
      • Wait 0.03 seconds
      • Trigger - Turn off (This trigger)
 
Last edited:
Level 39
Joined
Feb 27, 2007
Messages
5,015
That’s because the minimum wait time is ~0.27s. A wait with a duration lower than that will not actually wait that short duration but instead the longer min wait. This can’t be overcome, you must use a timer to time in increments lower than that.
 
I fixed it based on your responses but I am still not really contented to how it works, sometimes (maybe once every 10 double clicks) it doesn't really trigger the second one when I am clicking continuously.

  • Global Left Clicked Attack A
    • Events
      • Player - Player 1 (Red) issues Mouse Down event
    • Conditions
      • (Trigger Mouse Button) Equal to Left Mouse Button
    • Actions
      • Game - Display to (All players) the text: 1
      • Set Global_MousePointA= (Point((Mouse Position X for Triggered Mouse Event), (Mouse Position Y for Triggered Mouse Event)))
      • Set MouseCheck = True
      • Countdown Timer - Start MouseTimer as a One-shot timer that will expire in 0.50 seconds
      • Countdown Timer - Resume (Last started timer)
      • Trigger - Turn off (This trigger)
      • Wait 0.03 seconds
      • Trigger - Turn on Global Left Clicked Attack B <gen>
  • Global Left Clicked Attack B
    • Events
      • Player - Player 1 (Red) issues Mouse Down event
    • Conditions
    • Actions
      • Game - Display to (All players) the text: 2
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Trigger Mouse Button) Equal to Left Mouse Button
          • MouseCheck Equal to True
          • Remaining Time for MouseTimer Greater than 0.00
        • Then - Actions
          • Set Global_MousePointB = (Point((Mouse Position X for Triggered Mouse Event), (Mouse Position Y for Triggered Mouse Event)))
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • Distance between Global_MousePointA and Global_MousePointB Less than or equal to 200.00
            • Then - Actions
              • Unit - Order Global_MainHero to Neutral Pandaren Brewmaster - Breath Of Fire Point
              • Special Effect - Create a special effect at Global_MousePointB using war3mapImported\NewConfirmationRed.mdx
              • Special Effect - Destroy (Last created special effect)
            • Else - Actions
              • Do nothing
          • Custom script: call RemoveLocation(udg_Global_MousePointB)
        • Else - Actions
      • Set MouseCheck = False
      • Custom script: call RemoveLocation(udg_Global_MousePoint)
      • Trigger - Turn off (This trigger)
      • Wait 0.03 seconds
      • Trigger - Turn on Global Left Clicked Attack A <gen>
  • Global Left Clicked Attack C
    • Events
      • Time - MouseTimer expires
    • Conditions
    • Actions
      • Game - Display to (All players) the text: 3
      • Set MouseCheck = False
      • Trigger - Turn on Global Left Clicked Attack A <gen>
      • Trigger - Turn off Global Left Clicked Attack B <gen>
 
Last edited:
Level 39
Joined
Feb 27, 2007
Messages
5,015
IMO there's a much simpler solution: start a timer on map init for max duration. When a mouse click event is issued, save the current time elapsed on that timer into a variable, and compare that to the time elapsed at the last mouse click. If they are close enough in distance and the elapsed time is < your double click threshold, then it was double clicked. Since the events default to XY coordinates (not locations) you can simply save those and compute the distance as D = Sqrt(dx*dx + dy*dy). Also, mouse events that happen over the UI return (0,0) as the location, so probably filter those out.

  • Events
    • Map Initialization
  • Conditions
  • Actions
    • Countdown Timer - Start MouseTimer as a repeating timer that will expire in 100000.00 seconds
    • Set OldTime = 0.00
  • Events
    • Player - Player 1 (Red) issues a mouse down event
  • Conditions
  • Actions
    • Set NewX = (Mouse position X for (Triggered Mouse Event))
    • Set NewY = (Mouse position Y for (Triggered Mouse Event))
    • If (All conditions are true) then do (Then actions) else do (Else actions)
      • If - Conditions
        • MouseX not equal to 0.00
        • MouseY not equal to 0.00
      • Then - Actions
        • Set NewTime = (Elapsed time for MouseTimer)
        • Set DX = (NewX - OldX)
        • Set DY = (NewY - OldY)
        • If (All conditions are true) then do (Then actions) else do (Else actions)
          • If - Conditions
            • (NewTime - OldTime) less than DOUBLE_CLICK_WINDOW
            • SquareRoot((DX x DX) + (DY x DY)) less than DISTANCE_WINDOW
          • Then - Actions
            • -------- double click happened here --------
          • Else - Actions
        • Set OldTime = NewTime
        • Set OldX = NewX
        • Set OldY = NewY
      • Else - Actions
 
I worried earlier what will happen when the timer expires, then realized I just have to reset it every 27 hours :D (or maybe reset it when the caster is idle).

By the way the player can now cast more than twice when clicked under the time window (In my test it often gets 3 clicks under 0.15, lowering it makes it harder sometimes to identify if the player is double clicking) which is not how I expect it to work but since I will be spamming the clicks I guess I don't have to worry about it.

Still, thanks for the help. :)
 
Last edited:
Level 39
Joined
Feb 27, 2007
Messages
5,015
By the way the player can now cast more than twice when clicked under the time window (In my test it often gets 3 clicks under 0.15, lowering it makes it harder sometimes to identify if the player is double clicking) which is not how I expect it to work
You can solve this by introducing a lockout boolean. This will only allow 1 double click to be registered per lockout period. I'm assuming this is a single-player map and you don't need to worry about doing this for all players (in which case you'd need some arrays):

  • Events
    • Map Initialization
  • Conditions
  • Actions
    • Countdown Timer - Start MouseTimer as a repeating timer that will expire in 100000.00 seconds
    • Set OldTime = 0.00
  • Events
    • Player - Player 1 (Red) issues a mouse down event
  • Conditions
    • DCLockout equal to False
  • Actions
    • Set NewX = (Mouse position X for (Triggered Mouse Event))
    • Set NewY = (Mouse position Y for (Triggered Mouse Event))
    • If (All conditions are true) then do (Then actions) else do (Else actions)
      • If - Conditions
        • MouseX not equal to 0.00
        • MouseY not equal to 0.00
      • Then - Actions
        • Set NewTime = (Elapsed time for MouseTimer)
        • Set DX = (NewX - OldX)
        • Set DY = (NewY - OldY)
        • If (All conditions are true) then do (Then actions) else do (Else actions)
          • If - Conditions
            • (NewTime - OldTime) less than DOUBLE_CLICK_WINDOW
            • SquareRoot((DX x DX) + (DY x DY)) less than DISTANCE_WINDOW
          • Then - Actions
            • -------- double click happened here --------
            • Set DCLockout = True
            • Countdown Timer - Start LockoutTimer as a one-shot timer that will expire in LOCKOUT_DURATION seconds
          • Else - Actions
        • Set OldTime = NewTime
        • Set OldX = NewX
        • Set OldY = NewY
      • Else - Actions
  • Events
    • Countdown Timer - LockoutTimer expires
  • Conditions
  • Actions
    • Set DCLockout = False
 
Status
Not open for further replies.
Top