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

Fear System v3

Hi everyone,
Here is my first submission there.
It is a fear system.
What is a fear ? It is a crowd control that makes the target to move randomly while being unable to attack or get orders from the owner of the unit.

Here is the code (and the doc at the beggining) with Vex's Table or Bribe's Table.
Vexorian version :
JASS:
library FearSystem /* v3
************************************************************************************
*
*   */uses /*
*   
*       */ Table /*       http://www.wc3c.net/showthread.php?t=101246
*        //By Vexorian
*
************************************************************************************
*
*   struct Fear extends array
*
*       Description
*       -------------------------
*
*           This is a fear system; use it to remove player
*           control from a unit temporarily. Units affected
*           will also be unable to attack.
*
*       Fields
*       -------------------------
*
*           unit targ -> The unit you want to apply the fear.
* 
*           string path -> The path of the sfx you want to add to the unit.
*
*           string attach -> The attachment string you want the sfx to be on the unit
*
*           readonly effect e -> The effect currently applied to the unit.
*           Initializes to null
*
*       Methods
*       -------------------------
*
*           static method create takes nothing returns thistype
*           method destroy takes nothing returns nothing
*
*           method start takes nothing returns nothing
*           When you have set every parameters you start your fear instance.
*
*           method changeEffect takes string path, string attach returns nothing
*           If you already have set the effect of your instance and it is running
*           and you want to change it use this.
*
*           static method isFeared takes unit u returns boolean
*           static method get takes unit u returns thistype
*           
*       Operators
*       -------------------------
*
*           method operator time= takes real t returns nothing
*           method operator time takes nothing returns real
*
*       Credits
*       -------------------------
*
*           - Vexorian for vJASS and Table
*           - Maker for the DisableUnit function
*           - Bribe for Table
*           - Chobibo for the addition in the DisableUnit function/
*
************************************************************************************/
    native UnitAlive takes unit u returns boolean
    
    globals
        //There will be check every FPS second.
        private constant real FPS = 0.31250000
        //Feared units will change direction every EACH_CHANGE FPS.
        private constant integer EACH_CHANGE = 3
        //Feared units will go maximum in a circle of 150 around them each time they change direction.
        private constant real AROUND = 150.
        //The rawcode of the attack disable. Be sure it is the same in the Object Editor.
        private constant integer DISABLE_ATTACK = 'W000'
        //The rawcode of the morph. Be sure it is the same in the Object Editor.
        private constant integer MORPH_ID = 'Z001'
        //The rawcode of the bear form. Be sure it is the same in the Object Editor.
        private constant integer BEAR_ID = 'Z000'
    endglobals
    
    //The Table for Vexorian version
    globals
        private HandleTable tab
    endglobals

    
    private function round takes real r returns integer
        return R2I(r+0.5)
    endfunction
    
    private function modulo takes integer a, integer b returns integer
        return a - (a/b)*b
    endfunction
    
    //Credits to Maker for this awesum func <3
    private function DisableControl takes unit u returns nothing
        local boolean b
        call UnitAddAbility(u, 'Aloc')
        call UnitRemoveAbility(u, 'Aloc')
        if IsUnitType(u, UNIT_TYPE_HERO) then
            call UnitAddAbility(u,MORPH_ID)
            call IssueImmediateOrder(u, "metamorphosis")
            call UnitRemoveAbility(u,MORPH_ID)
        else
            call UnitAddAbility(u, BEAR_ID)
            call IssueImmediateOrder(u, "bearform")
            call UnitRemoveAbility(u, BEAR_ID)    
        endif
        //Thanks to chobibo for this idea
        if GetLocalPlayer() != GetOwningPlayer(u) then
            set b = not IsUnitHidden(u)
            call ShowUnit(u,false)
            call ShowUnit(u,b)
        endif
        //I added this line to disable their attack too.
        call UnitAddAbility(u,DISABLE_ATTACK)
    endfunction
    
    private function EnableControl takes unit u returns nothing
        local boolean backup = not IsUnitHidden(u)
        call ShowUnit(u,false)
        //I added this line to enable their attack.
        call UnitRemoveAbility(u,DISABLE_ATTACK)
        call ShowUnit(u,backup)
    endfunction
    
    struct Fear extends array
        unit targ
        string path
        string attach
        readonly effect e
        readonly boolean b
        private integer steps
        private integer startat
        private static timer period
        private static integer dindex
        private static thistype array data
        private static integer instanceCount
        private static thistype recycle
        private thistype recycleNext
        
        private static method periodic takes nothing returns nothing 
            local thistype this
            local real x
            local real y
            local integer i = 0
            loop
                exitwhen i > dindex
                set this = data[i]
                if modulo(this.steps,EACH_CHANGE) == this.startat then
                    set x = GetUnitX(this.targ)
                    set y = GetUnitY(this.targ)
                    call IssuePointOrder(this.targ, "move", GetRandomReal(x-AROUND,x+AROUND), GetRandomReal(y-AROUND, x+AROUND) )
                endif
                set this.steps = this.steps - 1
                if this.steps == 0 or not(UnitAlive(this.targ)) then
                    set data[i] = data[dindex]
                    set i = i - 1
                    set dindex = dindex - 1
                    if this.e != null then
                        call DestroyEffect(this.e)
                        set this.e = null
                    endif
                    call IssueImmediateOrder(this.targ,"stop")
                    call EnableControl(this.targ)
                    call tab.flush(this.targ)
                    if this.b then
                        set this.targ = null
                        set recycleNext = recycle
                        set recycle = this
                    endif
                endif
                if dindex == -1 then
                    call PauseTimer(period)
                endif
                set i = i + 1
            endloop
        endmethod
        
        static method isFeared takes unit u returns boolean
            return tab.exists(u)
        endmethod
        
        method operator time= takes real t returns nothing
            set this.steps = round(t/FPS)
        endmethod
        
        method operator time takes nothing returns real
            return this.steps*FPS
        endmethod
        
        method changeEffect takes string path, string attach returns nothing
            call DestroyEffect(this.e)
            set this.e = null
            set this.e = AddSpecialEffectTarget(path,this.targ,attach)
        endmethod
        
        static method get takes unit u returns thistype
            if isFeared(u) then
                return tab[u]
            else
                debug call BJDebugMsg("Tryng to get wrong instance")
                return 0
            endif
        endmethod
        
        method start takes nothing returns nothing
            debug if this.targ==null or this.steps==0 then
                debug call BJDebugMsg("You're instanciating badly ....")
                debug return
            debug endif
            set dindex = dindex + 1
            set data[dindex] = this
            set this.startat = modulo(this.steps,EACH_CHANGE)
            call DisableControl(this.targ)
            if this.path != "" and this.attach != ""  then
                set this.e = AddSpecialEffectTarget(this.path, this.targ, this.attach)
            endif
            set tab[this.targ] = this
            if dindex == 0 then
                call TimerStart(period, FPS, true, function thistype.periodic)
            endif
        endmethod
        
        static method create takes nothing returns thistype
            local thistype this
            if recycle == 0 then
                set instanceCount = instanceCount + 1
                set this = instanceCount
            else
                set this = recycle
                set recycle = recycle.recycleNext
            endif
            set this.path = ""
            set this.attach = ""
            set this.e = null
            set this.b = false
            return this
        endmethod
        
        method destroy takes nothing returns nothing
            set this.b = true
        endmethod
        
        private static method onInit takes nothing returns nothing
            set tab = HandleTable.create()
            set dindex = - 1
            set instanceCount = 0
            set recycle = 0
            set period = CreateTimer()
        endmethod
    endstruct
