System Stun

Ayanami

칼리
Reaction score
288
JASS:

library StunSystem uses Table

//********************************************************************************
//              Stun - Version 1.2.0.0 - By iAyanami aka Ayanami
//********************************************************************************
//
//    Stun:
//         - An easy to use system that stuns units
//         - Able to keep track of the remaining stun duration
//
//    Requirements:
//         - JASS NewGen
//         - Table
//
//    Functions:
//         - Stun.apply takes unit whichUnit, real duration, boolean stack returns nothing
//           * whichUnit is the target to be stunned
//           * duration is the duration of the stun
//           * stack is to determine if the stun should be a stacking one or not
//           * true - the stun will stack, the duration of the stun will add up with the previous duration
//           * false - the stun will not stack, the unit will be stunned for the longer stun duration
//
//         - Stun.getDuration takes unit whichUnit returns real
//           * whichUnit is the target to check
//           * returns the remaining stun duration
//
//         - Stun.stop takes unit whichUnit returns nothing
//           * removes stun from the target
//
//    How to import:
//         - Copy the whole "Stun" Trigger Folder into your map
//         - Save the map. Close and re-opem the map.
//         - You should have a new unit (Stun Dummy), ability (Stun (System)) and buff (Stun (System)) created
//         - Read through the Configuration part of the code
//
//    Credits:
//         - Bribe for Table
//
//********************************************************************************
//                                CONFIGURABLES
//********************************************************************************

globals
    // timer period. lower the value, the more accurate but might cause decrease in
    // performance
    private constant real PERIOD = 0.03125

    // raw code of ability "Stun (System)"
    private constant integer ABILID = 'ASTN'
    
    // raw code of buff "Stun (System)"
    private constant integer BUFFID = 'BSTN'
    
    // raw code of unit "Stun Dummy"
    private constant integer STUNID = 'sTUN'
endglobals

//********************************************************************************
//                                     CODE
//********************************************************************************

// initialization
module Init
    private static method onInit takes nothing returns nothing
        set table = Table.create()
        set caster = CreateUnit(Player(13), STUNID, 0, 0, 0)
        
        call UnitAddAbility(caster, ABILID)
    endmethod
endmodule

struct Stun extends array
    private unit u
    private real dur

    private thistype next
    private thistype prev
    
    private static Table table
    private static timer t = CreateTimer()
    private static unit caster
    private static integer count = 0
    
    // remove the stun and deallocate
    private method destroy takes nothing returns nothing
        call UnitRemoveAbility(this.u, BUFFID)
        
        if this.next != 0 then
            set this.next.prev = this.prev
        endif
            
        set this.prev.next = this.next
        set this.dur = 0
        set this.prev = thistype(0).prev
        set thistype(0).prev = this
        
        if thistype(0).next == 0 then
            call PauseTimer(t)
        endif
            
        call table.remove(GetHandleId(this.u))
    endmethod
    
    // iterating through all instances every PERIOD
    private static method iterate takes nothing returns nothing
        local thistype this = thistype(0)
        
        loop
            set this = this.next
            exitwhen this == 0
            if this.dur <= 0 or IsUnitType(this.u, UNIT_TYPE_DEAD) or GetUnitTypeId(this.u) == 0 then
                call this.destroy()
            else
                set this.dur = this.dur - PERIOD
            endif
        endloop
    endmethod
    
    // immediately removes stun for the specified unit
    // ex: call Stun.stop(whichTarget)
    static method stop takes unit u returns nothing
        local integer id = GetHandleId(u)
        
        if table.has(id) then
            call thistype(table[id]).destroy()
        endif
    endmethod
    
    // gets the duration left for stun, not stunned units always return 0
    // ex: local real r = Stun.getDuration(whichTarget)
    static method getDuration takes unit u returns real
            return thistype(table[GetHandleId(u)]).dur
    endmethod
    
    // stunning specified target and to see if the stun is a stacking one or not
    // ex: call Stun.apply(whichTarget, 5.0, false)
    static method apply takes unit u, real dur, boolean b returns nothing
        local thistype this
        local integer id = GetHandleId(u)
        
        if table.has(id) then
            set this = table[id]
        else    
            if thistype(0).prev == 0 then
                set count = count + 1
                set this = count
            else
                set this = thistype(0).prev
                set thistype(0).prev = thistype(0).prev.prev
            endif
            
            if thistype(0).next == 0 then
                call TimerStart(t, PERIOD, true, function thistype.iterate)
            else
                set thistype(0).next.prev = this
            endif
            
            set this.next = thistype(0).next
            set thistype(0).next = this
            set this.prev = thistype(0)
            set table[id] = this
            set this.u = u
            set this.dur = 0
            
            call IssueTargetOrder(caster, "firebolt", this.u)
        endif
        
        if b and dur > 0 then
            set this.dur = this.dur + dur
        else
            if this.dur < dur then
                set this.dur = dur
            endif
        endif
    endmethod

    implement Init
endstruct

endlibrary


Examples:

Basic ability that stuns a target for 2.0 seconds and non-stacking.
Trigger:
  • Stun
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Stun
    • Actions
      • Custom script: call Stun.use(GetSpellTargetUnit(), 2.0, false)


