1. Are you planning to upload your awesome spell or system to Hive? Please review the rules here.
    Dismiss Notice
  2. The Aftermath has been revealed for the 19th Terraining Contest! Be sure to check out the Results and see what came out of it.
    Dismiss Notice
  3. Melee Mapping Contest #3 - Results are out! Congratulate the winners and check plenty of new 4v4 melee maps designed for this competition!
    Dismiss Notice
  4. The winners of our cinematic soundtrack competition have been decided! Step by the Music Contest #11 - Results to check the entries and congratulate the winners!
    Dismiss Notice

Number Key Press Event v1.3

Submitted by Quilnez
This bundle is marked as approved. It works and satisfies the submission rules.
Allows you to perform actions when a player presses any number key (0-9). Can be useful in RPG or AOS maps. Still, there are some constrains in using this, read them in the documentation.

Code (vJASS):

library NumberKeyEvent initializer init
   
                        // Configurations
    globals
        // Key detector dummy's raw code in OE
        private constant integer DUMMY_ID   = 'h000'
       
        // Location of dummy, better to be a permanently
        // invisible spot in your map
        private constant real    DUMMY_X    = 2521.32
        private constant real    DUMMY_Y    = -2827.15
       
        // If true, system will use periodical check
        // results in more instaneous press event
        private constant boolean USE_TIMER  = true
        private constant real    CHECK_RATE = 0.01
    endglobals
   
    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
    *
    *                   NumberKeyEvent v1.3
    *                   ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
    *
    *       Description
    *       ¯¯¯¯¯¯¯¯¯¯¯
    *           Allows you to do actions when a player presses
    *           any number key (0-9)
    *
    *       Cons
    *       ¯¯¯¯
    *           - Needs calibration (check demo)
    *           - Disturbs unit selection
    *
    *       Requirement
    *       ¯¯¯¯¯¯¯¯¯¯¯
    *           -
    *
    *       How to import
    *       ¯¯¯¯¯¯¯¯¯¯¯¯¯
    *           - Copy KeyDetectorDummy unit from object editor to your map
    *           - Copy the trigger folder to your map
    *           - Configure the system accordingly
    *      
    *       API
    *       ¯¯¯
    *           function CalibrateNumberKeys takes integer playerId returns nothing
    *           function GetPressedNumberKey takes nothing returns integer
    *           function GetPressingPlayer   takes nothing returns player
    *           function RegisterAnyNumberKeyEvent   takes boolexpr func returns triggercondition
    *           function UnregisterAnyNumberKeyEvent takes triggercondition tc returns nothing
    *
    *       Notes
    *       ¯¯¯¯¯
    *           - Better to preserve an invisible area for dummy
    *             units to avoid unwanted camera panning
    *           - Player must be pressing CTRL when CalibrateNumberKeys
    *             function is called
    *           - You must allow players to calibrate their keys
    *             anytime whenever they want, in case the calibration
    *             is failed or broken
    *           - By using this system players are no longer supposed
    *             to use the control group shortcut keys: CTRL+(0-9).
    *             Because it will break the calibration. Warn them.
    *
    * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

   
    globals
        private unit    array KeyUnit
        private boolean array IsCalibrated
        private boolean array IsRegistered
        private trigger Handler = CreateTrigger()
        private integer EventPressed = -1
        private player  EventPresser = null
        private player  Locale
        private timer   Timer = null
    endglobals
   
    private function onSelection takes nothing returns boolean
       
        static if USE_TIMER then
            local integer i = 0
            local integer j
            local integer k
            local player  p
           
            loop
                exitwhen i > 11
                if IsCalibrated[i] then
                    set p = Player(i)
                    set j = 0
                    loop
                        exitwhen j > 9
                        set k = i*10+j
                        if IsUnitSelected(KeyUnit[k], p) then
                            if Locale == p then
                                call ClearSelection()
                            endif
                            set EventPresser = p
                            set EventPressed = j
                            call TriggerEvaluate(Handler)
                            set EventPressed = -1
                            set EventPresser = null
                        endif
                        set j = j + 1
                    endloop
                endif
                set i = i + 1
            endloop
        else
            local unit    u  = GetTriggerUnit()
            local player  p  = GetOwningPlayer(u)
            local integer id = GetPlayerId(p)
            local integer dt = GetUnitUserData(u)
           
            if Locale == p then
                call ClearSelection()
            endif
            if IsCalibrated[id] then
                set EventPresser = p
                set EventPressed = dt
                call TriggerEvaluate(Handler)
                set EventPressed = -1
                set EventPresser = null
            elseif dt == 9 then
                set IsCalibrated[id] = true
            endif
            set u = null
        endif
       
        return false
    endfunction
   
    function CalibrateNumberKeys takes integer playerId returns nothing
       
        local integer i
       
        if IsRegistered[playerId] then
            set IsCalibrated[playerId] = true
            if Locale == Player(playerId) then
                call ClearSelection()
                set i = 0
                loop
                    exitwhen i > 9
                    call SelectUnit(KeyUnit[playerId*10+i], true)
                    call ForceUIKey(I2S(i))
                    call SelectUnit(KeyUnit[playerId*10+i], false)
                    set i = i + 1
                endloop
            endif
        endif
       
        static if USE_TIMER then
            if Timer == null then
                set Timer = CreateTimer()
                call TimerStart(Timer, CHECK_RATE, true, function onSelection)
            endif
        endif
       
    endfunction
   
    function GetPressedNumberKey takes nothing returns integer
        return EventPressed
    endfunction
   
    function GetPressingPlayer takes nothing returns player
        return EventPresser
    endfunction
   
    function RegisterAnyNumberKeyEvent takes boolexpr func returns triggercondition
        return TriggerAddCondition(Handler, func)
    endfunction
   
    function UnregisterAnyNumberKeyEvent takes triggercondition tc returns nothing
        call TriggerRemoveCondition(Handler, tc)
    endfunction
   
    private function init takes nothing returns nothing
       
        local integer i = 0
        local integer j
        local integer k
        local player  p
        static if not USE_TIMER then
            local trigger t = CreateTrigger()
            call TriggerAddCondition(t, Condition(function onSelection))
        endif
       
        set Locale = GetLocalPlayer()
        loop
            exitwhen i > 11
            set p = Player(i)
            set IsRegistered[i] = GetPlayerController(p) == MAP_CONTROL_USER and GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING
            if IsRegistered[i] then
                set j = 0
                loop
                    exitwhen j > 9
                    set k = i*10+j
                    set KeyUnit[k] = CreateUnit(p, DUMMY_ID, DUMMY_X, DUMMY_Y, 0)
                    static if not USE_TIMER then
                        call TriggerRegisterUnitEvent(t, KeyUnit[k], EVENT_UNIT_SELECTED)
                        call SetUnitUserData(KeyUnit[k], j)
                    endif
                    call SetUnitX(KeyUnit[k], DUMMY_X)
                    call SetUnitY(KeyUnit[k], DUMMY_Y)
                    call PauseUnit(KeyUnit[k], true)
                    set j = j + 1
                endloop
            endif
            set i = i + 1
        endloop
       
    endfunction
   
