1. Are you planning to upload your awesome spell or system to Hive? Please review the rules here.
    Dismiss Notice
  2. The 30th edition of the Modeling Contest is finally up! The Portable Buildings need your attention, so come along and have a blast!
    Dismiss Notice
  3. 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
  4. Melee Mapping Contest #3 - Results are out! Congratulate the winners and check plenty of new 4v4 melee maps designed for this competition!
    Dismiss Notice
  5. 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

ArrowKeySequence v3.0.1

Submitted by IcemanBo
This bundle is marked as approved. It works and satisfies the submission rules.
Info

This code allows you to create an ArrowKeySequence which can be solved by a user.
An ArrowKeySequence is for example: { [⟶] [⟶] [↑] }. ( RIGHT, RIGHT, UP)
Now, when the user puhses these arrow keys in correct order, it can be seen as solved.

Examples:
1. It can be used as kind of a puzzle.
2. It can act as opening mechanism for treasure chests like in the RPG Gothic.
3. It can be a secret cheat seqeunce wich activates something hidden.

Actually I was mostly inspired by the usage for chests like in Gothic,
but I tried to make a more universal purpose out of it.

Check out the 4 demonstrations in map to see what you can do. :)

Special

What makes it kind of special I think is that a user is allowed to have parallel running sequences, even of the same type.
What does this mean?

For example the sequence to solve is: { [⟵] [⟶] [⟵] [↑] }
Let's assume that the user tries like this:

1.) Don't allow parallel sequences:
[⟵] [⟶] [⟵] []
4th element was wrong and the user has to start with the very first element again.

2.) Allow parallel sequences:
[⟵] [⟶] [⟵] []
[⟵] [⟶] [ ? ] [ ? ]

It turns out he still can solve the sequence with only 2 new attempts,
even the [⟶] arrow key was wrong for the initial started sequence.
So if "[ ? ] [ ? ]" will turn into "[⟵] [↑]", the user solves this sequence type.

Credits:

Code
Code (vJASS):
library ArrowKeySequence /* v3.0.1  By IcemanBo

*/
requires /*

        */
SequenceT        /* hiveworkshop.com/forums/submissions-414/sequencet-274244/#post2772894
        */
ArrowKeyEvent    /* hiveworkshop.com/forums/jass-resources-412/system-arrowkeyevent-205650/
       
*/


/*  What is this?

    This code allows you to create an ArrowKeySequence which can be solved by a user.
    An ArrowKeySequence is for example: "ArrowUp, ArrowDown, ArrowLeft".
    Now, when the user puhses these arrow keys in correct order, it can be seen as solved.
   
    It can be used as kind of a puzzle, or it can also act as
    opening mechanism for treasure chests like in the RPG Gothic.

*/


//! novjass  
   
//API

    /*  At first you need to create at least one
        ArrowKeySequence that a user can try to solve.
        You need knowledge of the Vector library to create a vector.
        You can look in Sequence Demo for an example.
   
        You also have to register a boolexpr as code,
        that will run, whenever a user tries to solve a sequence.*/

   
   
        //  struct ArrowKeySequence - constructor
   
                static method create takes IntegerVector vector, boolexpr bx returns thistype
       
        //  struct ArrowKeySequence - destructor
   
                For safety the destructor is wrapped into the API function DestroySequence. (see later)
   
    //  The registered code will fire whenever a user presses a key while he is about to
    //  solve a sequence. Within the code function you have access to:
   
                boolean IsSequenceSolved                // Is sequence completed
                boolean IsKeyCorrect                    // If current input was correct
                integer CurrentSequenceVectorPosition   // Current position in sequence
                integer ArrowKeyInteger                 // Read ArrowKeyEvent for info which key it is.
                player  ArrowKeyUser                    // User who pressed the arrow key
   
                function EndSequence takes nothing returns nothing
                    // The current running sequence will end for the user.
                   
                function EndSequenceAll takes ArrowKeySequence keySequence, player p returns nothing
                    // Will end ALL sequences of a type for the user "p".
                   
                function DestroySequence takes ArrowKeySequence keySequence returns nothing
                    // Will end ALL sequences of the type for all players.
                    // Will completly destroy the sequence so it can't be used anymore. (deallocate)
                   
               
               
               
    //  Use follwing function to start.
   
                function StartPlayerSequence takes player p, ArrowKeySequence id, integer pos returns nothing
                    // whichPlayer
                    // whichSequence
                    // startPosition (All vectors start with "0". So "0" is the common start value.
                    //                But in case you want, you can manipulate it to your needs.
               
               
    //  It is recommended to read the demo examples.
    //  That was it. Have fun!
   
