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

Trackables System [GUI Friendly] v1.10

  • Like
Reactions: Callahan and ILH
Preview GIFs

151092d1450409907-gui-friendly-trackables-system-v1-00-trackable-system.gif



JASS:
//          Trackables System [GUI Friendly] v1.10
//                    by Flux
//     http://www.hiveworkshop.com/forums/members/flux/

//  A trackables system which is easy to use for GUI users.
//  It allows users to detect when a certain player hovers
//  or clicks (using the mouse) on an area within a Region
//  (which is actually a rect in JASS).

//  NOTE:
//   - This system cost 1 hashtable.
//   - TRK_Players (force) is automatically destroyed so it is
//     highly advised to not set TRK_Players to an existing Player
//     group, but instead, create a new one (as shown in the demo).
//   - TRK_Point (location) must not be removed or overwritten.

//  HOW TO IMPORT:
//  1. Copy the Trackables System Variable Creator in your map.
//     Make sure you set the "Automatically create unknown variables
//     while pasting trigger data" in Files -> Preferences.
//     After copying, delete Trackables System Variable Creator
//  2. Copy Trackables System to your map.

//  HOW TO USE:
//  1. Set 'TRK_Players'. The Players in this PlayerGroup are the ones 
//     who can interact with the trackables about to be created.
//     The Player Group is automatically destroyed so you don't need
//     to manually destroy 'TRK_Players'
//  2. Set 'TRK_Rect' which refers to the rect where the trackables
//     will be created. Rects are called Regions in GUI.
//  3. Set 'TRK_HoverTrigger' which refers to the trigger that will run when
//     a player in TRK_Players hovers a trackable in the 'TRK_Region'.
//  4. Set 'TRK_ClickTrigger' which refers to the trigger that will run when
//     a player in TRK_Players clicks a trackable in the 'TRK_Region'.
//  5. Set 'TRK_Spacing' which refers to the spacing between trackables.
//  6. Set 'TRK_ModelPath' which determines how the trackables will look
//     in game.
//  7. Run the system using:
//     'Trigger - Run Trackables System <gen> (checking conditions)'
//  8. In your trackables event triggers, TRK_Point refers to the location
//     of the trackables that was clicked/hovered and TRK_TriggeringPlayer
//     is the player that interacted with the trackable. Note that you cannot
//     use TRK_Point and TRK_TriggeringPlayer in the Conditions so you have
//     to create a big IF-THEN-ELSE if your condition involves TRK_Point
//     or TRK_TriggeringPlayer
//  9. Do your actions


function Trig_Trackables_System_InitVariables takes nothing returns boolean
    local integer id = LoadInteger(udg_TRK_Hashtable, GetHandleId(GetTriggeringTrackable()), 0)
    call MoveLocation(udg_TRK_Point, udg_TRK_TrackableX[id], udg_TRK_TrackableY[id])
    set udg_TRK_TriggeringPlayer = udg_TRK_TrackableOwner[id]
    return true
endfunction

function Trig_Trackables_System_PickPlayers takes nothing returns nothing
    local string s = ""
    local trackable t
    set udg_TRK_TrackableOwner[udg_TRK_Index] = GetEnumPlayer()
    if GetPlayerSlotState(udg_TRK_TrackableOwner[udg_TRK_Index]) == PLAYER_SLOT_STATE_PLAYING and GetPlayerController(udg_TRK_TrackableOwner[udg_TRK_Index]) == MAP_CONTROL_USER then
        //Trackable Properties
        set udg_TRK_TrackableX[udg_TRK_Index] = udg_TRK_x
        set udg_TRK_TrackableY[udg_TRK_Index] = udg_TRK_y
        if GetLocalPlayer() == udg_TRK_TrackableOwner[udg_TRK_Index] then
            set s = udg_TRK_ModelPath
        endif
        set t = CreateTrackable(s, udg_TRK_x, udg_TRK_y, 0)
        //Save index
        call SaveInteger(udg_TRK_Hashtable, GetHandleId(t), 0, udg_TRK_Index)
        //Register the trackable
        if udg_TRK_HoverTrigger != null then
            call TriggerRegisterTrackableTrackEvent(udg_TRK_HoverTrigger, t)
        endif
        if udg_TRK_ClickTrigger != null then
            call TriggerRegisterTrackableHitEvent(udg_TRK_ClickTrigger, t)
        endif
        set udg_TRK_Index = udg_TRK_Index + 1
    endif
endfunction

