- Joined
- Jan 30, 2013
- Messages
- 12,762
How does this stun system works internally?
(0 ratings)
/*
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
ORDER_ID = 852239
<- kindly input a prefix or comment of its string equivalent.I can't test this in-game but...
"A simple stun system that uses a method no other system uses."
What method exactly?
"Has no limitation on which targets may be stunned and plays nice with default stun mechanics."
I don't think you're sure about this judging on the script,
I wouldn't dive through optimizations as I'm just curious;
ORDER_ID = 852239
<- kindly input a prefix or comment of its string equivalent.
I don't see any stomp or thunderbolt methods here so I guess you're ordering a unit to simulate a fake stun via infinite channel,
Which is not the same mechanics for original stun, in case I'm not wrong about this. However, If this is correct then it's limited. :]
Besides, we have dozens of this system already, each with bugs and limitations, as this can't be doable perfectly of bug-free yet.
How does this stun system works internally?
No Object Editor abilities needed right?
CorrectAside from the 'STUN' ability the system comes with, nope.
Considering the mechanics behind the stun action, this would disrupt shift-queued orders, which regular stuns normally respect.
Follow through time infinite and disable other abilities = trueAh, what's the difference with the normal channel then? The latest version prevents older editors from opening the map as far as I am aware.
Possibly, if it uses channel as the ability cast. I'm away from my computer rn so I can't check.Maybe it's similar to [vJASS] - [Snippet] SuspendUnit.
Possibly, if it uses channel as the ability cast. I'm away from my computer rn so I can't check.
Tested it or not, the logic of ordering a unit itself to simulate a stun-like mechanic to itself is already prone to fail at some cases.I've tested it quite extensively and have not found any issues thus far.
This system accounts for failed casts. But valid points beyond that.Tested it or not, the logic of ordering a unit itself to simulate a stun-like mechanic to itself is already prone to fail at some cases.
Plus, this breaks the order rather than retaining it, it also blacks out the command card which is not the case for original stun...
I kinda disapprove the method you chose for stunning units, it would be good for pausing units though, which is already known.
While it's a good thing you've taken it into consideration, I don't think it would be good enough for the unit's inability to execute the order.This system accounts for failed casts.
It's a fine idea but not that reliable to replace or at least simulate a stun. Before making a public system make sure to check for the others.Here I thought this was an original idea lol. I can make a list of pro/cons of using this method if the system won't be outright rejected.
Very fair points. You're right, I had not considered silence. Maybe I'll rework this with another method I was considering.While it's a good thing you've taken it into consideration, I don't think it would be good enough for the unit's inability to execute the order.
Take this for sleeping or silenced units for example, they couldn't execute an order from their state which would just generate an overhead.
A timer runs as they couldn't execute an order and would only be destroyed if the order is successful, otherwise if duration elapsed it'll linger.
It's a fine idea but not that reliable to replace or at least simulate a stun. Before making a public system make sure to check for the others.
You may stick to this and wait for the moderator's verdict or at least update it with exemplary features that would make it shine from the rest.
(These statements are just my point of view though. Just criticizing this as I'm just curious on what method you've done here in the first place)
Yeah, I've also read that from somewhere else claiming it. I didn't tested it yet but you may try it here and then prove if it works. (I hope so)silence does not affect channel if it has universal cast enabled
Didn't notice you're destroying two timers even the other one is only created if a condition is met, otherwise you're destroying a non-existent.Also the timer at the moment does not linger, it is destroyed when the duration ends.
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"Destroying a null timer is less computationally taxing then checking a comparison then destruction imo. , it may not be for this scenario
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.(And credit IcemanBo)
It wouldn't overwrite if the concatenated 'or' checks for the stun removal obviously, which makes your code shorter and logical.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.
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.what exact scenario bugs.
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.
I attempted a work around using BlzUnitDisableAbility and BlzUnitHideAbility but it appears to hard code lock abilities from being cast during these cases.
Only problem with pauseunit is that it pauses buffs afaik
PauseUnit
I am talking about. BlzPauseUnitEx
can stop a unit in its tracks, while respecting shift-queue orders, and leaves ordinary buffs untouched.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
.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 lolIt's not the ordinaryPauseUnit
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 callingBlzPauseUnitEx
.
That's interesting and didn't know that native even existed. In what patch it's introduced anyway?It's not the ordinaryPauseUnit
I am talking about.BlzPauseUnitEx
can stop a unit in its tracks, while respecting shift-queue orders, and leaves ordinary buffs untouched.
It's also notable that it pauses expiration timer of unit which is kinda minor but impacts gameplay.Empirically,PauseUnit
also disables all abilities a desired unit has, which breaks shift-queue orders
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.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
BlzPauseUnitEx
native yields perfectly the same as this method results then I think it's better to deprecate the method.The whole method is flawed in the first place, make sure to test this on illusion, polymorphed or even militia units.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.
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.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, ifBlzPauseUnitEx
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.
I don't see how this system is flawed considering it is able to handle every scenario thus far.
make sure to test this on illusion, polymorphed or even militia units.
I don't know why you're claiming it would conflict to others as it's counter-based native.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.
BlzPauseUnitEx
works just like stun (just make it timed + overhead effect and you're done)I don't know why you're going in that direction as you should be focusing on resolving the problems with your method.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.
BlzPauseUnitEx
native.make sure to test this on illusion, polymorphed or even militia units.