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 havn't received your rank award? Then please contact the administration.
    Dismiss Notice
  3. We have recently started the 16th edition of the Mini Mapping Contest. The theme is mini RPG. Do check it out and have fun.
    Dismiss Notice
  4. Choose your ride to damnation in the 5th Special Effect Contest Poll.
    Dismiss Notice
  5. The winners of the 13th Techtree Contest have been announced!
    Dismiss Notice
  6. The 13th Music Contest Poll is up! Vote for the best tracks in this symphony of frost and flame.
    Dismiss Notice
  7. Race against the odds and Reforge, Don't Refund. The 14th Techtree Contest has begun!
    Dismiss Notice
  8. 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.

[vJASS] DisableAutocast

Discussion in 'Submissions' started by busterkomo, Jan 4, 2019.

  1. busterkomo

    busterkomo

    Joined:
    Jun 17, 2007
    Messages:
    1,423
    Resources:
    1
    Tutorials:
    1
    Resources:
    1
    Sometimes it can be useful to disable the auto-casting of certain abilities. For example, you may have a custom Searing Arrows ability that has a cooldown. Unfortunately, the auto-casting of it does not properly trigger the cooldown (and I believe has other issues relating to things like range). I haven't written vJASS in ~8 years, so maybe my approach is terrible or outdated, but it seems fine to me.

    This API is simple:
    Code (vJASS):
    function DisableAutocast takes integer activateOrder, integer deactivateOrder returns nothing

    where 'activateOrder' is the order id to enable auto-casting, and 'deactivateOrder' is the order to turn it off. For example,
    Code (vJASS):
    call DisableAutocast(852067, 852068)
     
    prevents Inner Fire from being autocast.


    Code (vJASS):

    library DisableAutocast initializer Init requires TimerUtils, Table

    globals
        private Table table
    endglobals

    private struct DisableData
        unit u
        integer deactivateOrder

        static method create takes unit u, integer deactivateOrder returns DisableData
            local DisableData this = DisableData.allocate()

            set this.u = u
            set this.deactivateOrder = deactivateOrder

            return this
        endmethod
    endstruct

    private function Callback takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local DisableData d = GetTimerData(t)
        call IssueImmediateOrderById(d.u, d.deactivateOrder)
        call ReleaseTimer(t)
        call d.destroy()

        set t = null
    endfunction

    private function Actions takes nothing returns nothing
        local timer t
        local DisableData d
        local integer orderId = GetIssuedOrderId()

        if table.exists(orderId) then
            set t = NewTimer()
            set d = DisableData.create(GetTriggerUnit(), table[orderId])
            call SetTimerData(t, d)
            call TimerStart(t, 0., false, function Callback)
            set t = null
        endif
    endfunction

    function DisableAutocast takes integer activateOrder, integer deactivateOrder returns nothing
        set table[activateOrder] = deactivateOrder
    endfunction

    public function Init takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_ORDER)
        call TriggerAddAction(t, function Actions)
        set table = Table.create()
    endfunction

    endlibrary
     
     
  2. Jampion

    Jampion

    JASS Reviewer

    Joined:
    Mar 25, 2016
    Messages:
    1,287
    Resources:
    0
    Resources:
    0
    You should include some documentation, especially some information and links about the required libraries, even if they are common ones in this case.
    The table library you are using is outdated. You should use this one: [Snippet] New Table
    It has a backwards compatibility snippet, but for new resources one should use the new table.

    It would be nice to be able to use order strings as well. You could follow the JASS naming convention for orders and have DisableAutocast and DisableAutocastById.


    There are 2 side effects when you use this. The unit is being stopped and all its orders are canceled. Usually toggling autocast is instant and does not interrupt orders.
    Other currently active autocast effects are turned off.

    Does this have use outside of arrow abilities? Other autocast abilities can usually be emulated by using some non-autocast ability and a dummy ability to apply the effect.

    Arrow abilities allow you to attack from further away, if you cast them manually and cast range is greater than the attack range of the unit.
     
  3. busterkomo

    busterkomo

    Joined:
    Jun 17, 2007
    Messages:
    1,423
    Resources:
    1
    Tutorials:
    1
    Resources:
    1
    Nice feedback, I'll try to update this sometime in the next week or so.
     
  4. Jampion

    Jampion

    JASS Reviewer

    Joined:
    Mar 25, 2016
    Messages:
    1,287
    Resources:
    0
    Resources:
    0
    Are you still planning to update this?
     
  5. Bribe

    Bribe

    Joined:
    Sep 26, 2009
    Messages:
    8,126
    Resources:
    25
    Maps:
    3
    Spells:
    10
    Tutorials:
    3
    JASS:
    9
    Resources:
    25
    This doesn't need TimerUtils. Just use one single timer but with a singly linked list or simple stack in order to loop the active autocast instances after expiration.
     
  6. Bribe

    Bribe

    Joined:
    Sep 26, 2009
    Messages:
    8,126
    Resources:
    25
    Maps:
    3
    Spells:
    10
    Tutorials:
    3
    JASS:
    9
    Resources:
    25
    Here's the most simplified version possible
    Code (vJASS):

    library DisableAutocast requires Table

    globals
        private Table table = 0
        private integer n = 0
        private unit array units
        private integer array deactivateOrder
        private timer tick = CreateTimer()
    endglobals

    private function Callback takes nothing returns nothing
        local integer i = 0
        loop
            exitwhen i == n
            call IssueImmediateOrderById(units[i], deactivateOrder[i])
            set i = i + 1
        endloop
        set n = 0
    endfunction

    private function Actions takes nothing returns boolean
        local integer orderId = table[GetIssuedOrderId()]
       
        if orderId != 0 then
            set units[n] = GetTriggerUnit()
            set deactivateOrder[n] = orderId
            if n == 0 then
                call TimerStart(tick, 0.00, false, function Callback)
            endif
            set n = n + 1
        endif
        return false
    endfunction

    function DisableAutocast takes integer activateOrder, integer deactivateOrder returns nothing
        local trigger t
        if table == 0 then
            set t = CreateTrigger()
            call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_ORDER)
            call TriggerAddCondition(t, Filter(function Actions))
            set table = Table.create()
        endif
        set table[activateOrder] = deactivateOrder
    endfunction

    endlibrary