• 🏆 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!
  • 🏆 Hive's 6th HD Modeling Contest: Mechanical is now open! Design and model a mechanical creature, mechanized animal, a futuristic robotic being, or anything else your imagination can tinker with! 📅 Submissions close on June 30, 2024. Don't miss this opportunity to let your creativity shine! Enter now and show us your mechanical masterpiece! 🔗 Click here to enter!

[General] Detect player ping?

Level 22
Joined
Dec 3, 2020
Messages
535
Is there an easy way to detect a player's ping as an event? I need it for a single player map and preferably for patch 1.29.2 but if it's something 1.32+ specific then it's fine as well.
For example I want to make it so when the player pings in a certain location, all of his summoned units Attack Move to that position/coordinates.

Thanks in advance.
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,596
As far as I know...

You could detect when the user presses Alt + Left click with OSKeys + mouse events, then check their current camera position, and use that as a frame of reference. It'll probably be imprecise if you're clicking / panning the camera too often.

For the minimap, you'll probably have to use custom UI frames or some clever usage of screen coordinates to determine where that is exactly. You'll probably have to settle with the Position being off.

I came up with this so far but I can't get it to work properly:
vJASS:
library MinimapFrames initializer MinimapFrameInit

    globals
        integer frameCount = 0
        framehandle minimap
        framehandle array frames
    endglobals

    function MinimapFrameAltUp takes nothing returns nothing
        local integer i = 0
        call DisplayTextToPlayer(Player(0), 10, 0, "Alt key is up")
        loop
            // Hide the frames so they can't be used
            call BlzFrameSetVisible(frames[i], false)
            set i = i + 1
        exitwhen i == 195
        endloop
    endfunction

    function MinimapFrameAltDown takes nothing returns nothing
        local integer i = 0
        call DisplayTextToPlayer(Player(0), 10, 0, "Alt key is down")
        loop
            // Show the frames so they can be used
            call BlzFrameSetVisible(frames[i], true)
            set i = i + 1
        exitwhen i == 195
        endloop
    endfunction

    // function MinimapFrameEntered takes nothing returns nothing
    //     local player p = GetTriggerPlayer()
    //     local framehandle fh = BlzGetTriggerFrame()
    //     call DisplayTextToPlayer(Player(0), 10, 0, "Entered button!")
    // endfunction

    function MinimapFrameClicked takes nothing returns nothing
        local player p = GetTriggerPlayer()
        local framehandle fh = BlzGetTriggerFrame()
        call DisplayTextToPlayer(Player(0), 10, 0, "Pressed button!")
    endfunction

    function MinimapFrameCreate takes real x, real y returns framehandle
        local framehandle fh = BlzCreateSimpleFrame("MySimpleButton", minimap, 0)
        //local framehandle fh = BlzCreateFrameByType("GLUETEXTBUTTON", "MyScriptDialogButton", minimap, "ScriptDialogButton", 0)
        call BlzFrameSetPoint(fh, FRAMEPOINT_CENTER, minimap, FRAMEPOINT_CENTER, x, y)
        call BlzFrameSetSize(fh, 0.015, 0.015)
        call BlzFrameSetEnable(fh, false)
        call BlzFrameSetVisible(fh, false)
        set frames[frameCount] = fh
        set frameCount = frameCount + 1
        return fh
    endfunction
 
    function MinimapFrameInit takes nothing returns nothing
        local trigger t1 = CreateTrigger()
        local trigger t2 = CreateTrigger()
        local trigger t3 = CreateTrigger()
        local trigger t4 = CreateTrigger()
        local framehandle fh = null
        local real baseX = -0.075 - 0.001
        local real x = baseX
        local real y = 0.065
        local integer count = 0
        set minimap = BlzGetOriginFrame(ORIGIN_FRAME_MINIMAP, 0)
        call BlzLoadTOCFile("war3mapImported\\MySimpleButton.toc")
        call BlzTriggerRegisterPlayerKeyEvent(t3, Player(0), OSKEY_LALT, 4, true)
        call BlzTriggerRegisterPlayerKeyEvent(t4, Player(0), OSKEY_LALT, 0, false)
        call TriggerAddAction(t3, function MinimapFrameAltDown)
        call TriggerAddAction(t4, function MinimapFrameAltUp)
        loop
            if count != 0 and ModuloInteger(count, 14) == 0 then
                set x = baseX
                set y = y - 0.01
            endif
            set count = count + 1
            set x = x + 0.01
            set fh = MinimapFrameCreate(x, y)
            call BlzTriggerRegisterFrameEvent(t1, fh, FRAMEEVENT_CONTROL_CLICK)
            //call BlzTriggerRegisterFrameEvent(t2, fh, FRAMEEVENT_MOUSE_ENTER)
        exitwhen count >= 196 // 14 * 14 = 196
        endloop
 
        call DisplayTextToPlayer(Player(0), 10, 0, I2S(count) )
        call TriggerAddAction(t1, function MinimapFrameClicked)
        //call TriggerAddAction(t2, function MinimapFrameEntered)
        set t1 = null
        set t2 = null
        set t3 = null
        set t4 = null
        set fh = null
    endfunction
 