//! endnovjass
   
    // Data of all default sequences (added by user)
    struct ArrowKeySequence extends array
        implement Alloc
        readonly trigger handler
        readonly IntegerSequenceType sequence
       
        static method create takes IntegerVector vec, boolexpr bx returns thistype
            local thistype this = allocate()
            set this.sequence = IntegerSequenceType.create(vec)
            set this.handler = CreateTrigger()
            call TriggerAddCondition(handler, bx)
            return this
        endmethod
       
        method destroy takes nothing returns nothing
            call this.sequence.destroy()
            call DestroyTrigger(this.handler)
            set this.handler = null
            call this.deallocate()
           
        endmethod
    endstruct

    //! runtextmacro DEFINE_STRUCT_VECTOR("", "SequenceVector", "IntegerSequence")
    //! runtextmacro DEFINE_STRUCT_VECTOR("", "ArrowKeySequenceVector", "ArrowKeySequence")

    globals
        player ArrowKeyUser
        integer ArrowKeyInteger
        boolean IsKeyCorrect
        private boolean endSequence
        private ArrowKeySequence currentArrowKeySequence
        private integer max
    endglobals
   
    // This handles the sequences of all players.
    struct PlayerSequence extends array
       
        private boolean inGame                
        readonly ArrowKeySequenceVector arrowKeySequence
        private SequenceVector sequence
        readonly integer sequenceAmount
       
        // Will remove the sequence from given position.
        method end takes integer pos returns nothing
            call this.arrowKeySequence.erase(pos, 1)
           
            call this.sequence[pos].destroy()
            call this.sequence.erase(pos, 1)
            set this.sequenceAmount = this.sequenceAmount - 1
           
        endmethod
       
        // Will start a new sequence from vectorPosition[startPos]
        method start takes ArrowKeySequence that, integer startPos returns nothing
            call this.arrowKeySequence.push(that)
            call this.sequence.push(IntegerSequence.create(that, startPos))
            set this.sequenceAmount = this.sequenceAmount + 1
        endmethod
       
        private method onArrowKeyEvent takes integer arrow, boolean pressed returns nothing
            local integer i
            local integer currentSequencePosition
           
            if (pressed) then
               
                // Responses
                set ArrowKeyUser = Player(this)
                set ArrowKeyInteger = arrow
               
                // We need an independant integer as max, to have more control.
                // The sequenceAmount is dynamic and can be changed which may lead to bugs.
                set max = this.sequenceAmount
             
                set currentSequencePosition = 0
                loop
                    exitwhen currentSequencePosition >= max
                   
                    set currentArrowKeySequence = this.arrowKeySequence[currentSequencePosition]
                   
                    call this.sequence[currentSequencePosition].onSequenceEvent(arrow)
                    set IsKeyCorrect = IsSequenceInputCorrect
                   
                    if (IsSequenceSolved) then
           
                        set i = this.sequenceAmount - 1
                        loop
                            exitwhen(i < 0)
                            if (this.arrowKeySequence[i] == currentArrowKeySequence) then
                                call this.end(i)
                                set max = max - 1
                            endif
                            set i = i - 1
                        endloop
                    endif
                     
                    set endSequence = false
                   
                    // Interact with user
                    call TriggerEvaluate(currentArrowKeySequence.handler)
                    if (endSequence) then
                        call this.end(currentSequencePosition)
                        set max = max - 1
                    else
                        set currentSequencePosition = currentSequencePosition + 1
                    endif
                   
                endloop
               
            endif
        endmethod
        implement ArrowKey
       
        // If a player leaves he doesn't need the vectors anymore
        private static method onLeave takes nothing returns boolean
            local integer i = GetPlayerId(GetTriggerPlayer())
           
            if (thistype(i).inGame) then
                call thistype(i).arrowKeySequence.destroy()
                call thistype(i).sequence.destroy()
                set thistype(i).sequenceAmount = 0
            endif
       
            return false
        endmethod
       
        private static method onInit takes nothing returns nothing
            local integer i = 0
            local trigger t = CreateTrigger()
            call TriggerAddCondition(t, function thistype.onLeave)
           
            loop
                exitwhen (i > 11)
               
                 set thistype(i).sequenceAmount = 0
                if (GetPlayerController(Player(i)) == MAP_CONTROL_USER) then
                   
                    set thistype(i).arrowKeySequence = ArrowKeySequenceVector.create()
                    set thistype(i).sequence = SequenceVector.create()
                    set thistype(i).inGame = true
                   
                    call TriggerRegisterPlayerEvent(t, Player(i), EVENT_PLAYER_LEAVE)
                endif
                set i = i + 1
            endloop
        endmethod
       
    endstruct
   
    // API
                   
    // Remove all sequences of a type for a player.
    function EndSequenceAll takes ArrowKeySequence currentKeySequence, player p returns nothing
        local PlayerSequence this = PlayerSequence(GetPlayerId(p))
        local integer i = this.sequenceAmount - 1
        loop
            exitwhen(i < 0)
            if (this.arrowKeySequence[i] == currentKeySequence) then
                call this.end(i)
                set max = max - 1
            endif
            set i = i - 1
        endloop
    endfunction
   
    // When a sequence per pe gets destroyed then
    // we to run though all player sequences and
    // remove the destroyed sequence type.
    function DestroySequence takes ArrowKeySequence keySequence returns nothing
        local integer i = 0
        loop
            exitwhen (i > 11)
            call EndSequenceAll(keySequence, Player(i))
            set i = i + 1
        endloop
        call keySequence.destroy()
    endfunction
   
    function EndSequence takes nothing returns nothing
        set endSequence = true
    endfunction
   
    function StartPlayerSequence takes player p, ArrowKeySequence id, integer pos returns nothing
        call PlayerSequence(GetPlayerId(p)).start(id, pos)
    endfunction
