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

[General] TimeStop that does not cancel channelling

Status
Not open for further replies.
Level 7
Joined
Feb 9, 2021
Messages
301
Is there a way to "stun" the unit without cancelling its channelling for the purpose of time stop?

I found this: [System] PreventOrders , but there are a couple of problems with it:
(1) A bug: I can't activate the unit back
(2) It does not stop immediate orders (berserk, mana shield)

I changed only Unit Indexer, so I don't think I fcked something up:

JASS:
library PreventOrders initializer Init requires UnitIndexer
    private keyword Data
 
    globals
        private timer       Tim         = CreateTimer()
        private Data array  CancelStack
        private integer     CancelCount = 0
        private hashtable   Hash        = InitHashtable()
     
        private constant integer ORDER_STOP = 851972
     
        // Purely for debugging purposes, this displays when an order is prevented
        private constant boolean DISPLAY_PREVENTED_ORDERS = false
        // Set this to true to make units keep their old orders rather than simply stopping when an order is prevented
        private constant boolean RETAIN_PREVIOUS_ORDERS   = false
    endglobals
 
    private function DebugMsg takes string unitName, string orderType, string orderString returns nothing
        debug static if DISPLAY_PREVENTED_ORDERS then
        debug     call BJDebugMsg("PreventOrders: Prevented " + unitName + " from being issued a" + orderType + " " + orderString + " order")
        debug endif
    endfunction
 
    private struct Data extends array
        static constant integer IMMEDIATE = 1
        static constant integer POINT     = 2
        static constant integer TARGET    = 3
     
     
        unit u
        boolean i
        boolean p
        boolean t
     
        boolean doNext
     
        integer lastOrderType
        integer lastOrderId
        widget  lastOrderTargetW
        real    lastOrderTargetX
        real    lastOrderTargetY
        boolean cancel
     
        method lastImmediateOrder takes integer id returns nothing
            set lastOrderType = IMMEDIATE
            set lastOrderId   = id
        endmethod
     
        method lastPointOrder takes integer id, real x, real y returns nothing
            set lastOrderType    = POINT
            set lastOrderId      = id
            set lastOrderTargetX = x
            set lastOrderTargetY = y
        endmethod
     
        method lastTargetOrder takes integer id, widget target returns nothing
            set lastOrderType    = TARGET
            set lastOrderId      = id
            set lastOrderTargetW = target
        endmethod
     
        method doLastOrder takes nothing returns nothing
            if cancel then
                set doNext = true
                call IssueImmediateOrderById(u, ORDER_STOP)
            else
                if     lastOrderType == IMMEDIATE then
                    set doNext = true
                    call IssueImmediateOrderById(u, lastOrderId)
                elseif lastOrderType == POINT then
                    set doNext = true
                    call IssuePointOrderById(u, lastOrderId, lastOrderTargetX, lastOrderTargetY)
                elseif lastOrderType == TARGET then
                    set doNext = true
                    call IssueTargetOrderById(u, lastOrderId, lastOrderTargetW)
                else
                    set doNext = true
                    call IssueImmediateOrderById(u, ORDER_STOP)
                endif
            endif
        endmethod
     
        method assign takes unit whichUnit returns nothing
            set u = whichUnit
        endmethod
     
        method destroy takes nothing returns nothing
            call FlushChildHashtable(Hash, this)

            set u = null
            set i = false
            set p = false
            set t = false
         
            set doNext = false
         
            set lastOrderType = 0
            set cancel        = false
        endmethod
    endstruct
 
    private function Cancel takes nothing returns nothing
        loop
            set CancelCount = CancelCount - 1
            static if RETAIN_PREVIOUS_ORDERS then
                call CancelStack[CancelCount].doLastOrder()
            else
                set CancelStack[CancelCount].doNext = true
                call IssueImmediateOrderById(CancelStack[CancelCount].u, ORDER_STOP)
            endif
            exitwhen CancelCount == 0
        endloop
    endfunction
 
    private function PreventCurrentOrderFromData takes Data d returns nothing
        if CancelCount == 0 then
            call TimerStart(Tim, 0., false, function Cancel)
        endif
        set CancelStack[CancelCount] = d
        set CancelCount = CancelCount + 1
    endfunction
 
    function PreventCurrentOrder takes unit u returns nothing
        call PreventCurrentOrderFromData(Data[GetUnitId(u)])
    endfunction
 
    function CancelOrders takes unit u returns nothing
        local Data d = Data[GetUnitId(u)]
        static if RETAIN_PREVIOUS_ORDERS then
            set d.cancel = true
        endif
        call PreventCurrentOrderFromData(d)
    endfunction
 
    function PreventOrders takes unit u, boolean i, boolean p, boolean t returns nothing
        local Data d = Data[GetUnitId(u)]
     
        if i or p or t then
            set d.i = i
            set d.p = p
            set d.t = t
        endif
    endfunction
 
    function PreventSpecificOrderById takes unit u, integer orderId, boolean prevent returns nothing
        local Data d = Data[GetUnitId(u)]
     
        if orderId != 0 then
            if prevent then
                call SaveBoolean(Hash, d, orderId, true)
            elseif d != 0 then
                call SaveBoolean(Hash, d, orderId, false)
            endif
        endif
    endfunction
 
    function PreventSpecificOrder takes unit u, string order, boolean prevent returns nothing
        call PreventSpecificOrderById(u, OrderId(order), prevent)
    endfunction
 
    function ClearSpecificOrderPreventionById takes unit u, integer orderId returns nothing
        local Data d = Data[GetUnitId(u)]
     
        if orderId != 0 and orderId != ORDER_STOP then
            call RemoveSavedBoolean(Hash, d, orderId)
        endif
    endfunction
 
    function ClearSpecificOrderPrevention takes unit u, string order returns nothing
        call ClearSpecificOrderPreventionById(u, OrderId(order))
    endfunction
 
    function ClearAllSpecificOrderPrevention takes unit u returns nothing
        local Data d = Data[GetUnitId(u)]
        call FlushChildHashtable(Hash, d)
    endfunction
 
    function AllowNextOrder takes unit u returns nothing
        local Data d = Data[GetUnitId(u)]
        set d.doNext = true
    endfunction
 
    private function ImmediateOrder takes nothing returns boolean
        local unit u = GetTriggerUnit()
        local Data d = Data[GetUnitId(u)]
        local integer i = GetIssuedOrderId()
     
        if d.doNext then
            set d.doNext = false
            call d.lastImmediateOrder(i)
        else
            if d.i then
                if (not HaveSavedBoolean(Hash, d, i)) or (LoadBoolean(Hash, d, i)) then
                    call PreventCurrentOrderFromData(d)
                    debug call DebugMsg(GetUnitName(u), "n immediate", OrderId2String(i))
                else
                    static if RETAIN_PREVIOUS_ORDERS then
                        call d.lastImmediateOrder(i)
                    endif
                endif
            elseif LoadBoolean(Hash, d, i) then
                call PreventCurrentOrderFromData(d)
                debug call DebugMsg(GetUnitName(u), "n immediate", OrderId2String(i))
            else
                static if RETAIN_PREVIOUS_ORDERS then
                    call d.lastImmediateOrder(i)
                endif
            endif
        endif
     
        set u = null
     
        return false
    endfunction
 
    private function PointOrder takes nothing returns boolean
        local unit u    = GetTriggerUnit()
        local Data d    = Data[GetUnitId(u)]
        local integer i = GetIssuedOrderId()
     
        if d.doNext then
            set d.doNext = false
            call d.lastPointOrder(i, GetOrderPointX(), GetOrderPointY())
        else
            if d.p then
                if (not HaveSavedBoolean(Hash, d, i)) or (LoadBoolean(Hash, d, i)) then
                 
                    call PreventCurrentOrderFromData(d)
                    debug call DebugMsg(GetUnitName(u), " point", OrderId2String(i))
                else
                    static if RETAIN_PREVIOUS_ORDERS then
                        call d.lastPointOrder(i, GetOrderPointX(), GetOrderPointY())
                    endif
                endif
            elseif LoadBoolean(Hash, d, i) then
                call PreventCurrentOrderFromData(d)
                debug call DebugMsg(GetUnitName(u), " point", OrderId2String(i))
            else
                static if RETAIN_PREVIOUS_ORDERS then
                    call d.lastPointOrder(i, GetOrderPointX(), GetOrderPointY())
                endif
            endif
        endif
     
        set u = null
     
        return false
    endfunction
 
    private function TargetOrder takes nothing returns boolean
        local unit u    = GetTriggerUnit()
        local Data d    = Data[GetUnitId(u)]
        local integer i = GetIssuedOrderId()
     
        if d.doNext then
            set d.doNext = false
            call d.lastTargetOrder(i, GetOrderTarget())
        else
            if d.t then
                if (not HaveSavedBoolean(Hash, d, i)) or (LoadBoolean(Hash, d, i)) then
                    call PreventCurrentOrderFromData(d)
                    debug call DebugMsg(GetUnitName(u), " target", OrderId2String(i))
                else
                    static if RETAIN_PREVIOUS_ORDERS then
                        call d.lastTargetOrder(i, GetOrderTarget())
                    endif
                endif
            elseif LoadBoolean(Hash, d, i) then
                call PreventCurrentOrderFromData(d)
                debug call DebugMsg(GetUnitName(u), " target", OrderId2String(i))
            else
                static if RETAIN_PREVIOUS_ORDERS then
                    call d.lastTargetOrder(i, GetOrderTarget())
                endif
            endif
        endif
     
        set u = null
     
        return false
    endfunction
 
    private function onUnitIndex takes nothing returns nothing
        local Data d = Data[UnitIndexer.eventIndex]
        call d.assign(UnitIndexer.eventUnit)
    endfunction
 
    private function onUnitDeindex takes nothing returns nothing
        local Data d = Data[UnitIndexer.eventIndex]
        call d.destroy()
    endfunction
 
 
    private function Init takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_ORDER)
        call TriggerAddCondition(t, Condition(function ImmediateOrder))
     
        set t = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER)
        call TriggerAddCondition(t, Condition(function PointOrder))
     
        set t = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER)
        call TriggerAddCondition(t, Condition(function TargetOrder))
     
        call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function onUnitIndex))
        call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function onUnitDeindex))
    endfunction