endlibrary
It fills the Minimap with tiny button frames that you can click/mouse over. The issue is that they prevent you from using the Minimap since they take "mouse priority". I tried fixing it but couldn't find a good solution. In it's current form I am trying to detect when the Left Alt key is pressed and Show the frames only then (they're normally hidden). A hidden frame won't take mouse priority so the idea was to only have them active when you were trying to ping. I guess from here you could try to detect when the Player left clicks their mouse, determine if they're moused over a UI frame, and simulate the ping (or somehow get a real one to fire). If you can get that working you'll then need some logic to convert the frame you clicked into world x/y coordinates, of course this will lack precision since there's only 196 buttons being used to represent your entire map (so basically divide your map into a 14x14 grid and link each nodes center x/y coordinates to the corresponding frame button). You may be able to shrink the buttons and create more of them for better precision.
 
Last edited:
Level 22
Joined
Dec 3, 2020
Messages
535
Woah that's a lot to take in!

I shall try the initial method. Worst case scenario I can use an edited Far Sight ability that I add to the player's Town Halls.
Although my initial idea was for the player to not have to use a unit/structure but I might as well do that.
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,596
Woah that's a lot to take in!

I shall try the initial method. Worst case scenario I can use an edited Far Sight ability that I add to the player's Town Halls.
Although my initial idea was for the player to not have to use a unit/structure but I might as well do that.
Alright, I got it working nicely :D See attached map below (requires latest patch to open).

You can Control + Left click anywhere on the Minimap and the system will respond by setting variables and running a trigger of your choosing:
  • Minimap Frames Setup
    • Events
      • Time - Elapsed game time is 0.00 seconds
    • Conditions
    • Actions
      • -------- The trigger that runs when you control + click the minimap: --------
      • Set VariableSet MinimapFramesTrigger = Demo Attack <gen>
Here are the variables that you would use inside of your MinimapFramesTrigger:

MinimapFramesPlayer = The Player that clicked the minimap.
MinimapFramesX[] = The X coordinate of where you clicked (a close estimate). You must use their Player Number as the [index].
MinimapFramesY[] = The Y coordinate of where you clicked (a close estimate). You must use their Player Number as the [index].
  • Demo Attack
    • Events
    • Conditions
    • Actions
      • Set VariableSet PlayerId = (Player number of MinimapFramesPlayer)
      • Set VariableSet TempPoint = (Point(MinimapFramesX[PlayerId], MinimapFramesY[PlayerId]))
      • -------- --------
      • Cinematic - Ping minimap for (All players) at TempPoint for 1.00 seconds, using a Simple ping of color (0.00%, 100.00%, 0.00%)
      • Game - Display to (All players) for 30.00 seconds the text: (Attack towards coordinates: + ((String(MinimapFramesX[PlayerId])) + ( / + (String(MinimapFramesY[PlayerId])))))
      • -------- --------
      • Custom script: set bj_wantDestroyGroup = true
      • Unit Group - Pick every unit in (Units owned by MinimapFramesPlayer.) and do (Actions)
        • Loop - Actions
          • Unit - Order (Picked unit) to Attack-Move To TempPoint
      • -------- --------
      • Custom script: call RemoveLocation( udg_TempPoint )
^ This is my example trigger which runs whenever you Control + Left click the Minimap. It orders all of the clicking Player's units to attack to wherever you clicked. Note that I've set it up to only work for a square map, which means that your Map's Width/Height values must be the same number:

map xy size.png


Also, you MUST tell the system your map's size in the code. Change 64 to whatever your Width/Height is:
vJASS:
// DEFINE THIS:
integer your_map_size = 64     // 64 x 64

Here's the code if you need to build this yourself:
vJASS:
library MinimapFrames initializer MinimapFrameInit
    globals
        // DEFINE THIS:
        integer your_map_size = 64      // 64 x 64

        // DON'T EDIT:
        framehandle array frames
        boolean array key_is_down
        real array map_x
        real array map_y
        framehandle minimap
        integer frame_count = 0
        real original_offset = 0.01
        real original_size = 0.015
        real new_offset
        real new_size
        real top_left_corner_x
        real map_offset
    endglobals

    function MinimapFrameKeyUp takes nothing returns nothing
        local player p = GetTriggerPlayer()
        local integer id = GetPlayerId(p)
        local integer i = 0
        set key_is_down[id] = false
        //call DisplayTextToPlayer(Player(0), 0, 0, "Left Control key is up")
        loop
            // Hide the frames so they can't be used
            if (GetLocalPlayer() == p) then
                call BlzFrameSetVisible(frames[i], false)
            endif
            set i = i + 1
        exitwhen i == frame_count
        endloop
        set p = null
    endfunction

    function MinimapFrameKeyDown takes nothing returns nothing
        local player p = GetTriggerPlayer()
        local integer id = GetPlayerId(p)
        local integer i = 0
        // This will keep running so let's avoid repeats
        if key_is_down[id] then
            set p = null
            return
        endif
        set key_is_down[id] = true
        //call DisplayTextToPlayer(Player(0), 0, 0, "Left Control key is down")
        loop
            // Show the frames so they can be used
            if (GetLocalPlayer() == p) then
                call BlzFrameSetVisible(frames[i], true)
            endif
            set i = i + 1
        exitwhen i == frame_count
        endloop
        set p = null
    endfunction

    function MinimapFrameClicked takes nothing returns nothing
        local player p = GetTriggerPlayer()
        local integer id = GetConvertedPlayerId(p)
        local framehandle fh = BlzGetTriggerFrame()
        local integer index = S2I(BlzFrameGetText(fh))
        //call DisplayTextToPlayer(Player(0), 0, 0, "Pressed button: " + I2S(index))
        ///////////////////////////////////////////
        // This is all GUI stuff (optional)
        set udg_MinimapFramesPlayer = p
        set udg_MinimapFramesX[id] = map_x[index]
        set udg_MinimapFramesY[id] = map_y[index]
        call TriggerExecute(udg_MinimapFramesTrigger)
        ///////////////////////////////////////////
        call BlzFrameSetEnable(fh, false)
        call BlzFrameSetEnable(fh, true)
   
        set p = null
        set fh = null
    endfunction

    function MinimapFrameCreate takes real x, real y returns framehandle
        //local framehandle fh = BlzCreateSimpleFrame("MySimpleButton", minimap, 0)
        local framehandle fh = BlzCreateFrameByType("GLUETEXTBUTTON", "MyScriptDialogButton", minimap, "ScriptDialogButton", 0)
        call BlzFrameSetPoint(fh, FRAMEPOINT_CENTER, minimap, FRAMEPOINT_CENTER, x, y)
        call BlzFrameSetSize(fh, new_size, new_size)
        //call BlzFrameSetEnable(fh, false)
        call BlzFrameSetVisible(fh, false)
        call BlzFrameSetAlpha(fh, 0)
        set frame_count = frame_count + 1
        call BlzFrameSetText(fh, I2S(frame_count))
        set frames[frame_count] = fh
        return fh
    endfunction
 
    function MinimapFrameInit takes nothing returns nothing
        local trigger t1 = CreateTrigger()
        local trigger t2 = CreateTrigger()
        local trigger t3 = CreateTrigger()
        local framehandle fh = null
        local integer count = 0
        local real baseX = -0.075 - 0.001
        local real x = baseX
        local real y = 0.065
        local real y_offset = 0.01 * (14.0 / 16.0)
        local integer width = 16
        local integer total = width * width
        local integer x2 = 0
        local integer y2 = 1
        set new_offset = original_offset * (14.0 / 16.0)
        set new_size = original_size * (14.0 / 16.0)
        set top_left_corner_x = (your_map_size * 64) * -1
        set map_offset = your_map_size * 8
   
        //call DisplayTextToPlayer(Player(0), 10, 0, "map_offset " + R2S(map_offset) )
        //call DisplayTextToPlayer(Player(0), 10, 0, "top_left_corner_x " + R2S(top_left_corner_x) )
        //call DisplayTextToPlayer(Player(0), 10, 0, "top_left_corner_y " + R2S(top_left_corner_y) )
        //call DisplayTextToPlayer(Player(0), 10, 0, "width " + I2S(width) )
        //call DisplayTextToPlayer(Player(0), 10, 0, "total " + I2S(total) )
        //call DisplayTextToPlayer(Player(0), 10, 0, "new_offset " + R2S(new_offset) )
        //call DisplayTextToPlayer(Player(0), 10, 0, "new_size " + R2S(new_size) )
   
        set minimap = BlzGetOriginFrame(ORIGIN_FRAME_MINIMAP, 0)
        //call BlzLoadTOCFile("war3mapImported\\MySimpleButton.toc")
   
        call BlzTriggerRegisterPlayerKeyEvent(t2, Player(0), OSKEY_LCONTROL, 2, true)
        call BlzTriggerRegisterPlayerKeyEvent(t3, Player(0), OSKEY_LCONTROL, 0, false)
        call TriggerAddAction(t2, function MinimapFrameKeyDown)
        call TriggerAddAction(t3, function MinimapFrameKeyUp)
   
        loop
       
            if count != 0 and ModuloInteger(count, width) == 0 then
                set x = baseX
                set y = y - y_offset
                set y2 = y2 + 1
                set x2 = 0
            endif
            set count = count + 1
            set x2 = x2 + 1
            set x = x + new_offset
            set fh = MinimapFrameCreate(x, y)
            call BlzTriggerRegisterFrameEvent(t1, fh, FRAMEEVENT_CONTROL_CLICK)
            // Calculate the map x/y coordinates (frame_count is the same as count)
            set map_x[count] = (top_left_corner_x + (map_offset * x2)) - (map_offset / 2)
            set map_y[count] = ((top_left_corner_x * -1) - (map_offset * y2)) + (map_offset / 2)
       
            exitwhen count > total // 16 * 16 = 256
        endloop
   
        call TriggerAddAction(t1, function MinimapFrameClicked)
   
        set t1 = null
        set t2 = null
        set t3 = null
        set fh = null
    endfunction
 
endlibrary
 

Attachments

  • Minimap Position Detection.w3m
    22.9 KB · Views: 2
Last edited:

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,596
Thank you, I shall test this very soon!
So from what I read, it only works for the minimap pings.
I guess that's fine :gg:
Here's an updated map with the Ping working on the game world. It still uses Control + Left click for the Minimap since I had to use a special system to make that work and it's very limited.

Here's the new trigger for ordering your units to Attack towards wherever you Ping on the game world:
  • Demo Attack World
    • Events
      • Player - Player 1 (Red) issues Mouse Down event
    • Conditions
      • (Trigger Mouse Button) Equal to Left Mouse Button
    • Actions
      • Set VariableSet MinimapFramesPlayer = (Triggering player)
      • Set VariableSet PlayerId = (Player number of MinimapFramesPlayer)
      • -------- --------
      • -------- This custom script checks if you're pressing the Alt key. --------
      • -------- You can edit it to use the control key instead: if control_key_is_down --------
      • Custom script: if alt_key_is_down[udg_PlayerId] then
      • -------- --------
      • Set VariableSet MouseX = (Mouse Position X for Triggered Mouse Event)
      • Set VariableSet MouseY = (Mouse Position Y for Triggered Mouse Event)
      • Set VariableSet TempPoint = (Point(MouseX, MouseY))
      • -------- --------
      • Game - Display to (All players) for 30.00 seconds the text: (Attack towards coordinates: + ((String(MouseX)) + ( / + (String(MouseY)))))
      • -------- --------
      • Custom script: set bj_wantDestroyGroup = true
      • Unit Group - Pick every unit in (Units owned by MinimapFramesPlayer.) and do (Actions)
        • Loop - Actions
          • Unit - Order (Picked unit) to Attack-Move To TempPoint
      • -------- --------
      • Custom script: call RemoveLocation( udg_TempPoint )
      • -------- --------
      • Custom script: endif
Again, this trigger does NOT work for the Minimap, you need to rely on Control + Left click for that. Also, make sure to add all of your Players to the Events.
 

Attachments

  • Minimap Frames Custom Ping 1.w3m
    24.3 KB · Views: 2
Last edited:
Top