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

[JASS] Make a Queue of Orders via JASS (SHIFT-CLICK in-game)

Status
Not open for further replies.
Level 40
Joined
Dec 14, 2005
Messages
10,532
Hiveworkshop was down today so I couldn't browse, sorry.

Anyways, I don't have time to write a good explanation or a script until tomorrow morning or maybe afternoon (code will illustrate this more clearly, but as I said, tomorrow), but here is the theory behind my approach:

  • First, attach a struct via Custom Value (structs are integers!) (or use cache, but handle vars are much slower and otherwise unfeasible) to each unit which will use the system, which has as one of its elements (if you need it for other purposes just add more stuff) as a string array of a small size (max order stack), a widget array (for targets with TargetOrder), and two real arrays (x/y, for PointOrder), as well as an integer counter for each (So you know which is the last index being used at the moment)

  • Then, whenever you want an order to be added, add it to the end of the "stack" and increase the counter value. If it requires a target widget, add that to the widget "stack" and increase the respective counter, and same for points. (You can know which target/point orders pertain to which places on the stack of those targets just by recognizing which orders are which types, or if you are using plenty of them (like random spell ones) you could just use a substring on the front/back which has the type (eg "point" or "widget")).

  • Then, checking rapidly on the unit's current orders, if it has the null order (ie it has finished its current action), issue the next order on the stack and clear it from memory (so that you don't get double issues), reducing the index variables as well.
 
Level 11
Joined
Feb 18, 2004
Messages
394
I am a complete beginner to the JASS, and I want to know how can I give an unit a queue of orders via JASS script, just like the Shift-Click in game.

Basically, thats not possible. It is, however, possible to do as poot says and code an order queueing system.

Poot, I would favour a linked list considering you want a FIFO structure, as you will only ever need to pop the first element and append to the end. (and thats O(1) complexity with a linked list if you store pointers to first and last in the list.) Using structs as nodes for the list would make for an elegant solution, especially with more than 8190 instances. (Newest JASS Helper, check it out.) A linked list also has the benefit of dynamic size with less wasted space. However it has a higher overhead cost.
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
Dynamic size is a good point, the reason I never really considered a linked list was because of the need of an object per order (but I suppose that is actually beneficial, it makes differentiation of order types inlined!). The speed isn't really a major issue, I doubt you will be processing hundreds of new orders to issue every fraction of a second. (If you were, your map would have other problems...)

Linked list is a good idea though, if not mostly because of the simplicity in the storage of order targets. Will do.

EDIT: Untested and unparsed, but here is how I have it so far (This should explain how it works better, if you can read it that is :p). (Will test, parse, etc, in a while)

JASS:
library OrderQueue initializer init
globals
    group oq_queuedUnits = CreateGroup() //to reduce lag, only check for order queues for units in this group
endglobals
struct Order
    integer orderId
    Order next = -1
    integer orderType = 0
    //0 = no target
    //1 = point target
    //2 = widget target
    real x //point target
    real y //point target
    widget w //order target
    static method create takes integer orderId, real x, real y, widget target returns Order
        local Order o = Order.allocate()
        set o.orderId = orderId
        if x != 0 or y != 0 then
            set o.orderType = 1
        elseif target != null then
            set o.orderType = 2
        endif
        set o.x = x
        set o.y = y
        set o.w = target
        return o
    endmethod
    method Issue takes unit subject returns nothing
        if .orderType == 0 then
            call IssueImmediateOrderById(subject,.orderId)
        elseif .orderType == 1 then
            call IssuePointOrderById(subject,.orderId,.x,.y)
        else
            call IssueTargetOrderById(subject,.orderId,.w)
        endif
    endmethod
endstruct

struct UnitData
    Order first = -1
    Order last = -1 //for faster allocation of new orders
    static method create takes unit attach returns UnitData
        local UnitData dat = UnitData.allocate()
        call SetUnitUserData(attach,dat)
        return dat
    endmethod
    method QueueOrder takes integer orderId, real x, real y, widget target returns nothing
        local Order o = Order.create(orderId,x,y,target)
        if .first == -1 then
            set .first = o
        else
            set .last.next = o
        endif
        set .last = o
    endmethod
    method QueueOrderStringNoTarget takes string orderString returns nothing
        call QueueOrder(OrderId(orderString),0,0,null)
    endmethod
    method QueueOrderStringWidgetTarget takes string orderString, widget target returns nothing
        call QueueOrder(OrderId(orderString),0,0,target)
    endmethod
    method QueueOrderStringPointTarget takes string orderString, real x, real y returns nothing
        call QueueOrder(OrderId(orderString),x,y,null)
    endmethod
    method QueueOrderNoTarget takes integer orderId returns nothing
        call QueueOrder(orderId,0,0,null)
    endmethod
    method QueueOrderWidgetTarget takes integer orderId, widget target returns nothing
        call QueueOrder(orderId,0,0,target)
    endmethod
    method QueueOrderPointTarget takes integer orderId, real x, real y returns nothing
        call QueueOrder(orderId,x,y,null)
    endmethod
endstruct

private function CheckOrders_Child takes nothing returns nothing
    local unit u = GetEnumUnit()
    local UnitData dat = GetUnitUserData(u)
    local Order o
    if GetUnitCurrentOrder(u) == 0 then //I think the null order is 0... or is it "stop"?
        set o = dat.first
        call o.Issue(u)
        set dat.first = o.next
        call o.destroy()
    endif
    set u = null
endfunction

private function CheckOrders takes nothing returns nothing
    call ForGroup(oq_queuedUnits,function CheckOrders_Child)
endfunction

private function init takes nothing returns nothing
    call TimerStart(CreateTimer(),.25,true,function CheckOrders)//change interval as you will; the higher, the less lag, the lower, the more precise.
endfunction
endlibrary
 
Last edited:
Level 10
Joined
Oct 2, 2005
Messages
398
I was travelling, I do need it.
About the value, I use WEU, and you can use the Unit Custom String Value, if necessary, but I need like 50 characters of it for personal use, the system can go since the 51 ahead.
The system sounds good, thank you so much for doing it. I can someway understand it, but I will need a demo of usage... xD
 
Status
Not open for further replies.
Top