This time, a more flexible stun. Stuns depending on the caster's agility and non-stacking.
Trigger:
  • Stun
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Stun
    • Actions
      • Set TempInt = (Agility of (Triggering unit) (Include bonuses))
      • Custom script: call Stun.use(GetSpellTargetUnit(), udg_TempInt, false)


Basic ability that stuns a target for 2.0 seconds and stacks.
Trigger:
  • Stun
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Stun
    • Actions
      • Set TempInt = (Agility of (Triggering unit) (Include bonuses))
      • Custom script: call Stun.use(GetSpellTargetUnit(), udg_TempInt, true)


Closing:
I'm open to any more possible functions that can be implemented into this system. Do suggest some. Thanks!

Changelogs:
Version 1.2.0.0:
- Removed Alloc
- Renamed .get to .getDuration
- Renamed .use to .apply
- Made a check to start/pause timer accordingly, rather than letting it run forever
- Added a GetUnitTypeId(this.u) == 0 check
- Used a module initializer
Version 1.1.0.0:
- Fixed minor bugs
- Renamed library to StunSystem
- Added a boolean parameter to Stun.use function to allow user to specify if the stun is a stacking one or not
- Added a new function, Stun.stop which removes stun from the specified unit
Version 1.0.0.0:
- Release.
 

luorax

Invasion in Duskwood
Reaction score
67
I haven't tested it yet, but seems it has a little problem:

If you stun your unit for 3 secs, and after 0.5 sec you stun it for 1 sec, the stun will be removed after 1 sec, because the duration has been overwritten, however the unit has to keep stunned for 1,5 more secs. You should fix it, like this:

Change this:
JASS:

static method use takes unit u, real dur returns nothing
        local thistype this
        local integer id = GetHandleId(u)
        
        if table.has(id) then
            set this = table[id]
        else    
            set this = thistype.allocate()
            set thistype(0).next.prev = this
            set this.next = thistype(0).next
            set thistype(0).next = this
            set this.prev = thistype(0)
            set table[id] = this
        endif
        
        set this.u = u
        set this.dur = dur
        
        call IssueTargetOrder(caster, "firebolt", this.u)
        
        set u = null
    endmethod


To this:
JASS:

static method use takes unit u, real dur returns nothing
        local thistype this
        local integer id = GetHandleId(u)
        
        if table.has(id) then
            set this = table[id]
        else    
            set this = thistype.allocate()
            set thistype(0).next.prev = this
            set this.next = thistype(0).next
            set thistype(0).next = this
            set this.prev = thistype(0)
            set table[id] = this
        endif
        
        set this.u = u
        if this.dur < dur then
            set this.dur = dur
        endif
        
        call IssueTargetOrder(caster, "firebolt", this.u)
        
        set u = null
    endmethod


And also, why do you use firebolt outside? You don't have to use it again if the unit is already stunned. It should be something like this:
JASS:

static method use takes unit u, real dur returns nothing
        local thistype this
        local integer id = GetHandleId(u)
        
        if table.has(id) then
            set this = table[id]
        else    
            set this = thistype.allocate()
            set thistype(0).next.prev = this
            set this.next = thistype(0).next
            set thistype(0).next = this
            set this.prev = thistype(0)
            set table[id] = this
            call IssueTargetOrder(caster, "firebolt", this.u)
            set this.u = u
        endif
        
        if this.dur < dur then
            set this.dur = dur
        endif
        
        set u = null
    endmethod
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
JASS:
if new>remaining then
    set new - remaining = extended
endif

Start the timer using remaining+extended.

JASS:

static method operator [] takes unit u returns real
    return TimerGetRemaining(thistype(table[GetHandleId(u)]).timer)
endmethod

This is better, don't you?

And also, you can use HandleTable instead, so that you don't have to use GetHandleId by yourself. :)
 

Ayanami

칼리
Reaction score
288
@ luorax

I always thought the newest stun would override the stun. Guess I was wrong xD

Will update soon. Thanks for the feedback.

EDIT
Updated to Version 1.1.0.0
 

tooltiperror

Super Moderator
Reaction score
231
Yeah, I think (as a site) we should move away from a bunch of small snippets and move to larger, standard scripts as WC3C does.

Status accomplishes this and does it in a standard way, so this is redundant.
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
I came up with something like this. :)
JASS:
library Stun initializer OnInit requires Table, TimerUtils, DummyCaster, Alloc
	
	globals
	    private constant integer ABIL_ID = 'ASTN'
	    private constant integer BUFF_ID = 'BSTN'
    	    private HandleTable Data
	endglobals
	
	struct Stun extends array
	    private unit u
       	    private timer t
		
	    implement Alloc
		
		static method operator [] takes unit u returns real
			return TimerGetRemaining(thistype(Data<u>).t)
		endmethod
		
		private static method onExpired takes nothing returns nothing
			local thistype this=GetTimerData(GetExpiredTimer())
			call UnitRemoveAbility(this.u,BUFF_ID)
			call Data.flush(this.u)
			call this.deallocate()
		endmethod
		
		static method operator []= takes unit u, real r returns nothing
			local thistype this=Data<u>
			if this==0 then
				set this=thistype.allocate()
				set this.t=NewTimer()
				call SetTimerData(this.t)
				set this.u=u
				set Data<u>=this
				call UnitAddAbility(DUMMY,ABIL_ID)
				call IssueTargetOrder(DUMMY,&quot;firebolt&quot;,u)
			endif
			if TimerGetRemaining(this.t)&lt;r then
				call TimerStart(this.t,r,true,function thistype.onExpired)
			endif
		endmethod
	endstruct
	
	private function OnInit takes nothing returns nothing
		set Data=HandleTable.create()
	endfunction
	