endlibrary

The Bribe version :
JASS:
library FearSystem /* v3
************************************************************************************
*
*   */uses /*
*   
*       */ Table /*        http://www.hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/
*        //By Bribe
*
************************************************************************************
*
*   struct Fear extends array
*
*       Description
*       -------------------------
*
*           This is a fear system; use it to remove player
*           control from a unit temporarily. Units affected
*           will also be unable to attack.
*
*       Fields
*       -------------------------
*
*           unit targ -> The unit you want to apply the fear.
* 
*           string path -> The path of the sfx you want to add to the unit.
*
*           string attach -> The attachment string you want the sfx to be on the unit
*
*           readonly effect e -> The effect currently applied to the unit.
*           Initializes to null
*
*       Methods
*       -------------------------
*
*           static method create takes nothing returns thistype
*           method destroy takes nothing returns nothing
*
*           method start takes nothing returns nothing
*           When you have set every parameters you start your fear instance.
*
*           method changeEffect takes string path, string attach returns nothing
*           If you already have set the effect of your instance and it is running
*           and you want to change it use this.
*
*           static method isFeared takes unit u returns boolean
*           static method get takes unit u returns thistype
*           
*       Operators
*       -------------------------
*
*           method operator time= takes real t returns nothing
*           method operator time takes nothing returns real
*
*       Credits
*       -------------------------
*
*           - Vexorian for vJASS and Table
*           - Maker for the DisableUnit function
*           - Bribe for Table
*           - Chobibo for the addition in the DisableUnit function/
*
************************************************************************************/
    native UnitAlive takes unit u returns boolean
    
    globals
        //There will be check every FPS second.
        private constant real FPS = 0.31250000
        //Feared units will change direction every EACH_CHANGE FPS.
        private constant integer EACH_CHANGE = 3
        //Feared units will go maximum in a circle of 150 around them each time they change direction.
        private constant real AROUND = 150.
        //The rawcode of the attack disable. Be sure it is the same in the Object Editor.
        private constant integer DISABLE_ATTACK = 'W000'
        //The rawcode of the morph. Be sure it is the same in the Object Editor.
        private constant integer MORPH_ID = 'Z001'
        //The rawcode of the bear form. Be sure it is the same in the Object Editor.
        private constant integer BEAR_ID = 'Z000'
    endglobals
    
    globals
        private Table tb
    endglobals
    
    private function round takes real r returns integer
        return R2I(r+0.5)
    endfunction
    
    private function modulo takes integer a, integer b returns integer
        return a - (a/b)*b
    endfunction
    
    //Credits to Maker for this awesum func <3
    private function DisableControl takes unit u returns nothing
        local boolean b
        call UnitAddAbility(u, 'Aloc')
        call UnitRemoveAbility(u, 'Aloc')
        if IsUnitType(u, UNIT_TYPE_HERO) then
            call UnitAddAbility(u,MORPH_ID)
            call IssueImmediateOrder(u, "metamorphosis")
            call UnitRemoveAbility(u,MORPH_ID)
        else
            call UnitAddAbility(u, BEAR_ID)
            call IssueImmediateOrder(u, "bearform")
            call UnitRemoveAbility(u, BEAR_ID)    
        endif
        //Thanks to chobibo for this idea
        if GetLocalPlayer() != GetOwningPlayer(u) then
            set b = not IsUnitHidden(u)
            call ShowUnit(u,false)
            call ShowUnit(u,b)
        endif
        //I added this line to disable their attack too.
        call UnitAddAbility(u,DISABLE_ATTACK)
    endfunction
    
    private function EnableControl takes unit u returns nothing
        local boolean backup = not IsUnitHidden(u)
        call ShowUnit(u,false)
        //I added this line to enable their attack.
        call UnitRemoveAbility(u,DISABLE_ATTACK)
        call ShowUnit(u,backup)
    endfunction
    
    struct Fear extends array
        unit targ
        string path
        string attach
        readonly effect e
        readonly boolean b
        private integer steps
        private integer startat
        private static timer period
        private static integer dindex
        private static thistype array data
        private static integer instanceCount
        private static thistype recycle
        private thistype recycleNext
        
        private static method periodic takes nothing returns nothing 
            local thistype this
            local real x
            local real y
            local integer i = 0
            loop
                exitwhen i > dindex
                set this = data[i]
                if modulo(this.steps,EACH_CHANGE) == this.startat then
                    set x = GetUnitX(this.targ)
                    set y = GetUnitY(this.targ)
                    call IssuePointOrder(this.targ, "move", GetRandomReal(x-AROUND,x+AROUND), GetRandomReal(y-AROUND, x+AROUND) )
                endif
                set this.steps = this.steps - 1
                if this.steps == 0 or not(UnitAlive(this.targ)) then
                    set data[i] = data[dindex]
                    set i = i - 1
                    set dindex = dindex - 1
                    if this.e != null then
                        call DestroyEffect(this.e)
                        set this.e = null
                    endif
                    call IssueImmediateOrder(this.targ,"stop")
                    call EnableControl(this.targ)
                    call tb.remove(GetHandleId(this.targ))
                    if this.b then
                        set this.targ = null
                        set recycleNext = recycle
                        set recycle = this
                    endif
                endif
                if dindex == -1 then
                    call PauseTimer(period)
                endif
                set i = i + 1
            endloop
        endmethod
        
        static method isFeared takes unit u returns boolean
            return tb.has(GetHandleId(u))
        endmethod
        
        method operator time= takes real t returns nothing
            set this.steps = round(t/FPS)
        endmethod
        
        method operator time takes nothing returns real
            return this.steps*FPS
        endmethod
        
        method changeEffect takes string path, string attach returns nothing
            call DestroyEffect(this.e)
            set this.e = null
            set this.e = AddSpecialEffectTarget(path,this.targ,attach)
        endmethod
        
        static method get takes unit u returns thistype
            local thistype this
            if isFeared(u) then
                return tb[GetHandleId(u)]
            else
                debug call BJDebugMsg("Tryng to get wrong instance")
                return 0
            endif
        endmethod
        
        method start takes nothing returns nothing
            debug if this.targ==null or this.steps==0 then
                debug call BJDebugMsg("You're instanciating badly ....")
                debug return
            debug endif
            set dindex = dindex + 1
            set data[dindex] = this
            set this.startat = modulo(this.steps,EACH_CHANGE)
            call DisableControl(this.targ)
            if this.path != "" and this.attach != ""  then
                set this.e = AddSpecialEffectTarget(this.path, this.targ, this.attach)
            endif
            set tb[GetHandleId(this.targ)] = this
            if dindex == 0 then
                call TimerStart(period, FPS, true, function thistype.periodic)
            endif
        endmethod
        
        static method create takes nothing returns thistype
            local thistype this
            if recycle == 0 then
                set instanceCount = instanceCount + 1
                set this = instanceCount
            else
                set this = recycle
                set recycle = recycle.recycleNext
            endif
            set this.path = ""
            set this.attach = ""
            set this.e = null
            set this.b = false
            return this
        endmethod
        
        method destroy takes nothing returns nothing
            set this.b = true
        endmethod
        
        private static method onInit takes nothing returns nothing
            set tb = Table.create()
            set dindex = - 1
            set instanceCount = 0
            set recycle = 0
            set period = CreateTimer()
        endmethod
    endstruct