endlibrary
 
Last edited:
Level 7
Joined
Feb 9, 2021
Messages
301
I don't think this is possible without triggering your own channeling system. That being said, it wouldn't be too difficult to do so and could open up some doors to more possibilities.
What about preventing orders? If this library can be fixed + Stopping unit from casting instant abilities solution for the instant cast, then it can work. However, I am not sure what the problem is with the library.

What do you mean by channelling system?
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,513
I don't think that library will work for channeling spells but you can try.

I mean that you trigger your own system to handle casting spells. So you play the cast animation yourself, start your own "cast time" Timer, etc. Then you could simply pause the Timer/Animation Speed when a unit becomes frozen in time and resume them once the unit is freed from this effect.
 
Level 7
Joined
Feb 9, 2021
Messages
301
I don't think that library will work for channeling spells but you can try.

I mean that you trigger your own system to handle casting spells. So you play the cast animation yourself, start your own "cast time" Timer, etc. Then you could simply pause the Timer/Animation Speed when a unit becomes frozen in time and resume them once the unit is freed from this effect.
You are right, it does not work.

Well, it actually stops the unit and does not interrupt the cast, but if the target clicks, then the spell is cancelled. I think this might be good enough? The problem is I can't "unpause" the unit.

In the channelling system, how do you catch that the cast was interrupted?
 
Last edited:

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,513
The way I imagined the system to work was that you would simply restart the casting process once the unit became unfrozen.

So the channeled ability would get interrupted, but the unit would begin casting it again the moment it became unfrozen and since the whole system is triggered you would have control over animations/durations of things. Mind you, you'd want to design your entire map around this system.

I've done something like this before in Lua. I had it setup so that each spell had it's own unique Cast Backswing/Cast Point instead of having to rely on the Unit's static values for these. I could also dynamically change these values (stats like increased casting speed come to mind) and create custom animations for each ability using Animation Index.
 
Status
Not open for further replies.
Top