function Trig_Trackables_System_Main takes nothing returns boolean
    local real xmax = GetRectMaxX(udg_TRK_Rect)
    local real xmin = GetRectMinX(udg_TRK_Rect)
    local real ymax = GetRectMaxY(udg_TRK_Rect)
    set udg_TRK_y = GetRectMinY(udg_TRK_Rect)
    if udg_TRK_HoverTrigger != null then
        call TriggerAddCondition(udg_TRK_HoverTrigger , Condition(function Trig_Trackables_System_InitVariables))
    endif
    if udg_TRK_ClickTrigger != null then
        call TriggerAddCondition(udg_TRK_ClickTrigger , Condition(function Trig_Trackables_System_InitVariables))
    endif
    loop
        exitwhen udg_TRK_y >= ymax
        set udg_TRK_x = xmin
        loop
            exitwhen udg_TRK_x >= xmax
            //Create Trackable for each player
            call ForForce(udg_TRK_Players, function Trig_Trackables_System_PickPlayers)
            set udg_TRK_x = udg_TRK_x + udg_TRK_Spacing
        endloop
        set udg_TRK_y = udg_TRK_y + udg_TRK_Spacing
    endloop
    if udg_TRK_Players != bj_FORCE_ALL_PLAYERS then
        call DestroyForce(udg_TRK_Players)
    endif
    set udg_TRK_HoverTrigger = null
    set udg_TRK_ClickTrigger = null
    return false
endfunction

//===========================================================================
function InitTrig_Trackables_System takes nothing returns nothing
    set gg_trg_Trackables_System = CreateTrigger()
    set udg_TRK_Hashtable = InitHashtable()
    set udg_TRK_Point = Location(0, 0)
    set udg_TRK_Index = 0
    call TriggerAddCondition(gg_trg_Trackables_System, Condition(function Trig_Trackables_System_Main))
endfunction

Using the System

  • Create Trackables Demo 1
    • Events
      • Player - Player 1 (Red) types a chat message containing 1 as An exact match
    • Conditions
    • Actions
      • Game - Display to (All players) the text: Demo 1 enabled!
      • -------- ----------------------------------------------------------------- --------
      • -------- ---------- Set the configurations --------------- --------
      • -------- ----------------------------------------------------------------- --------
      • -------- Player Group that can interact with the Trackable --------
      • Set TRK_Players = (Player group(Player 1 (Red)))
      • -------- Select the Region where Trackables will be created --------
      • Set TRK_Rect = Region 000 <gen>
      • -------- Select the trigger that will run when the mouse hovers the trackables --------
      • Set TRK_HoverTrigger = Demo 1 on Hover <gen>
      • -------- Select the trigger that will run when the mouse clicks the trackables --------
      • Set TRK_ClickTrigger = Demo 1 on Click <gen>
      • -------- Set the spacing between trackables --------
      • Set TRK_Spacing = 128.00
      • -------- Set the model path of trackables --------
      • Set TRK_ModelPath = Doodads\Terrain\InvisiblePlatform\InvisiblePlatform.mdl
      • -------- Run the System --------
      • Trigger - Run Trackables System <gen> (checking conditions)



  • Demo 1 on Hover
    • Events
    • Conditions
    • Actions
      • -------- Your Actions Here --------
      • Unit - Make Tinker 0000 <gen> face TRK_Point over 0.00 seconds



  • Demo 1 on Click
    • Events
    • Conditions
    • Actions
      • -------- Your Actions Here --------
      • Unit - Order Tinker 0000 <gen> to Move To TRK_Point



  • Demo 2 on Hover
    • Events
    • Conditions
    • Actions
      • -------- Your Actions Here --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • TRK_TriggeringPlayer Equal to Player 1 (Red)
        • Then - Actions
          • Unit - Move Wisp 0004 <gen> instantly to TRK_Point
        • Else - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • TRK_TriggeringPlayer Equal to Player 2 (Blue)
            • Then - Actions
              • Unit - Move Wisp 0005 <gen> instantly to TRK_Point
            • Else - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • TRK_TriggeringPlayer Equal to Player 3 (Teal)
                • Then - Actions
                  • Unit - Move Wisp 0006 <gen> instantly to TRK_Point
                • Else - Actions


Changelog:
v1.00 - [17 December 2015]
- Initial Release

v1.01 - [18 December 2015]
- Fixed a minor mistake in TriggerAddCondition. It now fully works without needing Jass New Gen Pack.

