1. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  2. DID YOU KNOW - That you can unlock new rank icons by posting on the forums or winning contests? Click here to customize your rank or read our User Rank Policy to see a list of ranks that you can unlock. Have you won a contest and still haven't received your rank award? Then please contact the administration.
    Dismiss Notice
  3. From the gates of hell, the 5th Special Effect Contest Results have emerged.
    Dismiss Notice
  4. Rubbed the right way, the genie is out of its lamp! The 12th Concept Art Contest Results have been announced.
    Dismiss Notice
  5. Race against the odds and Reforge, Don't Refund. The 14th Techtree Contest has begun!
    Dismiss Notice
  6. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

[Snippet] OrderQueueLite

Discussion in 'Graveyard' started by Ender, Feb 8, 2013.

  1. Ender

    Ender

    Joined:
    Jan 28, 2012
    Messages:
    208
    Resources:
    2
    Spells:
    1
    Tutorials:
    1
    Resources:
    2
    OrderQueueLite, is a simple system that replicates the functionality of shift orders, with the advantage that it is uninteruptable, and you can issue them by triggers.

    Why Lite? I am making another version that will use a linked list, enable you to change the order, and have a memory of previous Orders(the size of the memory will be user definable.)
    Code (vJASS):
    library OrderQueueLite /* v 1.0.0.5
    **************************************************************
    *       ___            _____                                 *
    *      |   \          | ____|                                *
    *      |   /  \\  / / | |__    _   _   __       _    _   _   *
    *      |   \   \\/ /  |  __|  |  \| | |   \   /   \ | |/ /   *
    *      |___/   / /    | |___  | \ \ | |    | | |__/ |  /     *
    *             / /     |_____| |_|\ \| |___/   \__\  |_|      *
    *                                                            *
    **************************************************************
    *           */
    uses /*
    *           */
    CTL /* hiveworkshop.com/forums/jass-resources-412/snippet-constant-timer-loop-32-a-201381/
    *           */
    Table /* hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/?highlight=Table
    *           */
    UnitIndexer /* hiveworkshop.com/forums/jass-resources-412/system-unit-indexer-172090/
    *           * Order Id Repo * hiveworkshop.com/forums/jass-resources-412/repo-order-ids-197002/
    **************************************************************
    *
    * Credits- Almia for giving some useful suggestions.
    *
    **************************************************************
    *
    *             what is OrderQueueLite?
    *               - it is a system that copies shift order functionallity
    *               - Unlike OrderQueue(not released yet) it can not
    *                   insert new orders in the units order chain.
    *
    ***************************************************************
    *
    *       struct OrderQueue extends array
    *
    *           readonly integer last
    *           readonly integer current
    *
    *           static method create takes unit u returns thistype
    *               - a unit will only ever have one unit queue
    *               - order queues are destroyed automatically
    *                   so call create whenever you want to
    *                    add new orders to an OrderQueue
    *
    *           static method isValidOrder takes integer i returns boolean
    *               - tells you whether i is valid Order for a Queue.
    *
    *          method getOrderId takes integer i returns integer
    *              - gives you the orderId of a specific order
    *
    *          method getOrderType takes integer i returns integer
    *              - tells you what Type of order is in that slot
    *
    *           method destroy takes nothing returns nothing
    *               -destroys the OrderQueue
    *
    *           method pop takes nothing returns nothing
    *               removes the Current Order the Unit is doing
    *                  and orders them to do the next
    *
    *
    *
    *           method issuePointOrder takes integer order, real x, real y returns nothing
    *           method issueTargetOrder takes integer order, widget target returns nothing
    *           method issueImmediateOrder takes integer order returns nothing
    *           method issueItemPointOrder takes item toUse, real x, real y returns nothing
    *           method issueItemTargetOrder takes item toUse, widget target returns nothing
    *           method issueItemOrder takes item toUse returns nothing
    *          
    ***************************************************************/




        private module OrderQueueInit
            static method onInit takes nothing returns nothing
                set tg = TimerGroup32.create(function thistype.periodic)
                call TriggerRegisterAnyUnitEventBJ(stopOrder, EVENT_PLAYER_UNIT_ISSUED_ORDER)
                call TriggerRegisterAnyUnitEventBJ(stopOrder, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER)
                call TriggerRegisterAnyUnitEventBJ(stopOrder, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER)
                call TriggerAddCondition(stopOrder, Condition(function thistype.stopOrders))
            endmethod
        endmodule

        struct OrderQueue extends array
            private static constant integer Point = 0
            private static constant integer Target = 1
            private static constant integer Immediate = 2
            private static constant integer ItemPoint = 3
            private static constant integer ItemTarget = 4
            private static constant integer Item = 5

            private static constant integer totalC = 4
            private static TimerGroup32 tg
            static trigger stopOrder = CreateTrigger()
            private Table list
           
            private integer count
            private integer recycle
            readonly integer current
            readonly integer last
            boolean active
            boolean paused

            thistype nex
            thistype pre
           
            method operator canOrder takes nothing returns boolean
                return (not paused) and (GetUnitCurrentOrder(GetUnitById(this))==0)
            endmethod

            private method getRecycle takes integer i returns integer
                return list[i+2]
            endmethod
            private method setRecycle takes integer i, integer toWhat returns nothing
                set list[i+2]=toWhat
            endmethod
            private method next takes integer i returns integer
                return list[i]
            endmethod
            private method setNext takes integer i, integer a returns nothing
                set list[i]=a
            endmethod
           
            static method isValidOrder takes integer i returns boolean
                return (R2I(I2R(i)/I2R(totalC)) == i/totalC)
            endmethod
           
            method getOrderId takes integer i returns integer
                debug if not isValidOrder(i) then
                    debug call BJDebugMsg(I2S(i) + " Is an invalid order")
                    debug return 1/0
                debug endif
                return list[i+1]
            endmethod
           
            method getOrderType takes integer i returns integer
                debug if not isValidOrder(i) then
                    debug call BJDebugMsg(I2S(i) + " Is an invalid order")
                    debug return 1/0
                debug endif
                return list[i+3]
            endmethod

            method pause takes nothing returns nothing
                local integer i = 0
                set paused = true
     
                if current != 0 then
                    call setNext(0,current)
                    set current = 0
                endif
            endmethod

            method unpause takes nothing returns nothing
                set paused = false
            endmethod

            static method create takes unit u returns thistype
                local thistype this = GetUnitUserData(u)

                if active then
                    return this
                endif
                if .nex == 0 then
                    call tg.start()
                endif
                set paused = false
                call UnitIndex(this).lock()
                set list = Table.create()
                set active = true
                set .nex = 0
                set .pre = thistype(0).pre
                set thistype(0).pre = this
                set .pre.nex = this
                return this
            endmethod
           
            method destroy takes nothing returns nothing
                if not active then
                    return
                endif
                if thistype(0).nex == this and thistype(0).pre == this then
                    call tg.stop()
                endif

                set active = false
                call UnitIndex(this).unlock()
                call list.destroy()
                set .current = 0
                set .last = 0
                set .pre.nex = .nex
                set .nex.pre = .pre
            endmethod

            method pop takes nothing returns nothing
                local integer i = current
                local integer n = next(i)
                local integer b = totalC-1
                local integer s = list[n+3]

                set current = n

                if i != 0 then
                    call setRecycle(i,recycle)
                    set recycle = i
                    call list.handle.remove(i)
                    call list.handle.remove(i+1)
                endif
               
                if s > Immediate then
                    if s < Item then
                        if s == ItemPoint then
                            call UnitUseItemPoint(GetUnitById(this),list.item[n+1],list.real[n],list.real[n+1])
                            return
                        endif
                        call UnitUseItemTarget(GetUnitById(this),list.item[n+1],list.widget[n])
                        return
                    endif
                    call UnitUseItem(GetUnitById(this),list.item[n+1])
                    return
                else
                    if s < Immediate then
                        if s == Point then
                            call IssuePointOrderById(GetUnitById(this),list[n+1],list.real[n],list.real[n+1])
                            return
                        endif
                        call IssueTargetOrderById(GetUnitById(this),list[n+1],list.widget[n])
                        return
                    endif
                    call IssueImmediateOrderById(GetUnitById(this),list[n+1])
                endif
            endmethod
           
            private method push takes nothing returns integer
                local integer i = recycle
                if i == 0 then
                    set i = count+totalC
                    set count = i
                else
                    set recycle = getRecycle(i)
                endif
                call setNext(last,i)
                set last = i
                return i
            endmethod
           
            static method periodic takes nothing returns boolean
                local thistype this = thistype(0).nex

                call DisableTrigger(stopOrder)

                loop
                    exitwhen this ==0
                    if .canOrder then
                        if current == last then
                            call destroy()
                        else
                            call pop()
                        endif
                    endif
                    set this = .nex
                endloop

                call EnableTrigger(stopOrder)
                return false
            endmethod
           
            method issuePointOrderById takes integer order, real x, real y returns nothing
                local integer i = push()
                set list.real[i] = x
                set list.real[i + 1]= y
                set list[i + 1] = order
                set list[i + 3] = Point
            endmethod
            method issueImmediateOrderById takes integer order returns nothing    
                local integer i = push()
                set list[i + 1] = order
                set list[i + 3] = Immediate
            endmethod
            method issueTargetOrderById takes integer order, widget target returns nothing
                local integer i= push()
                set list.widget[i] = target
                set list[i + 1] = order
                set list[i + 3] = Target
            endmethod
            method issueItemPointOrder takes item toUse, real x, real y returns nothing
                local integer i = push()
                set list.real[i] = x
                set list.real[i + 1] = y
                set list.item[i + 1] = toUse
                set list[i + 3] = ItemPoint
            endmethod
            method issueItemOrder takes item toUse returns nothing    
                local integer i = push()
                set list.item[i + 1] = toUse
                set list[i + 3] = Item
            endmethod
            method issueItemTargetOrder takes item toUse, widget target returns nothing
                local integer i= push()
                set list.widget[i]= target
                set list.item[i + 1] = toUse
                set list[i + 3] = ItemTarget
            endmethod
           
            private static method stopOrders takes nothing returns boolean
                local thistype this =GetUnitUserData(GetTriggerUnit())
                local integer n = .current
                local integer s

                if n != 0 then
                    call DisableTrigger(stopOrder)
                    set s = list[n+3]
                    if s > Immediate then
                        if s < Item then
                            if s == ItemPoint then
                                call UnitUseItemPoint(GetUnitById(this),list.item[n+1],list.real[n],list.real[n+1])
                            else
                                call UnitUseItemTarget(GetUnitById(this),list.item[n+1],list.widget[n])
                            endif
                        else
                            call UnitUseItem(GetUnitById(this),list.item[n+1])
                        endif
                    else
                        if s < Immediate then
                            if s == Point then
                                call IssuePointOrderById(GetUnitById(this),list[n+1],list.real[n],list.real[n+1])
                            else
                                call IssueTargetOrderById(GetUnitById(this),list[n+1],list.widget[n])
                            endif
                        else
                            call IssueImmediateOrderById(GetUnitById(this),list[n+1])
                        endif
                    endif
                    call EnableTrigger(stopOrder)
                endif
                return false
            endmethod

            private method deindex takes nothing returns nothing
                call this.destroy()
            endmethod
           
            implement UnitIndexStruct
            implement OrderQueueInit
        endstruct
    endlibrary


    ChangeLog
    1.0.0.0
    Uploaded
    1.0.0.1
    Fixed spacing
    1.0.0.2
    -fixed a bug involving the binary tree
    -added pause and unpause
    1.0.0.3
    Fixedd a minor bug with issueTargetOrder
    1.0.0.4
    Made Sys RegisterAnyUnitEvent
    added a link to an awsome Repository by Nestherus
    1.0.0.5
    Removed some changes from previous version

    Example
    Code (vJASS):
    scope TestOrderQueue initializer init
        globals
            private integer count = 21
            private OrderQueue pauseThis
        endglobals
        private function wait takes nothing returns nothing
            call pauseThis.unpause()
            call DestroyTimer(GetExpiredTimer())
        endfunction
        private function createLots takes nothing returns nothing
            local unit u  = CreateUnit(Player(0),'hfoo',0,0,0)
            local OrderQueue this = OrderQueue.create(u)
            local integer i = 10

            loop
                call this.issuePointOrderById(851986 , 700, -700)
                call this.issuePointOrderById(851986 , 700, 700)
                call this.issuePointOrderById(851986 , -700, 700)
                call this.issuePointOrderById(851986 , -700, -700)
                call this.issuePointOrderById(851986 , 700, -700)
                set i =i-1
                exitwhen i == 0
            endloop

            set u = null
            set count = count-1
            if count == 0 then
                set pauseThis = this
                call this.pause()
                call TimerStart(CreateTimer(),1,false,function wait)
                call DestroyTimer(GetExpiredTimer())
            endif
        endfunction
       
        private function init takes nothing returns nothing
            call createLots()
            call TimerStart(CreateTimer(),1,true,function createLots)
        endfunction
    endscope
     
    Last edited: Feb 25, 2013
  2. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,006
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    I think
    empty
    would be a better name for the
    hasNoOrder
    method operator because
    empty
    refers to the queue directly while
    hasNoOrder
    refers to the unit :eek:

    This resource looks cool. I coded something like this a long time ago for one of my maps. It was pretty lame though :p

    The spacing is a bit inconsistent though.
    Usually, I'd recommend an empty line between consecutive methods unless they're a long chain of method operators, getters and setters.
    I'd recommend this kind of spacing:
    set variable = value

    call Function(param, param, param)

    set myInteger = 1 + 5/6*7 - 4*3 + 2/1


    - and + get spaces before and after while * and / don't.

    Also, are the strings really necessary? :eek:
    Wouldn't some constant integers accomplish the same thing?

    One last thing concerning your list iteration. I think the
    exitwhen this == 0
    line should be the first line to appear in the loop because it gives correct behavior for an empty list.
     
  3. Ender

    Ender

    Joined:
    Jan 28, 2012
    Messages:
    208
    Resources:
    2
    Spells:
    1
    Tutorials:
    1
    Resources:
    2
    yes, I will change it in the next version and I will fix the spacing.
    edit:changed
     
    Last edited: Feb 9, 2013
  4. PurgeandFire

    PurgeandFire

    Code Moderator

    Joined:
    Nov 11, 2006
    Messages:
    7,428
    Resources:
    18
    Icons:
    1
    Spells:
    4
    Tutorials:
    9
    JASS:
    4
    Resources:
    18
    Nice job, you have a pretty elegant approach to it. You should make a quick sample and post it in the main post.
     
  5. Ender

    Ender

    Joined:
    Jan 28, 2012
    Messages:
    208
    Resources:
    2
    Spells:
    1
    Tutorials:
    1
    Resources:
    2
    @PurgeandFire thank you, I will add a sample soon, I also am going to add pause and unpause (or should it be pause(boolean)?)

    edit: Fixed a major bug
     
    Last edited: Feb 12, 2013
  6. Ender

    Ender

    Joined:
    Jan 28, 2012
    Messages:
    208
    Resources:
    2
    Spells:
    1
    Tutorials:
    1
    Resources:
    2
    BugFix: updated to fix a minor bug with issueTargetOrder.

    Should I change the use item orders to use itemSlot orders?
     
  7. Almia

    Almia

    Joined:
    Apr 24, 2012
    Messages:
    4,843
    Resources:
    35
    Spells:
    30
    Tutorials:
    4
    JASS:
    1
    Resources:
    35
  8. Ender

    Ender

    Joined:
    Jan 28, 2012
    Messages:
    208
    Resources:
    2
    Spells:
    1
    Tutorials:
    1
    Resources:
    2
    Updated to use RegisterAnyUnitEvent, thank you for the suggestion Almia.
     
  9. gorillabull

    gorillabull

    Joined:
    Jul 17, 2011
    Messages:
    1,368
    Resources:
    2
    Spells:
    2
    Resources:
    2
    this is very nice + more rep hahahahahahhaha
     
  10. Almia

    Almia

    Joined:
    Apr 24, 2012
    Messages:
    4,843
    Resources:
    35
    Spells:
    30
    Tutorials:
    4
    JASS:
    1
    Resources:
    35
    you can use [Repo]order ids by nestharus found in page 4 of this section
     
  11. Ender

    Ender

    Joined:
    Jan 28, 2012
    Messages:
    208
    Resources:
    2
    Spells:
    1
    Tutorials:
    1
    Resources:
    2
    @Almia very good suggestion, I have included a link to it
     
  12. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,006
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
  13. Ender

    Ender

    Joined:
    Jan 28, 2012
    Messages:
    208
    Resources:
    2
    Spells:
    1
    Tutorials:
    1
    Resources:
    2
    bleh, I just realized that i would need to update a whole lot of code to switch to either one, because i need to turn the detection on and off.
     
  14. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,006
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    I too realized that this doesn't compile in its current state.
     
  15. Ender

    Ender

    Joined:
    Jan 28, 2012
    Messages:
    208
    Resources:
    2
    Spells:
    1
    Tutorials:
    1
    Resources:
    2
    I could use a flag to enable it to use IssueAnyOrder
    or i could do
    Code (vJASS):
    call DisableTrigger(so1)
    call DisableTrigger(so2)
    call DisableTrigger(so3)
    /*
    *Where  triggers so1-3 are set using GetPlayerUnitEventTrigger
    * The problem with this is it would mess up other UnitOrderEvents
    */
     
  16. Almia

    Almia

    Joined:
    Apr 24, 2012
    Messages:
    4,843
    Resources:
    35
    Spells:
    30
    Tutorials:
    4
    JASS:
    1
    Resources:
    35
    I think you could add GetLastCommand() which returns orders
     
  17. Ender

    Ender

    Joined:
    Jan 28, 2012
    Messages:
    208
    Resources:
    2
    Spells:
    1
    Tutorials:
    1
    Resources:
    2
    what do you mean? would it be the last order a queue has? or something else?
     
  18. Almia

    Almia

    Joined:
    Apr 24, 2012
    Messages:
    4,843
    Resources:
    35
    Spells:
    30
    Tutorials:
    4
    JASS:
    1
    Resources:
    35
    yeah,last order of the queue of the unit.if you can make it,it will be good addition for an AI system
     
  19. Ender

    Ender

    Joined:
    Jan 28, 2012
    Messages:
    208
    Resources:
    2
    Spells:
    1
    Tutorials:
    1
    Resources:
    2
     readonly integer last/[ljass]
    i'll also add [ljass]getOrderId takes integer whichOrder returns integer


    Edit: updated
     
    Last edited: Feb 25, 2013
  20. TriggerHappy

    TriggerHappy

    Code Moderator

    Joined:
    Jun 23, 2007
    Messages:
    3,702
    Resources:
    22
    Spells:
    11
    Tutorials:
    2
    JASS:
    9
    Resources:
    22
    You should probably be using GetUnitId instead of GetUnitUserData (it will inline anyways). It could cause issues in certain rare cases.

    For example using the UnitIndexer compatibility library with UnitDex's hashtable option set to true.

    vJass also supports 2D-arrays so you don't have to do things like [i + 3].

    The code looks good but I'll need to test it before approving.