endlibrary

Credits :
- Vexorian for Table Library and vJASS.
- Maker for the help in the disable function.
- Bribe for Table Library (Yes there is two :D ).
- Chobibo for addition in the disable function.

v1.0:
- Initial Release

v1.1 :
- Trigger Optimization.
- Added a version with Table by Bribe.

v1.2 :
- Added 'Avul' during the unfeared phase.

v1.3 :
- Only one trigger for both Table Libraries.

v2.0 :
- Added a GUI/JASS version.

v2.1 :
- Fix a bug with hashtable.

v2.2 :
- Fix some issues.
- Fix this box ^^.

v2.3 :
- Change the code
- Delete the JASS version for the moment.

v2.4 :
- Fix bugs.

v2.5 :
- Thanks to chobibo you can target feared units if you're not the owner of those.

v2.6 :
- Fix a bug with the indexing.
- Fix a bug with a static integer which should have been thistype instead;
- Optimize some triggers with the backup boolean.
- Optimize round functions.
- Now properly works.

v2.7 :
- Bug corrected.

v3 :
- Separated Bribe and Vexorian codes for the sake of statif if bugs.


Give credits to me and the four above if you use it :)
Malhorne

Keywords:
Fear System, Fear, System, vJASS, JESP, Malhorne, Status Effect, Status, Status Alteration, Corwd, Control, Crowd Control
Contents

Just another Warcraft III map (Map)