endlibrary
 

Keywords:
keyboard, number, key, press, event
Contents

Number Key Event (Map)

Reviews
Moderator
Number Key Press Event v1.1 | Reviewed by BPower | 28.06.2015 Concept[/COLOR]] [IMG]Fires an event when a control group is selected. Allows users to register code to this event. @Map-makers: Make sure to guid players properly throught the...
  1. Number Key Press Event v1.1 | Reviewed by BPower | 28.06.2015
    • Concept[/COLOR]]
      [​IMG] Fires an event when a control group is selected.
      Allows users to register code to this event.

      @Map-makers: Make sure to guid players properly
      throught the calibration process.

      Great idea!
    • Code[/COLOR]]
      [​IMG]
      • System is MUI, leakless and seems to work.
      • Players may overwrite their control groups,
        in this case the system does nothing and the player
        has to do the calibration again.
      [​IMG]
      • Remove the keyword.
      • Sticking to the JPAG is recommended
      • Table and TimerUtils could be good dependencies.
    • Demo[/COLOR]]
      [​IMG]
      • The demo is well done.
    • Rating[/COLOR]]
      CONCEPT CODE DEMO RATING STATUS
      5/5
      3/5
      4/5
      4/5
      APPROVED

    • Links[/COLOR]]
      [​IMG]
      • TimerUtils could be useful, as it recycles the timer.
      • Table is definetly a win.
    [/td]
     
  2. BPower

    BPower

    Joined:
    Mar 18, 2012
    Messages:
    1,745
    Resources:
    21
    Spells:
    15
    Tutorials:
    1
    JASS:
    5
    Resources:
    21
    What is a good time value for StartCalibration?

    Can paused units be selected via UIKey? If so pause all dummies.

    JPAG
     
  3. Quilnez

    Quilnez

    Joined:
    Oct 12, 2011
    Messages:
    3,169
    Resources:
    37
    Icons:
    2
    Tools:
    1
    Maps:
    7
    Spells:
    21
    Tutorials:
    2
    JASS:
    4
    Resources:
    37
    Depends on user.

    Does that make any difference?

    Don't care
     
  4. Almia

    Almia

    Joined:
    Apr 24, 2012
    Messages:
    4,839
    Resources:
    35
    Spells:
    30
    Tutorials:
    4
    JASS:
    1
    Resources:
    35
    We care dumbo.

    btw i love this, we should really compile all of our keyboard events, but i am still waiting for the Tab key Event which should be possible(through some h4xx lol jk)
     
  5. Quilnez

    Quilnez

    Joined:
    Oct 12, 2011
    Messages:
    3,169
    Resources:
    37
    Icons:
    2
    Tools:
    1
    Maps:
    7
    Spells:
    21
    Tutorials:
    2
    JASS:
    4
    Resources:
    37
    Maybe gtfo?
     
  6. BPower

    BPower

    Joined:
    Mar 18, 2012
    Messages:
    1,745
    Resources:
    21
    Spells:
    15
    Tutorials:
    1
    JASS:
    5
    Resources:
    21
    Slightly. Paused units require overall less computation time then non-paused units.

    I care, along with many others.
    --------------------------------------

    Can't you change it to O(1)?
    Wrote directly into comments, so maybe not working at all or including mistakes.
    Code (vJASS):

    // Step 1
    set dummy = CreateUnit(Player(i), DUMMY, x, y, 0)
    set table[GetHandleId(dummy)] = UIkey
    set table.unit[i*9 + UIKey] = dummy
    //call PauseUnit(dummy, true)

    //Step 2, Calibration
    loop
        exitwhen i > 9
    //.....
             call SelectUnit(table.unit[id*9 + i], true)
             call ForceUIKey(I2S(i))
    // ....
    endloop

    // Step 3 onSelect.
    if table.has(GetHandleId(u)) and GetOwningPlayer(u) == p then
    set eventIndex  = table[GetHandleId(u)]
    set eventPlayer = p
    //--> Fire trigger

     

    Storing
    Player(id)
    in function calibrate into local player p is not a benefit.
    You just need it once.
    GetLocalPlayer() == Player(x)
    is also very read-able.

    Recursion safety.

    Can locust units be selected? I know that you immediatly lose controll,
    but maybe it still does fire an event ( users accidently killing dummy, etc )

    I still want that you explain what a good calibration timeout parameter is.
    How should a user know where to start/end? A short guidance is appreciated.

    Register the select event only to players who are non computer, user players.

    I guess it gets overwritten quickly, when users decided to assign their hero to
    i.e. UIkey 1
     
    Last edited: Jun 27, 2015
  7. Quilnez

    Quilnez

    Joined:
    Oct 12, 2011
    Messages:
    3,169
    Resources:
    37
    Icons:
    2
    Tools:
    1
    Maps:
    7
    Spells:
    21
    Tutorials:
    2
    JASS:
    4
    Resources:
    37
    Updated
    - Some suggestions have been applied, however, I don't use Table
    - No longer requires TimerUtils
    - No more overhead in calibrating keys
    - Some other minor improvements

    _______
    Some points:
    - I really think camelCase looks much better for private functions. I doubt that I will ever change this style.
    - Tested, and selected locust unit does not fire event
    - Yes, players are not supposed to use that feature after using this system. Anyway, I don't think many people know about that feature to save unit control groups.
    - I forgot this. Quick update's incoming.

    _______
    Quick update:
    - Fixed registering problems
    - Fixed selection bug
    - Some minor improvements

    _______
    Does O(1) means constant execution times? If so, my previous method was O(1) already since the dummy units count never increase. Faster doesn't mean O(1), iirc.
    I don't want to complain your method tho since it's indeed better, I'm just a bit confused about what O(1) actually means?

    _______
    Now I can avoid the use of 2D array (which takes a lot of memory) by using unit group array. I wonder which one is better? Nvm, using unit groups will result in numerous overhead eventually.
     
    Last edited: Jun 27, 2015
  8. Almia

    Almia

    Joined:
    Apr 24, 2012
    Messages:
    4,839
    Resources:
    35
    Spells:
    30
    Tutorials:
    4
    JASS:
    1
    Resources:
    35
    O(n) means how long the process takes. O(1) is the "fastest" process. Read the Big O Notation:
    https://en.wikipedia.org/wiki/Big_O_notation
     
  9. BPower

    BPower

    Joined:
    Mar 18, 2012
    Messages:
    1,745
    Resources:
    21
    Spells:
    15
    Tutorials:
    1
    JASS:
    5
    Resources:
    21
    If I would have had to guess, I would say 97% of all wc3 players know. Probably I'm wrong and it is more.
    Everybody who every played normal wc3, the campaign or DotA knows this.
     
  10. Quilnez

    Quilnez

    Joined:
    Oct 12, 2011
    Messages:
    3,169
    Resources:
    37
    Icons:
    2
    Tools:
    1
    Maps:
    7
    Spells:
    21
    Tutorials:
    2
    JASS:
    4
    Resources:
    37
    So now that's a problem. New cons.
     
  11. BPower

    BPower

    Joined:
    Mar 18, 2012
    Messages:
    1,745
    Resources:
    21
    Spells:
    15
    Tutorials:
    1
    JASS:
    5
    Resources:
    21
    I still like this system alot. I think it's useful.

    One question: What is your problem with Table?
    Personally I think it's the most useful resource we have. ( Bribes & Vexorians)
     
  12. Quilnez

    Quilnez

    Joined:
    Oct 12, 2011
    Messages:
    3,169
    Resources:
    37
    Icons:
    2
    Tools:
    1
    Maps:
    7
    Spells:
    21
    Tutorials:
    2
    JASS:
    4
    Resources:
    37
    I don't have problem with it, I'm using Table a lot, but for personal use only. I'm just trying to have less requirements as possible.

    Small update:
    - Fixed re-calibrate event bug
    - Some minor improvements

    Small update:
    - Now it doesn't use 2D array
     
    Last edited: Jun 28, 2015
  13. edo494

    edo494

    Joined:
    Apr 16, 2012
    Messages:
    3,855
    Resources:
    5
    Spells:
    1
    JASS:
    4
    Resources:
    5
    That is not true.

    Big O notation means time/space complexity, not necessarily real time representation.

    For instance, despite bubble sort being O(n^2), it will most likely perform a lot better on array of 5 items than merge/quick/heap sort which tend to be O(n log n).

    Also the infamous linked list O(n) traversal is for sure a lot slower than O(n) array traverse

    edit:
    I want to add that O(n) is effectivelly equal to O(2n), since 2 is small factor as n increases to infinity, but still, O(n) will always be faster
     
    Last edited: Jun 28, 2015
  14. BPower

    BPower

    Joined:
    Mar 18, 2012
    Messages:
    1,745
    Resources:
    21
    Spells:
    15
    Tutorials:
    1
    JASS:
    5
    Resources:
    21
    Every dummy units is property of their triggering players.
    Ergo you could also go with EVEN_UNIT_SELECTED over EVENT_PLAYER_UNIT_SELECTED.

    The unit event will fire very seldom ( only when a controll group is selected ),
    the player unit event fires all the time ( each time any unit is selected )
     
  15. Quilnez

    Quilnez

    Joined:
    Oct 12, 2011
    Messages:
    3,169
    Resources:
    37
    Icons:
    2
    Tools:
    1
    Maps:
    7
    Spells:
    21
    Tutorials:
    2
    JASS:
    4
    Resources:
    37
    Fixed. Thanks for all of your suggestions, it's been much better now.
     
  16. BPower

    BPower

    Joined:
    Mar 18, 2012
    Messages:
    1,745
    Resources:
    21
    Spells:
    15
    Tutorials:
    1
    JASS:
    5
    Resources:
    21
    Not working yet. GetTriggerPlayer() is not a valid event response to EVENT_UNIT_SELECTED. ( It returns always 0 )

    Logical or : UNIT_EVENT vs PLAYER_UNIT_EVENT!

    You have to use
    GetOwningPlayer(GetTriggerUnit())
     
  17. Quilnez

    Quilnez

    Joined:
    Oct 12, 2011
    Messages:
    3,169
    Resources:
    37
    Icons:
    2
    Tools:
    1
    Maps:
    7
    Spells:
    21
    Tutorials:
    2
    JASS:
    4
    Resources:
    37
    How bout now?
     
  18. BPower

    BPower

    Joined:
    Mar 18, 2012
    Messages:
    1,745
    Resources:
    21
    Spells:
    15
    Tutorials:
    1
    JASS:
    5
    Resources:
    21
    Looks good? Did you perform ingame test?
    I will check out your demo yet and write a review afterwards.

    Edit: Tested and epic. Table would be a good dependency, it's used in nearly every map anyways.
    TimerUtils would also be nice. I will place these infos under "link" into the review.
     
  19. Quilnez

    Quilnez

    Joined:
    Oct 12, 2011
    Messages:
    3,169
    Resources:
    37
    Icons:
    2
    Tools:
    1
    Maps:
    7
    Spells:
    21
    Tutorials:
    2
    JASS:
    4
    Resources:
    37
    Hmm.. TimerUtils won't be a really good addition, since I never destroy timers afterwards. But I will consider to use Table since one hashtable for one system is pretty much "expensive", but maybe later.