1. Are you planning to upload your awesome spell or system to Hive? Please review the rules here.
    Dismiss Notice
  2. Head to the 33rd Modeling Contest Poll and drink to your heart's desire.
    Dismiss Notice
  3. Choose your means of doom in the 17th Mini Mapping Contest Poll.
    Dismiss Notice
  4. A slave to two rhythms, the 22nd Terraining Contest is here.
    Dismiss Notice
  5. The heavens smile on the old faithful. The 16th Techtree Contest has begun.
    Dismiss Notice
  6. The die is cast - the 6th Melee Mapping Contest results have been announced. Onward to the Hive Cup!
    Dismiss Notice
  7. The glory of the 20th Icon Contest is yours for the taking!
    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.

Stun System 1.12

Submitted by maddeem
This bundle is marked as substandard. It may contain bugs, not perform optimally or otherwise be in violation of the submission rules.
A channel based stun system.

Pros:
Can be used on any unit or structure, irregardless of invulnerability or status.

Creates one (non periodic) timer for tracking duration & one trigger to track orders (stun, pause, sleep etc). Effectively making it very computationally light.

Cons:
Interrupts orders

Documentation & Code
Code (vJASS):

/*
STUN SYSTEM 1.12
Credits to Maker & IcemanBo for the original concept

API DOCUMENTATION:

public function Unit takes unit u, real dur, boolean stacks returns nothing
    - Stuns a unit using a real duration and boolean for duration stacking.

    - For non-stacking & multiple applications, the highest duration will be applied.

public function End takes unit u returns nothing
    - Immediately ends a stun on a unit.

public function SetRemaining takes unit u, real dur returns nothing
    - Sets the direct duration of a stun.

public function GetRemaining takes unit u returns real
    - Gets the remaining stun duration.

function IsUnitStunned takes unit u returns boolean
    - Returns a unit's stun status.
*/


library Stun initializer init
    globals
        private constant integer SPELL_ID = 'STUN'
        private constant integer ORDER_ID = 852239 //String Order: "request_hero"
        private constant hashtable HASHTABLE = InitHashtable()
        private constant string EFFECT = "Abilities\\Spells\\Human\\Thunderclap\\ThunderclapTarget"
        private constant string EFFECT_POINT = "overhead"
        private timer TIMER
        private conditionfunc CONDITION
    endglobals

    public function End takes unit u returns nothing
        local integer unitId = GetHandleId(u)
        local timer t= LoadTimerHandle(HASHTABLE, unitId, 1)
        local integer timerId = GetHandleId(t)
        local trigger trig = LoadTriggerHandle(HASHTABLE, unitId, 2)
        call DestroyEffect(LoadEffectHandle(HASHTABLE, unitId, 3))
        call FlushChildHashtable(HASHTABLE, timerId)
        call DestroyTimer(t)
        call TriggerClearConditions(trig)
        call DestroyTrigger(trig)
        call FlushChildHashtable(HASHTABLE, unitId)
        call UnitRemoveAbility(u,SPELL_ID)
        set t = null
    endfunction

    private function Elapsed takes nothing returns nothing
        call End(LoadUnitHandle(HASHTABLE, GetHandleId(GetExpiredTimer()), 0))
    endfunction

    private function OrderCheck takes nothing returns boolean
        local trigger trig = GetTriggeringTrigger()
        call DisableTrigger(trig)
        call IssueImmediateOrderById(GetTriggerUnit(), ORDER_ID)
        call EnableTrigger(trig)
        set trig = null
        return false
    endfunction

    public function Unit takes unit u, real dur, boolean stacks returns nothing
        local timer t
        local trigger trig
        local real stunRemain
        local integer unitId = GetHandleId(u)
        local integer i = 0
        if LoadBoolean(HASHTABLE,unitId,0) then
            set t = LoadTimerHandle(HASHTABLE, unitId, 1)
            set stunRemain = TimerGetRemaining(t) - TimerGetElapsed(t)
            call PauseTimer(t)
            if stacks then
                set stunRemain = stunRemain + dur
            elseif stunRemain < dur then
                set stunRemain = dur
            endif
            call TimerStart(t, stunRemain, false, function Elapsed)
        else
            call UnitAddAbility(u,SPELL_ID)
            call IssueImmediateOrder(u,"stop")
            call BlzUnitDisableAbility(u, SPELL_ID, false, false)
            call IssueImmediateOrderById(u, ORDER_ID)
            set trig = CreateTrigger()
            call TriggerRegisterUnitEvent(trig, u, EVENT_UNIT_ISSUED_ORDER )
            call TriggerAddCondition(trig, CONDITION)
            set t = CreateTimer()
            call SaveBoolean(HASHTABLE, unitId, 0, true)
            call SaveTimerHandle(HASHTABLE, unitId, 1, t)
            call SaveTriggerHandle(HASHTABLE, unitId, 2, trig)
            call SaveEffectHandle(HASHTABLE, unitId, 3, AddSpecialEffectTarget(EFFECT,u,EFFECT_POINT))
            call SaveUnitHandle(HASHTABLE, GetHandleId(t),0,u)
            call TimerStart(t, dur, false, function Elapsed)
        endif
        set t = null
        set trig = null
    endfunction

    public function SetRemaining takes unit u, real dur returns nothing
        local timer t= LoadTimerHandle(HASHTABLE, GetHandleId(u), 1)
        call PauseTimer(t)
        call TimerStart(t, dur, false, function Elapsed)
        set t = null
    endfunction

    function IsUnitStunned takes unit u returns boolean
        return LoadBoolean(HASHTABLE, GetHandleId(u),0)
    endfunction

    public function GetRemaining takes unit u returns real
        set TIMER = LoadTimerHandle(HASHTABLE, GetHandleId(u), 1)
        return TimerGetRemaining(TIMER) - TimerGetElapsed(TIMER)
    endfunction

    private function init takes nothing returns nothing
        set CONDITION = Condition( function OrderCheck)
    endfunction