Reviews
Fear System v2.7 | Reviewed by Maker | 25th November 2013 Concept[/COLOR]] It is a unique system that has not been done before. Status effect systems are a welcome addition to out spell database Triggers[/COLOR]] Leakless and MUI...

Moderator

M

Moderator


Fear System v2.7 | Reviewed by Maker | 25th November 2013

[COLOR="gray"

[COLOR="gray"

[COLOR="gray"

[COLOR="gray"

Concept[/COLOR]]
126248-albums6177-picture66521.png
  • It is a unique system that has not been done before.
    Status effect systems are a welcome addition to out spell database
Triggers[/COLOR]]
126248-albums6177-picture66521.png
  • Leakless and MUI
Objects[/COLOR]]
126248-albums6177-picture66521.png
  • No unneeded objects and the system works with the current settings
Rating[/COLOR]]
CONCEPTTRIGGERSOBJECTSRATINGSTATUS
126248-albums6177-picture75360.jpg
126248-albums6177-picture75360.jpg
126248-albums6177-picture75360.jpg
126248-albums6177-picture75360.jpg
APPROVED



Fear System v2.5 | Reviewed by Maker | 17th November 2013

[COLOR="gray"

[COLOR="gray"

[COLOR="gray"

[COLOR="gray"

Concept[/COLOR]]
126248-albums6177-picture66521.png
  • It is a unique system that has not been done before.
    Status effect systems are a welcome addition to out spell database
Triggers[/COLOR]]
126248-albums6177-picture66521.png
  • Leakless and MUI
126248-albums6177-picture66522.png
  • Your index recycling is not working, instance count increases
    with each target affected
126248-albums6177-picture66523.png
  • You could merge start and create. Then that combined method
    could take unit, the strings and time as parameters
Objects[/COLOR]]
126248-albums6177-picture66521.png
  • No unneeded objects and the system works with the current settings
Rating[/COLOR]]
CONCEPTTRIGGERSOBJECTSRATINGSTATUS
126248-albums6177-picture75360.jpg
126248-albums6177-picture75359.jpg
126248-albums6177-picture75360.jpg
126248-albums6177-picture75359.jpg
NEEDS FIX
 
Level 9
Joined
Dec 12, 2007
Messages
489
To use this you will have to call the method Fear.add(unit, time, slow)
The parameter unit is the unit you want to fear.
The parameter time is how many time the unit have to be feared.
The parameter path : it is the path of the effect you'll add to the feared unit.
The parameter attach : it is the attachment of the effect on the feared unit.
An example : call Fear.add(u, 3)
you should fix your documentation.
 
Level 9
Joined
Dec 12, 2007
Messages
489
I still don't understand this part in your documentation,
The unit u will be feared during 3 seconds and it will be slowed of 35%.
I don't see any part of your script which capable of changing movement speed throught any means, although it will be a nice built in feature, although I prefer faster movement. you didn't slow down when under fear, you run like hell out of it.

Example : Fear.add(u,3,0.65)
I don't remember API can be flexible :)

anyway, to the code,
I can't find any flaws within the code other than within the documentation.
nice resource.
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
this.targ and this.e should be nulled in the end.
Note: I just read the code you posted here, so it might be fixed already.

Apart from that I didn't see anything wrong.

Vexorian for Table Library
Thats not a good idea in my mind, since Bribes Table is nowadays used by most resources and not Vexorians at least on THW.

static if LIBRARY_Table then This will throw an error, if the user has NewTable, since it is named Table aswell. But I'm sure you are aware of that.

Edit: I think this resource is very usefull and would love to see it beeing compatible with Bribe's Table.
 
Level 18
Joined
Sep 14, 2012
Messages
3,413
Don't know I hate red words xD !
Oh wait I can do it in one line because it will never be negative in my usage xD !

Yes I might do another version for table by Bribe :)


EDIT : I'll see further for modulo thingy.
A new version with Table by Bribe will be uploaded too.
And this new version will be in an unable trigger in the test map :)
So I'll add Bribe to the credits too :)
I'll do it tomorrow :)
Thanks for every reply !
 
Last edited:
Level 22
Joined
Sep 24, 2005
Messages
4,821
Maker is right, just use the ModuloInt BJ dude, your modulo function is redundant. I suggest using the IssuePointOrderById and IssueImmediateOrderById, to use less strings. There's an orderId list available here.
 
Level 18
Joined
Sep 14, 2012
Messages
3,413
Ah yes I did by string because I don't remember the id of those orders :/

For the doc yes it is bad :/
I'm so bad to explain something xD
I'll try to rewrite it after I'll update the globals leak, a second version with Table by Bribe and a better how to import.

Updated !
V1.0:
- Initial Release

V1.1 :
- Trigger Optimization.
- Added a version with Table by Bribe.
 
Last edited:
Level 16
Joined
Jul 31, 2012
Messages
2,217
Works well, i just found one bug.. it is related to the disablement i suppose, if i attack the feared unit and the projectile hits him after the the fear ended, the damage does not occur, i guess that also applies to many spells and such :/
 
Level 22
Joined
Sep 24, 2005
Messages
4,821
Add invulnerability during the transition from feared to unfeared to disable any attempt to attack the unit. Invulnerable units can't be targeted with both spells and 'Aatk'.
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
it should work, and the order you put it in will give the priority.

I recommend doing first check the Table.has.exists, so you support Bribe's table if both Bribes and Vexorians table exists on the same map, then Table.flush2D.exists and then normal hashtable
 
Level 22
Joined
Sep 24, 2005
Messages
4,821
Wouldn't that conflict (Bribe and Vexorian's table on a single map), the library identifiers are the same.
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
yea that is true, but eh :D

