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

ArrowKeySequence v3.0.1

  • Like
Reactions: HappyTauren
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
JASS:
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
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.

Moderator

M

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.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
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".

JASS:
    function IsPlayerInSequence takes player p returns boolean
         return PlayerKeySequence.enabled
     endfunction
     
     function StartPlayerSequence takes player p, ArrowKeySequence sequence returns nothing
         call PlayerKeySequence.start(sequence)
     endfunction
     
     function EndPlayerSequence takes player p returns nothing
         call PlayerKeySequence.end()
     endfunction
 
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:
Top