v1.02 - [8 January 2016]
- Custom scripts no longer needed!
- System will check first if the player is a user before creating the trackable for that player.
- Trackables' center will no longer exceed the specified rect boundary.
- Changed the variable name to 'TRK_Rect' since it is actually a rect but called Region in GUI.

v1.03 - [3 April 2016 ]
- TRK_Point no longer needs to be removed through Custom script.
- Fixed some typo.

v1.10 - [1 January 2017]
- Fixed a possible bug when too many trackables are used.
- Fixed unintentional resetting of TRK_Index resulting to a bug.


Keywords:
trackable, track, GUI friendly, mouse, click, hover, mouse move, mouse interact
Contents

Trackable System [GUI Friendly] v1.1 (Map)

Reviews
08:51, 18th Dec 2015 Bribe: Well-made with no issues which I can identify. 3.7/5. Please see the Track resource, http://www.hiveworkshop.com/forums/jass-resources-412/system-track-205760/ for perhaps adding a check when it's FORCE_ALL_PLAYERS that...

Moderator

M

Moderator

08:51, 18th Dec 2015
Bribe: Well-made with no issues which I can identify. 3.7/5. Please see the Track resource, http://www.hiveworkshop.com/forums/jass-resources-412/system-track-205760/ for perhaps adding a check when it's FORCE_ALL_PLAYERS that the player is actually playing.
 
Cool. A system written in plain JASS is useful.

Imo "region" should be replaced by "rect", in description and in code.
Vanilla JASS user might also use it, and it's anways fairly simple to
learn for GUI users that "Regions" in GUI is actually a rect.
It should be not exclusivly for GUI.

udg_TRK_y > ymax
->
udg_TRK_y >= ymax

exitwhen udg_TRK_x > xmax
->
exitwhen udg_TRK_x >= xmax

And no destroy is supported.
 
Level 22
Joined
Feb 6, 2014
Messages
2,466
Cool. A system written in plain JASS is useful.

Imo "region" should be replaced by "rect", in description and in code.
Vanilla JASS user might also use it, and it's anways fairly simple to
learn for GUI users that "Regions" in GUI is actually a rect.
It should be not exclusivly for GUI.
Okay I understand, I will just put "regions" in GUI are actually "rect" somewhere in the documentation.

udg_TRK_y > ymax
->
udg_TRK_y >= ymax

exitwhen udg_TRK_x > xmax
->
exitwhen udg_TRK_x >= xmax
Why? it won't create a trackable at the edge if I did this since it will exit the loop immediately if it the x and y happens to be at the edge of the rect.

And no destroy is supported.
Trackables can't be destroyed ;). If the user ever want to, they can disable the onHover and onClick triggers.
 
Level 22
Joined
Feb 6, 2014
Messages
2,466
Yes, you're right. But indices can be recycled so they can be used again.
You're right, but I don't think anyone will reach the limit because if they do, they also have 8190 trackables in the map.

And for the ">=", from my point of view, I would not want to have
trackables (partialy) outside my rect, but prefer to have a little "buffer" instead.
I myself would even use the size of trackable in the "exitwhen" condition.
But you can let it imo if you like it.
Good point, I would consider the trackable size if it can be detected.
But yeah, "I would not want to have trackables (partialy) outside my rect" make sense. I will change it.
 
Level 22
Joined
Feb 6, 2014
Messages
2,466
Totally forgot to update this, but I remember when I saw the GUITrack from another user.

So, updated to v1.02.
Changes:
- Custom scripts no longer needed!
- System will check first if the player is a user before creating the trackable for that player.
- Trackables' center will no longer touch the edge of the specified rect.
- Changed the variable name to 'TRK_Rect' since it is actually a rect but called Region in GUI.
 
Last edited:

sentrywiz

S

sentrywiz

Just curious, would this system lag in let's say: 128x64 map for multiple players?
 
This is amazing. It has great documentation and is easy enough to understand that even I can use it. Great work!!! I have a few questions though. Can you detect left-click from right-click? Smart already works for right, but I want a different action on left.

Also, it's great for moving a unit or activating a spell targeting a point, but how do I make it select a unit. Say, I hoover over a unit and I want it to have a floating text that says "Hi." How would that work? I could pick units within 50 of TRK_Point but that seems a bit sloppy. Could you write a quick example of how that might work? How can I enable the smart order again? Seems this system overwrites it. Which makes sense for something but not for others.

Sorry for being so naive. This system is really cool and I think that with such easy use many people will be able to use it even if they don't understand how it works. The more demos the better. 5/5 +rep
 