edit:

This wont compile anymore at least under 0.A.2.B of Vexorians(the newest) JassHelper, because globals are moved before static ifs are evaluated.

You will have to put those globals into private struct :(
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
This seriously doesn't belong in the documentation...

JASS:
Hi everyone !
Here is my first uploaded system.
This is a fear system. But what means fear ? You're trying to scare me D: ?
Fear a unit means that it will randomly walk.
During this period the unit will not be able to receive orders from the owner of the unit.
The unit will be still targetable for any attack or spell.
 
Level 22
Joined
Sep 24, 2005
Messages
4,821
I also think a description should be included, not everyone knows what a fear system is. Maybe you could make it shorter and more straight to the point like:
Code:
This is a fear system; use it to remove player
control from a unit temporarily. Units affected
will also be unable to attack.
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
Since you made it compatible with Bribe's Table, this is now very useful for any THW user.
The system is original amd effective.
And the most important thing, its doesn't create tons of Special Effects like all latest submissions do. It is based on unit manipulation, instead of pure eye-candy, which I appreciate. Such resources can be used in serious multiplayer games, where unit control is the meat and potatoes.

Good job. :)
 
Level 18
Joined
Sep 14, 2012
Messages
3,413
Updated !

V1.0:
- Initial Release

V1.1 :
- Trigger Optimization.
- Added a version with Table by Bribe.

V1.2 :
- Added 'Avul' during the unfeared phase.

V1.3 :
- Only one trigger for both Table Libraries.

V2.0 :
- Added a GUI/JASS version.

V2.1 :
- Fix a bug with hashtable.

V2.2 :
- Fix some issues.
- Fix this box ^^.
 