endlibrary</u></u></u>


JASS:

Stun[unit] -&gt; remaining time.
set Stun[unit]=10.0 -&gt; Add 10 seconds of stun to the unit.
 

tooltiperror

Super Moderator
Reaction score
231
I suppose this does have its uses, and the issues with it seem to be resolved.

When only using one status modification, this should suffice, for things bigger, use Status.

Approved.
 

Dirac

22710180
Reaction score
147
This library should use TimerUtils instead of iterating stuns using a pseudo-T32 interface

Also it does not need table, you can perfectly store Handles of units substracting the minimum handle value. Table should be used only for array variables inside structs
 
General chit-chat
Help Users
  • No one is chatting at the moment.
  • The Helper The Helper:
    I am great and it is fantastic to see you my friend!
    +1
  • The Helper The Helper:
    If you are new to the site please check out the Recipe and Food Forum https://www.thehelper.net/forums/recipes-and-food.220/
  • Monovertex Monovertex:
    How come you're so into recipes lately? Never saw this much interest in this topic in the old days of TH.net
  • Monovertex Monovertex:
    Hmm, how do I change my signature?
  • tom_mai78101 tom_mai78101:
    Signatures can be edit in your account profile. As for the old stuffs, I'm thinking it's because Blizzard is now under Microsoft, and because of Microsoft Xbox going the way it is, it's dreadful.
  • The Helper The Helper:
    I am not big on the recipes I am just promoting them - I use the site as a practice place promoting stuff
    +2
  • Monovertex Monovertex:
    @tom_mai78101 I must be blind. If I go on my profile I don't see any area to edit the signature; If I go to account details (settings) I don't see any signature area either.
  • The Helper The Helper:
    You can get there if you click the bell icon (alerts) and choose preferences from the bottom, signature will be in the menu on the left there https://www.thehelper.net/account/preferences
  • The Helper The Helper:
    I think I need to split the Sci/Tech news forum into 2 one for Science and one for Tech but I am hating all the moving of posts I would have to do
  • The Helper The Helper:
    What is up Old Mountain Shadow?
  • The Helper The Helper:
    Happy Thursday!
    +1
  • Varine Varine:
    Crazy how much 3d printing has come in the last few years. Sad that it's not as easily modifiable though
  • Varine Varine:
    I bought an Ender 3 during the pandemic and tinkered with it all the time. Just bought a Sovol, not as easy. I'm trying to make it use a different nozzle because I have a fuck ton of Volcanos, and they use what is basically a modified volcano that is just a smidge longer, and almost every part on this thing needs to be redone to make it work
  • Varine Varine:
    Luckily I have a 3d printer for that, I guess. But it's ridiculous. The regular volcanos are 21mm, these Sovol versions are about 23.5mm
  • Varine Varine:
    So, 2.5mm longer. But the thing that measures the bed is about 1.5mm above the nozzle, so if I swap it with a volcano then I'm 1mm behind it. So cool, new bracket to swap that, but THEN the fan shroud to direct air at the part is ALSO going to be .5mm to low, and so I need to redo that, but by doing that it is a little bit off where it should be blowing and it's throwing it at the heating block instead of the part, and fuck man
  • Varine Varine:
    I didn't realize they designed this entire thing to NOT be modded. I would have just got a fucking Bambu if I knew that, the whole point was I could fuck with this. And no one else makes shit for Sovol so I have to go through them, and they have... interesting pricing models. So I have a new extruder altogether that I'm taking apart and going to just design a whole new one to use my nozzles. Dumb design.
  • Varine Varine:
    Can't just buy a new heatblock, you need to get a whole hotend - so block, heater cartridge, thermistor, heatbreak, and nozzle. And they put this fucking paste in there so I can't take the thermistor or cartridge out with any ease, that's 30 dollars. Or you can get the whole extrudor with the direct driver AND that heatblock for like 50, but you still can't get any of it to come apart
  • Varine Varine:
    Partsbuilt has individual parts I found but they're expensive. I think I can get bits swapped around and make this work with generic shit though
  • Ghan Ghan:
    Heard Houston got hit pretty bad by storms last night. Hope all is well with TH.
  • The Helper The Helper:
    Power back on finally - all is good here no damage
    +2
  • V-SNES V-SNES:
    Happy Friday!
    +1
  • The Helper The Helper:
    New recipe is another summer dessert Berry and Peach Cheesecake - https://www.thehelper.net/threads/recipe-berry-and-peach-cheesecake.194169/

      The Helper Discord

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top