endlibrary
 
Contents

Stun System 1.12 (Map)

  1. JAKEZINC

    JAKEZINC

    Joined:
    Aug 13, 2013
    Messages:
    1,615
    Resources:
    9
    Spells:
    9
    Resources:
    9
    It's not about performance, it's just a bad practice. I mean you already stated the obvious: "But seeing as missed casts may be rare"
    Hence, the timer should only be destroyed if it's created, what's inside the script: destruction of it always while creation of it depends.

    EDIT:

    You can even merge the destruction of that periodic timer with an extra 'or' check inside the OrderCheck function by the way.
     
    Last edited: Aug 5, 2020
  2. maddeem

    maddeem

    Joined:
    Jan 1, 2011
    Messages:
    1,324
    Resources:
    6
    Icons:
    1
    Maps:
    2
    Spells:
    3
    Resources:
    6
    Adding an or check to a 0.03125 timer increases computation unnecessarily versus passing a null to destroy timer once. Also if a stun is removed, a new instance (within the period) would potentially overwrite the pre-existing timer.

    I'm all about performance
     
    Last edited: Aug 6, 2020
  3. IcemanBo

    IcemanBo

    Joined:
    Sep 6, 2013
    Messages:
    6,532
    Resources:
    23
    Maps:
    3
    Spells:
    11
    Template:
    1
    Tutorials:
    5
    JASS:
    3
    Resources:
    23
    In my resource, back then at least I could not really verfiy Bribe's claim with silence, so I'm not sure, too. He didn't also provide demo code when I asked, so idk if someone has shown what exact scenario bugs.
    You might read the linked thread for pro/contra which was stated, but not really need to credit me. Though thanks. : ) I also just saw Maker once doing it, and submitted the method as resource.
     
  4. JAKEZINC

    JAKEZINC

    Joined:
    Aug 13, 2013
    Messages:
    1,615
    Resources:
    9
    Spells:
    9
    Resources:
    9
    It wouldn't overwrite if the concatenated 'or' checks for the stun removal obviously, which makes your code shorter and logical.
    You shouldn't worry much of the performance anyway, I don't even think such comparison impacts performance. (it's negligible)
    Safety > Functionality > Performance (cause honestly it just looks like you're removing a unit that doesn't even exist or created)

    But yeah I couldn't persuade you, it's your choice anyways as this is your resource. It's always up to the moderator in the end. :]

    Ordering a unit to cast an ability that's silenced wouldn't work, casting silence on a unit that's currently channeling also breaks it.
     
  5. MyPad

    MyPad

    Spell Reviewer

    Joined:
    May 9, 2014
    Messages:
    1,526
    Resources:
    9
    Models:
    1
    Icons:
    2
    Maps:
    2
    Spells:
    3
    JASS:
    1
    Resources:
    9
    Posting a video verifying the first half of the quote above. (tested in Reforged)
     
  6. maddeem

    maddeem

    Joined:
    Jan 1, 2011
    Messages:
    1,324
    Resources:
    6
    Icons:
    1
    Maps:
    2
    Spells:
    3
    Resources:
    6
    Update 1.10:
    Fixed silence issues.
    Now it only uses a trigger to track when to apply the ability.
    Added credits.
    Added pros & cons.
    Demo map now stun selected unit when pressing esc.

    Edit:
    Added fringe case fix: units that train, upgrade or research wouldn't be stunned. So on every stun 7 cancel orders are issues. (This probably explains why buildings generally can't be stunned afaik). I attempted a work around using BlzUnitDisableAbility and BlzUnitHideAbility but it appears to hard code lock abilities from being cast during these cases.

    Edit 2:
    I've been trying to break this and it seems to hold up amazingly well so far. It even works with morph, which is totally surprising.
     
    Last edited: Aug 6, 2020
  7. MyPad

    MyPad

    Spell Reviewer

    Joined:
    May 9, 2014
    Messages:
    1,526
    Resources:
    9
    Models:
    1
    Icons:
    2
    Maps:
    2
    Spells:
    3
    JASS:
    1
    Resources:
    9
    Not only does the game disable most abilities a unit has when training another unit, it does so multiple times, corresponding to the number of units you force that particular unit to train. I remembered dealing with this scenario while creating my entries in techtree contests.

    I can suggest two approaches, the one using BlzUnitDisableAbility and another using BlzPauseUnitEx.

    The first approach:
    Try placing BlzUnitDisableAbility inside the loop. When successful, this will actually interrupt the training progress of buildings, as far as my tests go.

    The second approach:
    Just use BlzPauseUnitEx to simulate a stun. From my tests, this respects shift-queue orders, which was quite surprising.
     
  8. maddeem

    maddeem

    Joined:
    Jan 1, 2011
    Messages:
    1,324
    Resources:
    6
    Icons:
    1
    Maps:
    2
    Spells:
    3
    Resources:
    6
    Only problem with pauseunit is that it pauses buffs afaik
     
  9. MyPad

    MyPad

    Spell Reviewer

    Joined:
    May 9, 2014
    Messages:
    1,526
    Resources:
    9
    Models:
    1
    Icons:
    2
    Maps:
    2
    Spells:
    3
    JASS:
    1
    Resources:
    9
    It's not the ordinary
    PauseUnit
    I am talking about.
    BlzPauseUnitEx
    can stop a unit in its tracks, while respecting shift-queue orders, and leaves ordinary buffs untouched.

    Empirically,
    PauseUnit
    also disables all abilities a desired unit has, which breaks shift-queue orders, and also does the above. Internally, it must be calling
    BlzPauseUnitEx
    .
     
  10. maddeem

    maddeem

    Joined:
    Jan 1, 2011
    Messages:
    1,324
    Resources:
    6
    Icons:
    1
    Maps:
    2
    Spells:
    3
    Resources:
    6
    So I attempted to stack BlzUnitDisableAbility and that didn't work. BlzPauseUnitEx sounds like it would work just fine, but that removes all the clever hackery of this system lol

    Edit:
    Turns out BlzUnitDisableAbility has to have both boolean fields (disable & hide, set to false, because hide also disables abilities? lol)

    New version released with the fix (only one DisableAbility call is required even with multiple items in the queue)

    So now the only flaw remaining in this system is order interruption, which doesn't seem like a big deal imo, considering its a stun.
     
    Last edited: Aug 7, 2020
  11. JAKEZINC

    JAKEZINC

    Joined:
    Aug 13, 2013
    Messages:
    1,615
    Resources:
    9
    Spells:
    9
    Resources:
    9
    That's interesting and didn't know that native even existed. In what patch it's introduced anyway?
    It's also notable that it pauses expiration timer of unit which is kinda minor but impacts gameplay.
    I do also remember that it disrupts unit animations, particularly when it dies. (not sure about this)
    I don't see this method as a clever way of stunning units, it's been used for pausing units throughout the years and here you just screwed those resources that uses this kind of technique as an alternative to at least remedy pause/unpause side-effects. Imagine another resource that utilizes this kind of method and then suddenly uses it on a stunned unit by this system. It would cause conflict for those that made this without lock-safe.

    I would better call this a Pause System rather than a Stun System.

    Besides, if
    BlzPauseUnitEx
    native yields perfectly the same as this method results then I think it's better to deprecate the method.
    (which doesn't require ability object anymore and is much more robust as it doesn't require a unit to execute an order, and rendering it's safe)
    The whole method is flawed in the first place, make sure to test this on illusion, polymorphed or even militia units.
     
  12. maddeem

    maddeem

    Joined:
    Jan 1, 2011
    Messages:
    1,324
    Resources:
    6
    Icons:
    1
    Maps:
    2
    Spells:
    3
    Resources:
    6
    There is a lot going right for this system to be used as a stun. There are no periodic checks that loop through affected units. This means it is orders of magnitude more efficient & more accurate.

    Secondly I don't see how this system is flawed considering it is able to handle every scenario thus far.

    Thirdly, using BlzPauseUnitEx is far, far more likely to conflict with other systems and resources than this spell cast. Additionally, this method is pause/unpause safe.

    Fourthly, I'm going to be looking into the ability to cast certain spells w/ this method while under it's affects. (An ability for instance that can break a stun lock on cast) I already know for a fact that certain instant cast spells like berserk or divine shield would work... Effectively making it the only stun system which can have this mechanic.
     
  13. JAKEZINC

    JAKEZINC

    Joined:
    Aug 13, 2013
    Messages:
    1,615
    Resources:
    9
    Spells:
    9
    Resources:
    9
    I don't know why you're claiming it would conflict to others as it's counter-based native.

    BlzPauseUnitEx
    works just like stun (just make it timed + overhead effect and you're done)
    *should work for every units.
    *no more ability object.
    *no more executing of order.
    *no more checking of order.
    *no more blacking of command card.
    *no more interrupting of order.

    A perfect candidate to make one's life easy.
    I don't know why you're going in that direction as you should be focusing on resolving the problems with your method.
    The only options I could think of for this resource is to either rework it to Pause System or just use
    BlzPauseUnitEx
    native.

    Otherwise, I wouldn't bother with it anymore if you don't consider these options as I've already explained it all.
     
  14. maddeem

    maddeem

    Joined:
    Jan 1, 2011
    Messages:
    1,324
    Resources:
    6
    Icons:
    1
    Maps:
    2
    Spells:
    3
    Resources:
    6
    I'll try to explain it as best I can so you can understand. BlzPauseUnitEx and PauseUnit are widely used. Using either of these natives would cause collisions with other systems and maps that inherently use these natives already.

    This method is NOT widely used, therefore collision potential is insignificant.

    I don't even want to touch on the other "issues" because I think you need to acknowledge this first - and if you are unable to comprehend this, I would find it difficult to explain anything further.
     
  15. MyPad

    MyPad

    Spell Reviewer

    Joined:
    May 9, 2014
    Messages:
    1,526
    Resources:
    9
    Models:
    1
    Icons:
    2
    Maps:
    2
    Spells:
    3
    JASS:
    1
    Resources:
    9
    Created a test video on that, using the current version:


    It is quite notable that using the BlzPauseUnitEx approach will work on the cases where the current method normally fails.
     
  16. maddeem

    maddeem

    Joined:
    Jan 1, 2011
    Messages:
    1,324
    Resources:
    6
    Icons:
    1
    Maps:
    2
    Spells:
    3
    Resources:
    6
    Quite a nasty bug for those who use polymorph + channel in their map.

    I have another unorthodox method that'd I would like to try to implement.
     
  17. MyPad

    MyPad

    Spell Reviewer

    Joined:
    May 9, 2014
    Messages:
    1,526
    Resources:
    9
    Models:
    1
    Icons:
    2
    Maps:
    2
    Spells:
    3
    JASS:
    1
    Resources:
    9
    Moved to Substandard at the request of the author.