endlibrary


Changelog

v3.0.1
-little documentation changes​
v3.0
-many changes now with usage of SequenceT​
....
v1.0
- release​

Keywords:
Arrow, Key, Sequence, Event, Mechanism, Bribe, Vector, Bannar, Alloc, Gothic, IcemanBo, null, einfach cool, naja
Previews
Contents

Noch eine WARCRAFT-III-Karte (Map)

Reviews
Moderator
23:56, 18th Jan 2016 BPower: Very cool system, which could turn out to be useful for some map makers. Puzzle can always spice up games or make you turn frustrated. I was playing the demo map for quite some time. It's cool. Check it out.
  1. 23:56, 18th Jan 2016
    BPower:

    Very cool system, which could turn out to be useful for some map makers. Puzzle can always spice up games or make you turn frustrated.

    I was playing the demo map for quite some time. It's cool. Check it out.
     
  2. Bribe

    Bribe

    Joined:
    Sep 26, 2009
    Messages:
    7,746
    Resources:
    25
    Maps:
    3
    Spells:
    10
    Tutorials:
    3
    JASS:
    9
    Resources:
    25
    Looks like a neat thing, and would be cool for things like God-of-War sequences. Only one minor improvement from what I can see - the struct should all be normal methods which takes the player ID as the "this". The ArrowKey module provides you with static [] operators for taking a player and converting it to an ID, so your function wrappers can still take players but the struct would take the integer ID.

    Also, the struct already namespaces you to PlayerSequence, so its public methods should just be "start" and "end".

    Code (vJASS):

        function IsPlayerInSequence takes player p returns boolean
             return PlayerKeySequence[p].enabled
         endfunction
         
         function StartPlayerSequence takes player p, ArrowKeySequence sequence returns nothing
             call PlayerKeySequence[p].start(sequence)
         endfunction
         
         function EndPlayerSequence takes player p returns nothing
             call PlayerKeySequence[p].end()
         endfunction
     
     
  3. IcemanBo

    IcemanBo

    Joined:
    Sep 6, 2013
    Messages:
    5,924
    Resources:
    22
    Maps:
    3
    Spells:
    11
    Template:
    1
    Tutorials:
    4
    JASS:
    3
    Resources:
    22
    oh, you're right. added them later to the struct and forgot to remove the argument they take.
    I will anyway add 2 new ideas I had to have some more functionality so update will come soon. :)

    Thanks.

    edit: wait for update

    Okay updated.

    Biggest change was that it now allows parallel sequences. Read description.
    Also demo was improved and added 2 new demo codes.

    Edit: Hold on, will update it.

    Updated.

    Better API, onLeave detection, and demo and comments improved.
     
    Last edited: Dec 16, 2015
  4. Flux

    Flux

    Joined:
    Feb 6, 2014
    Messages:
    2,334
    Resources:
    28
    Maps:
    1
    Spells:
    19
    Tutorials:
    2
    JASS:
    6
    Resources:
    28
    The Link to VectorT redirects me to TimerUtils :/
     
  5. IcemanBo

    IcemanBo

    Joined:
    Sep 6, 2013
    Messages:
    5,924
    Resources:
    22
    Maps:
    3
    Spells:
    11
    Template:
    1
    Tutorials:
    4
    JASS:
    3
    Resources:
    22
    Will get fixed.

    Edit:
    This should not get reviewed atm.

    Edit 2:
    Updated.
     
    Last edited: Jan 2, 2016
  6. IcemanBo

    IcemanBo

    Joined:
    Sep 6, 2013
    Messages:
    5,924
    Resources:
    22
    Maps:
    3
    Spells:
    11
    Template:
    1
    Tutorials:
    4
    JASS:
    3
    Resources:
    22
    The update changed actually nothing but the compability to the new SequenceT version. It had to be updated.