Last edited:
Level 31
Joined
Jul 10, 2007
Messages
6,306
A unit indexer will improve this. All your static ifs are just uglifying the code. If you just tell a user to use any unit indexer (doesn't matter which one), you can use GetUnitUserData. This will remove all of your ugly static ifs.

Put an API in your docs. The tutorial format isn't appreciated.


Users shouldn't have to look for your API hidden away in the middle of blocks of text. That's just really, really bad practice. I personally hate it when people do that. I spent 2 hours trying to find something for Qt (instead of literally 8 seconds, that's how fast I found the website with the info I needed) precisely because they did what you are doing here. If you want to give people an easier time, do a nicely formatted API.


Next, because you are applying fear with effects, you need to do Fear.create with instances rather than a static single Fear for a given unit. With what you have now, you'll really mess things up with the effects :\.


Also, Fear is an ambiguous struct name.


Rather than extend, you should do fear.time (notice not cap, this is an instance property). You should also have a destroy method.


That's all for now.
 
Level 22
Joined
Sep 24, 2005
Messages
4,821
Why not treat the fear behavior as a buff and allow people to decide if they want to make it stackable or not.
 
Level 18
Joined
Sep 14, 2012
Messages
3,413
Okay guys I did this kinda fastly (I have to go in class soon) -> There is not doc but I put and example of use after.

JASS:
library FearSystemNew requires optional Table
    native UnitAlive takes unit u returns boolean
    
    globals
        //There will be check every FPS second.
        private constant real FPS = 0.31250000
        //Feared units will change direction every EACH_CHANGE FPS.
        private constant integer EACH_CHANGE = 3
        //Feared units will go maximum in a circle of 150 around them each time they change direction.
        private constant real AROUND = 150.
        //The rawcode of the attack disable. Be sure it is the same in the Object Editor.
        private constant integer DISABLE_ATTACK = 'W000'
        //The rawcode of the morph. Be sure it is the same in the Object Editor.
        private constant integer MORPH_ID = 'Z001'
        //The rawcode of the bear form. Be sure it is the same in the Object Editor.
        private constant integer BEAR_ID = 'Z000'
    endglobals
    
    static if Table.flush2D.exists then
        globals
            private HandleTable tab
        endglobals
    elseif Table.has.exists then
        globals
            private Table tb
        endglobals
    else
        globals
            private hashtable ht = InitHashtable()
        endglobals
    endif
    
    private function round takes real r returns integer
        if r-0.5 > R2I(r) then
            return R2I(r+1)
        else
            return R2I(r)
        endif
    endfunction
    
    private function modulo takes integer a, integer b returns integer
        return a - (a/b)*b
    endfunction
    
    //Credits to Maker for this awesum func <3
    private function DisableControl takes unit u returns nothing
        call UnitAddAbility(u, 'Aloc')
        call UnitRemoveAbility(u, 'Aloc')
        if IsUnitType(u, UNIT_TYPE_HERO) then
            call UnitAddAbility(u,MORPH_ID)
            call IssueImmediateOrder(u, "metamorphosis")
            call UnitRemoveAbility(u,MORPH_ID)
        else
            call UnitAddAbility(u, BEAR_ID)
            call IssueImmediateOrder(u, "bearform")
            call UnitRemoveAbility(u, BEAR_ID)    
        endif
        //I added this line to disable their attack too.
        call UnitAddAbility(u,DISABLE_ATTACK)
    endfunction
    
    private function EnableControl takes unit u returns nothing
        local boolean backup = not IsUnitHidden(u)
        call ShowUnit(u,false)
        //I added this line to enable their attack.
        call UnitRemoveAbility(u,DISABLE_ATTACK)
        call ShowUnit(u,true)
        call ShowUnit(u,backup)
    endfunction
    
    struct Fear extends array
        unit targ
        string path
        string attach
        readonly effect e
        private integer steps
        private integer startat
        private static timer period
        private static integer dindex
        private static thistype array data
        private static integer instanceCount
        private static integer recycle
        private thistype recycleNext
        
        private static method periodic takes nothing returns nothing 
            local thistype this
            local real x
            local real y
            local integer i = 0
            loop
                exitwhen i > dindex
                set this = data[i]
                if modulo(this.steps,EACH_CHANGE) == this.startat then
                    set x = GetUnitX(this.targ)
                    set y = GetUnitY(this.targ)
                    call IssuePointOrder(this.targ, "move", GetRandomReal(x-AROUND,x+AROUND), GetRandomReal(y-AROUND, x+AROUND) )
                endif
                set this.steps = this.steps - 1
                if this.steps == 0 or not(UnitAlive(this.targ)) then
                    set data[i] = data[dindex]
                    set i = i - 1
                    set dindex = dindex - 1
                    if this.e != null then
                        call DestroyEffect(this.e)
                        set this.e = null
                    endif
                    call IssueImmediateOrder(this.targ,"stop")
                    call EnableControl(this.targ)
                    static if Table.flush2D.exists then
                        call tab.flush(this.targ)
                    elseif Table.has.exists then
                        return tb.remove(GetHandleId(this.targ))
                    else
                        return FlushChildHashtable(ht,GetHandleId(this.targ))
                    endif
                    set this.targ = null
                    //Destroying the struct
                    set recycleNext = recycle
                    set recycle = this
                endif
                if dindex == -1 then
                    call PauseTimer(period)
                endif
                set i = i + 1
            endloop
        endmethod
        
        static method isFeared takes unit u returns boolean
            static if Table.flush2D.exists then
                return tab.exists(u)
            elseif Table.has.exists then
                return tb.has(GetHandleId(u))
            else
                return HaveSavedInteger(ht,GetHandleId(u),0)
            endif
        endmethod
        
        method extend takes real t returns nothing
            set this.steps = round(t/FPS) + this.steps
        endmethod
        
        method changeEffect takes string path, string attach returns nothing
            set this.e = AddSpecialEffectTarget(path,this.targ,attach)
        endmethod
        
        static method get takes unit u returns thistype 
            if isFeared(u) then
                static if Table.flush2D.exists then
                    return tab[u]
                elseif Table.has.exists then
                    return tb[GetHandleId(u)]
                else
                    return LoadInteger(ht,GetHandleId(u),0)
                endif
            else
                debug call BJDebugMsg("Tryng to get wrong instance")
                return 0
            endif
        endmethod
        
        method start takes real t returns nothing
            debug if this.targ == null or t<0 then
                debug call BJDebugMsg("You're instanciating badly ....")
                debug return
            debug endif
            set dindex = dindex + 1
            set data[dindex] = this
            set this.steps = round(t/FPS)
            set this.startat = modulo(this.steps,EACH_CHANGE)
            call DisableControl(this.targ)
            if this.path != "" and this.attach != ""  then
                set this.e = AddSpecialEffectTarget(this.path, this.targ, this.attach)
            endif
            static if Table.flush2D.exists then
                set tab[this.targ] = this
            elseif Table.has.exists then
                set tb[GetHandleId(this.targ)] = this
            else
                call SaveInteger(ht,GetHandleId(this.targ),0,this)
            endif
            if dindex == 0 then
                call TimerStart(period, FPS, true, function thistype.periodic)
            endif
        endmethod
        
        static method create takes nothing returns thistype
            local thistype this
            if recycle == 0 then
                set instanceCount = instanceCount + 1
                set this = instanceCount
            else
                set this = recycle
                set recycle = recycleNext
            endif
            set this.path = ""
            set this.attach = ""
            return this
        endmethod
        
        private static method onInit takes nothing returns nothing
            static if Table.flush2D.exists then
                set tab = HandleTable.create()
            elseif Table.has.exists then
                set tb = Table.create()
            endif
            set dindex = - 1
            set instanceCount = 0
            set recycle = 0
            set period = CreateTimer()
        endmethod
    endstruct
endlibrary

An example of use :
JASS:
scope TestFear
//=============================================================
//=========================SETUP================================
//=============================================================
    globals
        private constant real DURATION = 3.
        private constant real AOE = 350.
        private constant integer SPELL_ID = 'P000'
        private constant string PATH = "Abilities\\Spells\\Undead\\Curse\\CurseTarget.mdl"
        private constant string PATH_2 = "Abilities\\Spells\\NightElf\\BattleRoar\\RoarCaster.mdl"
        private constant string ATTACH = "overhead"
    endglobals
    
    private function Duration takes integer level returns integer
        return 2+level
    endfunction
    
    private function Aoe takes integer level returns integer
        return 300 + 50*level
    endfunction
    
    private function Cond takes nothing returns boolean
        local unit FoG
        local player p
        local real x
        local real y
        local group g
        local integer lvl
        local Fear F
        if GetSpellAbilityId() == SPELL_ID then
            set g = CreateGroup()
            set p = GetOwningPlayer(GetTriggerUnit())
            set x = GetSpellTargetX()
            set y = GetSpellTargetY()
            set lvl = GetUnitAbilityLevel(GetTriggerUnit(),SPELL_ID)
            call GroupEnumUnitsInRange(g, x, y, Aoe(lvl), null)
            call DestroyEffect(AddSpecialEffect(PATH_2,x,y))
            loop
                set FoG = FirstOfGroup(g)
                exitwhen FoG == null
                call GroupRemoveUnit(g, FoG)
                //I'm using UnitAlive since I declared it in the FearSystem
                if not IsUnitAlly(FoG,p) and UnitAlive(FoG) then
                    if Fear.isFeared(FoG) then
                        set F = Fear.get(FoG)
                        call F.extend(Duration(lvl))
                    else
                        set F = Fear.create()
                        set F.targ = FoG
                        set F.path = PATH
                        set F.attach = ATTACH
                        call F.start(Duration(lvl))
                    endif
                endif
            endloop
            call DestroyGroup(g)
            set g = null
        endif
        return false
    endfunction
    
    private module Module
        private static method onInit takes nothing returns nothing
            call init()
        endmethod
    endmodule
    
    private struct A extends array
        private static method init takes nothing returns nothing
            local trigger t = CreateTrigger()
            call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
            call TriggerAddCondition(t, Condition(function Cond))
            set bj_lastCreatedUnit = CreateUnit(Player(15),'h000',0,0,0)
            call UnitAddAbility(bj_lastCreatedUnit, SPELL_ID)
            call KillUnit(bj_lastCreatedUnit)
            call Preload(PATH)
            call Preload(PATH_2)
            set t = null
        endmethod
        implement Module
    endstruct
endscope
 
Level 18
Joined
Sep 14, 2012
Messages
3,413
Updated !
I manage to found some time to fix to this :
JASS:
library FearSystemNew requires optional Table
    native UnitAlive takes unit u returns boolean
    
    globals
        //There will be check every FPS second.
        private constant real FPS = 0.31250000
        //Feared units will change direction every EACH_CHANGE FPS.
        private constant integer EACH_CHANGE = 3
        //Feared units will go maximum in a circle of 150 around them each time they change direction.
        private constant real AROUND = 150.
        //The rawcode of the attack disable. Be sure it is the same in the Object Editor.
        private constant integer DISABLE_ATTACK = 'W000'
        //The rawcode of the morph. Be sure it is the same in the Object Editor.
        private constant integer MORPH_ID = 'Z001'
        //The rawcode of the bear form. Be sure it is the same in the Object Editor.
        private constant integer BEAR_ID = 'Z000'
    endglobals
    
    static if Table.flush2D.exists then
        globals
            private HandleTable tab
        endglobals
    elseif Table.has.exists then
        globals
            private Table tb
        endglobals
    else
        globals
            private hashtable ht = InitHashtable()
        endglobals
    endif
    
    private function round takes real r returns integer
        if r-0.5 > R2I(r) then
            return R2I(r+1)
        else
            return R2I(r)
        endif
    endfunction
    
    private function modulo takes integer a, integer b returns integer
        return a - (a/b)*b
    endfunction
    
    //Credits to Maker for this awesum func <3
    private function DisableControl takes unit u returns nothing
        call UnitAddAbility(u, 'Aloc')
        call UnitRemoveAbility(u, 'Aloc')
        if IsUnitType(u, UNIT_TYPE_HERO) then
            call UnitAddAbility(u,MORPH_ID)
            call IssueImmediateOrder(u, "metamorphosis")
            call UnitRemoveAbility(u,MORPH_ID)
        else
            call UnitAddAbility(u, BEAR_ID)
            call IssueImmediateOrder(u, "bearform")
            call UnitRemoveAbility(u, BEAR_ID)    
        endif
        //I added this line to disable their attack too.
        call UnitAddAbility(u,DISABLE_ATTACK)
    endfunction
    
    private function EnableControl takes unit u returns nothing
        local boolean backup = not IsUnitHidden(u)
        call ShowUnit(u,false)
        //I added this line to enable their attack.
        call UnitRemoveAbility(u,DISABLE_ATTACK)
        call ShowUnit(u,true)
        call ShowUnit(u,backup)
    endfunction
    
    struct Fear extends array
        unit targ
        string path
        string attach
        readonly effect e
        private integer steps
        private integer startat
        private static timer period
        private static integer dindex
        private static thistype array data
        private static integer instanceCount
        private static integer recycle
        private thistype recycleNext
        
        private static method periodic takes nothing returns nothing 
            local thistype this
            local real x
            local real y
            local integer i = 0
            loop
                exitwhen i > dindex
                set this = data[i]
                if modulo(this.steps,EACH_CHANGE) == this.startat then
                    set x = GetUnitX(this.targ)
                    set y = GetUnitY(this.targ)
                    call IssuePointOrder(this.targ, "move", GetRandomReal(x-AROUND,x+AROUND), GetRandomReal(y-AROUND, x+AROUND) )
                endif
                set this.steps = this.steps - 1
                if this.steps == 0 or not(UnitAlive(this.targ)) then
                    set data[i] = data[dindex]
                    set i = i - 1
                    set dindex = dindex - 1
                    if this.e != null then
                        call DestroyEffect(this.e)
                        set this.e = null
                    endif
                    call IssueImmediateOrder(this.targ,"stop")
                    call EnableControl(this.targ)
                    static if Table.flush2D.exists then
                        call tab.flush(this.targ)
                    elseif Table.has.exists then
                        return tb.remove(GetHandleId(this.targ))
                    else
                        return FlushChildHashtable(ht,GetHandleId(this.targ))
                    endif
                    set this.targ = null
                endif
                if dindex == -1 then
                    call PauseTimer(period)
                endif
                set i = i + 1
            endloop
        endmethod
        
        static method isFeared takes unit u returns boolean
            static if Table.flush2D.exists then
                return tab.exists(u)
            elseif Table.has.exists then
                return tb.has(GetHandleId(u))
            else
                return HaveSavedInteger(ht,GetHandleId(u),0)
            endif
        endmethod
        
        method operator time= takes real t returns nothing
            set this.steps = round(t/FPS) + this.steps
        endmethod
        
        method operator time takes nothing returns real
            return this.steps*FPS
        endmethod
        
        method changeEffect takes string path, string attach returns nothing
            call DestroyEffect(this.e)
            set this.e = null
            set this.e = AddSpecialEffectTarget(path,this.targ,attach)
        endmethod
        
        static method get takes unit u returns thistype 
            if isFeared(u) then
                static if Table.flush2D.exists then
                    return tab[u]
                elseif Table.has.exists then
                    return tb[GetHandleId(u)]
                else
                    return LoadInteger(ht,GetHandleId(u),0)
                endif
            else
                debug call BJDebugMsg("Tryng to get wrong instance")
                return 0
            endif
        endmethod
        
        method start takes real t returns nothing
            debug if this.targ == null or t<0 then
                debug call BJDebugMsg("You're instanciating badly ....")
                debug return
            debug endif
            set dindex = dindex + 1
            set data[dindex] = this
            set this.steps = round(t/FPS)
            set this.startat = modulo(this.steps,EACH_CHANGE)
            call DisableControl(this.targ)
            if this.path != "" and this.attach != ""  then
                set this.e = AddSpecialEffectTarget(this.path, this.targ, this.attach)
            endif
            static if Table.flush2D.exists then
                set tab[this.targ] = this
            elseif Table.has.exists then
                set tb[GetHandleId(this.targ)] = this
            else
                call SaveInteger(ht,GetHandleId(this.targ),0,this)
            endif
            if dindex == 0 then
                call TimerStart(period, FPS, true, function thistype.periodic)
            endif
        endmethod
        
        static method create takes nothing returns thistype
            local thistype this
            if recycle == 0 then
                set instanceCount = instanceCount + 1
                set this = instanceCount
            else
                set this = recycle
                set recycle = recycleNext
            endif
            set this.path = ""
            set this.attach = ""
            return this
        endmethod
        
        method destroy takes nothing returns nothing
            set recycleNext = recycle
            set recycle = this
        endmethod
        
        private static method onInit takes nothing returns nothing
            static if Table.flush2D.exists then
                set tab = HandleTable.create()
            elseif Table.has.exists then
                set tb = Table.create()
            endif
            set dindex = - 1
            set instanceCount = 0
            set recycle = 0
            set period = CreateTimer()
        endmethod
    endstruct
endlibrary

New test spell so ...
JASS:
scope TestFear
//=============================================================
//=========================SETUP================================
//=============================================================
    globals
        private constant real DURATION = 3.
        private constant real AOE = 350.
        private constant integer SPELL_ID = 'P000'
        private constant string PATH = "Abilities\\Spells\\Undead\\Curse\\CurseTarget.mdl"
        private constant string PATH_2 = "Abilities\\Spells\\NightElf\\BattleRoar\\RoarCaster.mdl"
        private constant string ATTACH = "overhead"
    endglobals
    
    private function Duration takes integer level returns integer
        return 2+level
    endfunction
    
    private function Aoe takes integer level returns integer
        return 300 + 50*level
    endfunction
    
    private function Cond takes nothing returns boolean
        local unit FoG
        local player p
        local real x
        local real y
        local group g
        local integer lvl
        local Fear F
        if GetSpellAbilityId() == SPELL_ID then
            set g = CreateGroup()
            set p = GetOwningPlayer(GetTriggerUnit())
            set x = GetSpellTargetX()
            set y = GetSpellTargetY()
            set lvl = GetUnitAbilityLevel(GetTriggerUnit(),SPELL_ID)
            call GroupEnumUnitsInRange(g, x, y, Aoe(lvl), null)
            call DestroyEffect(AddSpecialEffect(PATH_2,x,y))
            loop
                set FoG = FirstOfGroup(g)
                exitwhen FoG == null
                call GroupRemoveUnit(g, FoG)
                //I'm using UnitAlive since I declared it in the FearSystem
                if not IsUnitAlly(FoG,p) and UnitAlive(FoG) then
                    if Fear.isFeared(FoG) then
                        set F = Fear.get(FoG)
                        set F.time = Duration(lvl)
                    else
                        set F = Fear.create()
                        set F.targ = FoG
                        set F.path = PATH
                        set F.attach = ATTACH
                        call F.start(Duration(lvl))
                        call F.destroy()
                    endif
                endif
            endloop
            call DestroyGroup(g)
            set g = null
        endif
        return false
    endfunction
    
    private module Module
        private static method onInit takes nothing returns nothing
            call init()
        endmethod
    endmodule
    
    private struct A extends array
        private static method init takes nothing returns nothing
            local trigger t = CreateTrigger()
            call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
            call TriggerAddCondition(t, Condition(function Cond))
            set bj_lastCreatedUnit = CreateUnit(Player(15),'h000',0,0,0)
            call UnitAddAbility(bj_lastCreatedUnit, SPELL_ID)
            call KillUnit(bj_lastCreatedUnit)
            call Preload(PATH)
            call Preload(PATH_2)
            set t = null
        endmethod
        implement Module
    endstruct
endscope
What do you think Nestharus ?
There is no documentation at the moment sorry I'll try to see your documentation Nes to see how to do a good one that explains well.
And then I shall update the code.
 
Top