Last edited:
Is the unit that would say "Hi" moving?

It might be. I made it work with pick all unit within 127 of TRK_Point, but it seemed slow and not super responsive. It would get the units though and could probably be optimized with the right range.

I think you can't detect right-click but I haven't tested it.

Well, if you can detect left-click (smart), then can't you get right-click by process of elimination? I guess that doesn't work when you have no unit selected since there is no order issued, but for my purposes and for many other's, having it only do an action when a unit is selected is most likely what we want anyway. What I'm looking for is a duel attack functionality like Diablo II that fires one attack with right click and a different one with left. It seems like this system can do that, but I'm short on know how.

This system does not overwrite the smart order, it is just a demo. The main functionality is creating trackables in a rect and defining the hover and onClick triggers.

Can you add a demo that does something else then so the smart order is not interrupted? For example, the trackable click creates a special effect. I disabled the onClick demo trigger and I was still unable to move any units. It would just be nice to see more demos.

Either way, I meant what I said. This is a very advanced system and you have made it very accessible to those of us with less than advanced triggering skills. Sadly, I can't get Bribe's KB2D to work for warstomp. So seeing a system that is way more advanced be presented in such an easy to use fashion, is really amazing! Thank you. I will have fun with this!
 
Level 22
Joined
Feb 6, 2014
Messages
2,466
Unfortunately, I don't know how to apply it for moving units efficiently because trackables can't be moved. But for non-moving let's say NPCs, you can create a small rect (region) where the NPC is located and create an onHover trigger there.

The reason you still can't order Tinker (in demo) is probably because of the onHover trigger. It forces Tinker to face where the mouse cursor is, stopping current orders.
 
Level 3
Joined
Oct 6, 2015
Messages
10
this system cant be used on multiplayer since i cant detect the point for specific player like TRK_Point[( GetConvertedPlayerId(udg_TRK_TriggeringPlayer())] ..... each time i try to make it an array , it doesnt work on multiplayer.... I have tested it with my friend me and my friend if we keep clicking fast me and him walk to the same point... is there anyway to fix this?
Thank you for Taking Time Reading this.
 
Level 22
Joined
Feb 6, 2014
Messages
2,466
Uhm TRK_Point isn't an array. You could try doing something like this for specific player clicks
  • Demo 2 on Hover
    • Events
    • Conditions
    • Actions
      • -------- Your Actions Here --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • TRK_TriggeringPlayer Equal to Player 1 (Red)
        • Then - Actions
          • Unit - Move Wisp 0004 <gen> instantly to TRK_Point
        • Else - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • TRK_TriggeringPlayer Equal to Player 2 (Blue)
            • Then - Actions
              • Unit - Move Wisp 0005 <gen> instantly to TRK_Point
            • Else - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • TRK_TriggeringPlayer Equal to Player 3 (Teal)
                • Then - Actions
                  • Unit - Move Wisp 0006 <gen> instantly to TRK_Point
                • Else - Actions
 
Level 3
Joined
Oct 6, 2015
Messages
10
Uhm TRK_Point isn't an array. You could try doing something like this for specific player clicks
  • Demo 2 on Hover
    • Events
    • Conditions
    • Actions
      • -------- Your Actions Here --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • TRK_TriggeringPlayer Equal to Player 1 (Red)
        • Then - Actions
          • Unit - Move Wisp 0004 <gen> instantly to TRK_Point
        • Else - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • TRK_TriggeringPlayer Equal to Player 2 (Blue)
            • Then - Actions
              • Unit - Move Wisp 0005 <gen> instantly to TRK_Point
            • Else - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • TRK_TriggeringPlayer Equal to Player 3 (Teal)
                • Then - Actions
                  • Unit - Move Wisp 0006 <gen> instantly to TRK_Point
                • Else - Actions
yea i did try this before you say , but this method also did not work :(, it works great and perfectly with single but with multiplayer the point is the same for everybody cant make it specifically.
and , it's like when someone clicks it's good , but when 2 or more clicks in the same time the point will be displayed for both player in the same point .
 
Last edited:
Level 22
Joined
Feb 6, 2014
Messages
2,466
I'll check it out.

EDIT: Updated. Turns out there was some mispositioned function calls happening.

A new triggercondition is created every trackable instead of every system execution therefore when there's too many trackables (or players), some triggercondition may not be added to the onHover or onClick trigger.
This sort of things happen when the author himself does not use the resource he submitted because I'm using this
 
Last edited:
Top