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

CombopointListener

Level 16
Joined
Feb 22, 2006
Messages
960
Here is the new System I worked on. It's called CombopointListener look into the script header for more information.

Requires:

Credits:

Vexorian for JassHelper/Table 2.0/BoolexprUtils​
Deadon for help with methods reworking​
PurplePoot who reminded me to use a generic trigger​
aznricepuff for general and upcoming help​
JASS:
//****************************************************************************************************
//* CombopointListener v0.6a By xD.Schurke
//* ---------------------------------------
//*
//* Requires:
//* *At least JassHelper v0.9.Z.5
//* *Table 3.0
//*
//* Credits:
//* *Vexorian for JassHelper,Table
//* *Deaod for helping with some stuff
//* *PurplePoot who reminded me to use a generic trigger
//* *aznricepuff
//*
//* Changelog:
//* *Removed BoolexprUtils 
//* *Added an auto-reset via timer
//* *Added new method (autoReset(boolean))
//* *resetCPOnTargetSwitch is now a method and also was renamed (resetOnSwitch(boolean))
//* *Cleaned code (removed most operator overloading and simply renamed the variables)
//*
//* Changelog for 0.6a:
//* *Renamed globals for a better legibility
//* *Fixed a small issue with the intern variable dataNum
//* *Fixed a small issue with the stackRemove method which could cause some problems
//* 
//*
//* CombopointListener Doc:
//* ---------------------------------------
//*
//* The following Doc lists up all Methods/Members which can be influenced by the user.
//*
//*
//* Methods of CombopointListener:
//*
//* create (unit u)
//* Alocates a unique Instance for the unit
//*
//* resetCombopoints()
//* Sets the combopoints to 0
//*
//* newSpellData (integer rawCode, integer combpointsperspell)
//* Registers a spell and sets the combopoints gained per spell
//*
//* autoReset (boolean b)
//* If true the combopoints reset each autoResetTime-Interval to 0 
//* By default it's false
//*
//* resetOnSwitch (boolean b)
//* If true the combopoints reset on each target switch
//* By default it's true
//*
//* destroy()
//* Recycles the ID and resets all members of the instance
//*
//*
//* Members of CombopointListener:
//*
//* integer maxCombopoints
//* Represents the maxCombopoints which can gained by the unit
//* Standard for this member is 5.
//*
//* integer combopoints
//* The current number of combopoints
//*
//* real autoResetTime
//* Used for reseting combopoints if autoReset is true
//* By default each 90 seconds
//*
//*
//* Outstanding Constants:
//*
//* integer StandardMaxCP = 5
//* 
//* real StandardInterval = 0.03125
//*
//* Outstanding Functions:
//*
//* CombopointListener GetCombopointListener(unit u)
//* Returns the CombopointListener instance for this unit
//*
//* ---------------------------------------
//*
//* This small system simulates a combopoint system equal to the one in Worlf of Warcraft.
//* It works all for its own, that means you only have to register an unit and spells for this unit
//* and the system will register the combopoints. The only thing the user have to do is for abilities
//* which should remove combopoints or are based on the number of Combopoints.
//*
//****************************************************************************************************
library CombopointListener requires Table
globals
    private constant    integer STANDARD_MAX_CP      =   5
    private constant    real    STANDARD_INTERVAL    =   0.03125 
endglobals

struct CombopointListener    
    public              integer             maxCombopoints       = STANDARD_MAX_CP
    public              real                autoResetTime        = 90.0
    
    private             integer             cp                   = 0
    private             boolean             autoR                = false
    private             boolean             onSwitch             = true
    private             unit                listenUnit           = null
    private             unit                curTarget            = null
    private             real                time                 = 0.0
    private             integer             dataNum              = 0
    
    private     static  integer             size                 = 0
    private     static  thistype    array   data
    private     static  timer               tim
    readonly    static  HandleTable         regTable             = 0

    method operator combopoints= takes integer i returns nothing
    debug if i > this.maxCombopoints or i < 0 then
    debug   call BJDebugMsg("Warning: This number isn't supported by the system!")
            return
    debug endif
    debug set this.cp = i
    endmethod
    
    method operator combopoints takes nothing returns integer
        return this.cp
    endmethod

    method resetCombopoints takes nothing returns nothing
        set this.cp = 0
    endmethod

    method newSpellData takes integer rawCode, integer cpps returns nothing
        set Table[I2S(GetHandleId(this.listenUnit))][rawCode] = cpps
    endmethod
    
    static method autoResetCallback takes nothing returns nothing
        local integer i = 0
        local thistype this
        loop
            exitwhen i >= thistype.size
            set this = thistype.data[i]
            set this.time = this.time + STANDARD_INTERVAL
            if this.time >= this.autoResetTime then
                call this.resetCombopoints()
                set this.time = 0.0
            endif
        endloop
        if this.size == 0 then
            call PauseTimer(this.tim)
        endif
    endmethod
    
    method autoReset takes boolean b returns nothing
        if b then
            if this.size == 0 then
                call TimerStart(this.tim,STANDARD_INTERVAL,true,function thistype.autoResetCallback)
            endif
            set this.dataNum = this.size
            set this.data[this.size] = this
            set this.size = this.size + 1
            set this.autoR = true
        elseif this.size > 0 and this.autoR then
            call this.stackRemove()
            set this.autoR = false
        endif
    endmethod
    
    private method stackRemove takes nothing returns nothing
        if this.size > 1 then
            set this.size = this.size - 1
            set this.data[this.dataNum] = this.data[this.size]
            set this.data[this.size] = 0
            set this.data[this.dataNum].dataNum = this.dataNum            
        else
            set this.size = this.size - 1
            set this.data[this.size] = 0
        endif
        if this.size == 0 then
            call PauseTimer(this.tim)
        endif
    endmethod

    private static method condition takes nothing returns boolean
        local unit u = GetTriggerUnit()
        local thistype this = thistype.regTable[u]
        local boolean b = false
        if this != 0 or this != null then
            set b = Table[I2S(GetHandleId(u))].exists(GetSpellAbilityId())
        endif
        set u = null
        return b
    endmethod

    private static method action takes nothing returns nothing
        local unit u = GetTriggerUnit()
        local unit tar = GetSpellTargetUnit()
        local thistype this = thistype.regTable[u]
        if this.onSwitch and tar != this.curTarget then
            call this.resetCombopoints()
            set this.curTarget = tar
        endif
        set this.cp = this.cp + Table[I2S(GetHandleId(u))][GetSpellAbilityId()]
        if this.cp > this.maxCombopoints then
            set this.cp = this.maxCombopoints
        endif
        set this.time = 0.0
        set u = null
        set tar = null
    endmethod

    static method create takes unit u returns thistype
        local thistype this = thistype.allocate()
        set this.listenUnit = u
        set thistype.regTable[u] = this
        return this
    endmethod

    private method onDestroy takes nothing returns nothing
        if this.autoR then
            call this.stackRemove()
        endif
        call this.regTable.flush(this.listenUnit)
        call Table.flush2D(I2S(GetHandleId(this.listenUnit)))
        set this.listenUnit = null
        set this.curTarget = null
    endmethod

    private static method onInit takes nothing returns nothing
        local trigger int = CreateTrigger()
        local integer i = 0
        loop
            call TriggerRegisterPlayerUnitEvent(int,Player(i),EVENT_PLAYER_UNIT_SPELL_EFFECT,null)
            set i = i + 1
            exitwhen i >= bj_MAX_PLAYER_SLOTS
        endloop
        call TriggerAddCondition(int,Condition(function thistype.condition))
        call TriggerAddAction(int,function thistype.action)
        set thistype.regTable = HandleTable.create()
        set thistype.tim = CreateTimer()
        set int = null        
    endmethod
endstruct

function GetCombopointListener takes unit u returns CombopointListener
    debug if u == null then
    debug call BJDebugMsg("Warning: Attempted to get an instance for a null unit!")
    debug return 0
    debug elseif CombopointListener.regTable.exists(u) != true then
    debug call BJDebugMsg("Warning: There is no instance registered for this unit!")
    debug return 0
    debug endif
    return CombopointListener.regTable[u]
endfunction
endlibrary


Changelog

v0.6a
- Renamed globals for a better legibility
- Fixed a small issue with the intern variable dataNum
- Fixed a small issue with the stackRemove method which could cause some problems

v0.6
- Removed BoolexprUtils
- Added an auto-reset via timer
- Added new method (autoReset(boolean))
- resetCPOnTargetSwitch is now a method and also was renamed (resetOnSwitch(boolean))
- Cleaned code (removed most operator overloading and simply renamed the variables)

v0.5b
- Added compatibility for patch 1.24
- Removed return bug

v0.5
- Added more safety for changing current combopoints
- The way how newSpellData workes was changed, it uses now 2D Tables. Now there should be fewer Tables created unfortunately I now have to use the H2I bug, with 1.24 I will update how this works.

v0.4
- Fixed a bug that created a warcraft3 Critical Error when units, which are not registered, cast a spell

v0.3
- Created a constant integer which defines the standard maxCP
- regTable is now a readonly static member of CombopointListener
- There is only one Table left for combopoints (spellData)
- Reworked condition and action methods


v0.2
- Changed the way the trigger is created
- Changed regTable to HandleTable and removed the H2I function


v0.1
- Release
 

Attachments

  • CombopointListener v0.6a.w3x
    18.6 KB · Views: 161
Last edited:
Level 11
Joined
Feb 22, 2006
Messages
752
Use a generic trigger...i.e.:

JASS:
    call TriggerRegisterAnyUnitEventBJ(...)

And then check for conditions inside the trigger conditions (or actions...w/e you want). This way you don't create a new trigger every time you instantiate a struct.

And the following is VERY IMPORTANT:

NEVER DESTROY TRIGGERS. It causes handle stack corruption and screws up your game epicly.

And why not just use HandleTable for regTable? It does all that H2I stuff for you.

Also: youre consuming insane amounts of Table instances.

Depends on how many units are on the map at once. Table's default max instance is 8100, which means this system is still capped at 4050 instances, which is more than enough for any map. BUT...you should still find some other way to store your spell stuff other than Table, since if your system is eating up a bunch of Table instances, other stuff can't use those instances.
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
JASS:
function TriggerRegisterAnyUnitEventBJ takes trigger trig, playerunitevent whichEvent returns nothing
    local integer index

    set index = 0
    loop
        call TriggerRegisterPlayerUnitEvent(trig, Player(index), whichEvent, null)

        set index = index + 1
        exitwhen index == bj_MAX_PLAYER_SLOTS
    endloop
endfunction
No it doesn't.
 
Level 14
Joined
Nov 18, 2007
Messages
816
4050 instances if this is the only library using Table. You cant assume thats the case.

How about using a central register for the rawcodes and points?

JASS:
library CombopointListener requires Table, BoolexprUtils
globals
    private HandleTable regTable = 0
endglobals

struct CombopointListener
    private integer cp = 0
    private integer maxCP = 5
    private boolean b = false

    private unit listenUnit = null
    private unit curTarget = null

    private static Table spellCPPS // <<---
    method operator maxCombopoints takes nothing returns integer
        return .maxCP
    endmethod

    method operator maxCombopoints= takes integer value returns nothing
        set .maxCP = value
    endmethod

    method operator combopoints= takes integer i returns nothing
        set .cp = i
    endmethod

    method operator combopoints takes nothing returns integer
        if .cp == .maxCP then
            return .cp
        endif
        return .cp + 1
    endmethod

    method operator resetCPOnTargetSwitch= takes boolean b returns nothing
        set .b = b
    endmethod

    method resetCombopoints takes nothing returns nothing
        set .cp = 0
    endmethod

    static method newSpellData takes integer rawCode, integer cpps returns nothing
        set .spellCPPS[rawCode] = cpps // <<---
    endmethod

    private static method condition takes nothing returns boolean
        return CombopointListener.spellCPPS.exists(GetSpellAbilityId()) and regTable.exists(GetTriggerUnit()) // <<---
    endmethod

    private static method action takes nothing returns nothing
        local unit u = GetTriggerUnit()
        local unit tar = GetSpellTargetUnit()
        local thistype Dat = regTable[u]
        if Dat.b and tar != Dat.curTarget then // <<---
            call Dat.resetCombopoints()
            set Dat.curTarget = tar
        endif
        set Dat.cp=Dat.cp+Dat.spellCPPS[GetSpellAbilityId()] // <<---
        if Dat.cp> Dat.maxCP then
            set Dat.cp = Dat.maxCP
        endif
        set u = null
        set tar = null
    endmethod

    static method create takes unit u returns thistype
        local thistype Dat = thistype.allocate()
        set Dat.listenUnit = u
        set regTable[u] = Dat
        return Dat
    endmethod

    private method onDestroy takes nothing returns nothing
        call regTable.flush(.listenUnit)
        set .listenUnit = null
        set .curTarget = null
    endmethod

    private static method onInit takes nothing returns nothing
        local trigger int = CreateTrigger()
        local integer i = 0
        loop
            call TriggerRegisterPlayerUnitEvent(int,Player(i),EVENT_PLAYER_UNIT_SPELL_EFFECT,BOOLEXPR_TRUE)
            set i = i + 1
            exitwhen i >= bj_MAX_PLAYER_SLOTS
        endloop
        call TriggerAddCondition(int,Condition(function thistype.condition))
        call TriggerAddAction(int,function thistype.action)
        set regTable = Table.create()
        set CombopointListener.spellCPPS = Table.create()
        set int = null
    endmethod
endstruct

function GetCombopointListener takes unit u returns CombopointListener
    debug if u == null then
    debug     call BJDebugMsg("Warning: Attempted to get an instance for a null unit!")
    debug     return 0
    debug elseif regTable[u] == 0 or regTable[u] == null then
    debug     call BJDebugMsg("Warning: There is no instance registered for this unit!")
    debug     return 0
    debug endif
    return regTable[u]
endfunction
endlibrary

Also, the maxCp should be changeable via a global constant.
 
Level 11
Joined
Feb 22, 2006
Messages
752
4050 instances if this is the only library using Table. You cant assume thats the case.

That's why I tld him to find another method to deal with the spell stuff.

How about using a central register for the rawcodes and points?

Possible, but people might want more flexibility, i.e. one unit gets more from a spell than another for whatever reason.

Personally I think the best option is to simply handle it with events, i.e. whenever a spell cast is detected on a registered unit, a function/method is called that the user can specify that returns how many points the unit gets, and the system handles it after that. This way, if the user wants to use Table for a unit-by-unit basis determination of points, then they have the option. If they want a central register, then once again they can implement it that way, or any other way they see fit.
 
Level 16
Joined
Feb 22, 2006
Messages
960
4050 instances if this is the only library using Table. You cant assume thats the case.

How about using a central register for the rawcodes and points?

JASS:
library CombopointListener requires Table, BoolexprUtils
globals
    private HandleTable regTable = 0
endglobals

struct CombopointListener
    private integer cp = 0
    private integer maxCP = 5
    private boolean b = false

    private unit listenUnit = null
    private unit curTarget = null

    private static Table spellCPPS // <<---
    method operator maxCombopoints takes nothing returns integer
        return .maxCP
    endmethod

    method operator maxCombopoints= takes integer value returns nothing
        set .maxCP = value
    endmethod

    method operator combopoints= takes integer i returns nothing
        set .cp = i
    endmethod

    method operator combopoints takes nothing returns integer
        if .cp == .maxCP then
            return .cp
        endif
        return .cp + 1
    endmethod

    method operator resetCPOnTargetSwitch= takes boolean b returns nothing
        set .b = b
    endmethod

    method resetCombopoints takes nothing returns nothing
        set .cp = 0
    endmethod

    static method newSpellData takes integer rawCode, integer cpps returns nothing
        set .spellCPPS[rawCode] = cpps // <<---
    endmethod

    private static method condition takes nothing returns boolean
        return CombopointListener.spellCPPS.exists(GetSpellAbilityId()) and regTable.exists(GetTriggerUnit()) // <<---
    endmethod

    private static method action takes nothing returns nothing
        local unit u = GetTriggerUnit()
        local unit tar = GetSpellTargetUnit()
        local thistype Dat = regTable[u]
        if Dat.b and tar != Dat.curTarget then // <<---
            call Dat.resetCombopoints()
            set Dat.curTarget = tar
        endif
        set Dat.cp=Dat.cp+Dat.spellCPPS[GetSpellAbilityId()] // <<---
        if Dat.cp> Dat.maxCP then
            set Dat.cp = Dat.maxCP
        endif
        set u = null
        set tar = null
    endmethod

    static method create takes unit u returns thistype
        local thistype Dat = thistype.allocate()
        set Dat.listenUnit = u
        set regTable[u] = Dat
        return Dat
    endmethod

    private method onDestroy takes nothing returns nothing
        call regTable.flush(.listenUnit)
        set .listenUnit = null
        set .curTarget = null
    endmethod

    private static method onInit takes nothing returns nothing
        local trigger int = CreateTrigger()
        local integer i = 0
        loop
            call TriggerRegisterPlayerUnitEvent(int,Player(i),EVENT_PLAYER_UNIT_SPELL_EFFECT,BOOLEXPR_TRUE)
            set i = i + 1
            exitwhen i >= bj_MAX_PLAYER_SLOTS
        endloop
        call TriggerAddCondition(int,Condition(function thistype.condition))
        call TriggerAddAction(int,function thistype.action)
        set regTable = Table.create()
        set CombopointListener.spellCPPS = Table.create()
        set int = null
    endmethod
endstruct

function GetCombopointListener takes unit u returns CombopointListener
    debug if u == null then
    debug     call BJDebugMsg("Warning: Attempted to get an instance for a null unit!")
    debug     return 0
    debug elseif regTable[u] == 0 or regTable[u] == null then
    debug     call BJDebugMsg("Warning: There is no instance registered for this unit!")
    debug     return 0
    debug endif
    return regTable[u]
endfunction
endlibrary

Also, the maxCp should be changeable via a global constant.

yep I will make a global representing the standard maxCP

actually I try to find a better way to store the cpps, the thing with the method (aznricepuff) would make each spell get the same combopoints per spell , but my idea was to create an individual increasement of combopoints
 
Last edited:
Level 11
Joined
Feb 22, 2006
Messages
752
the thing with the method (aznricepuff) would make each spell get the same combopoints per spell

You misunderstand. My idea is to have something like this:

JASS:
method onSpellCast takes unit u, integer spellId returns integer
    return 0
endmethod

The user simply overrides the method and returns w/e number of points he wishes to add (or even subtract, maybe). The system handles the rest of the stuff after that.
 
Level 11
Joined
Feb 22, 2006
Messages
752
Either something like this:

JASS:
function interface SpellCastEvent takes unit caster, integer spellId returns integer

struct ComboPointListener
    private SpellCastEvent onCast
    // ...
    static method create takes ... SpellCastEvent onCast returns ComboPointListener
        local ComboPointListener this = ComboPointListener.allocate()
        set this.onCast = onCast
    endmethod
    // ...
    private static method action takes nothing returns nothing
        local unit u = GetTriggerUnit()
        local unit tar = GetSpellTargetUnit()
        local thistype Dat = thistype.regTable[u]
        if Dat.b and tar != Dat.curTarget then
            call Dat.resetCombopoints()
            set Dat.curTarget = tar
        endif
        set Dat.cp = Dat.cp + .onCast.evaluate(u, GetSpellAbilityId())
        if Dat.cp > Dat.maxCP then
            set Dat.cp = Dat.maxCP
        endif
        set u = null
        set tar = null
    endmethod
    // ...
endstruct

// ...
// And the user would do something like this:

library A

globals
    private Table table
endglobals

private function OnCastOne takes unit u, integer spellId returns integer
    return 1 // always adds one combo point on spell cast
endfunction

private function OnCastTwo takes unit u, integer spellId returns integer
    return table[spellId] // adds combo point based on global spell data
endfunction

private function RegisterUnitOne takes unit u returns nothing
    call ComboPointListener.create(u, SpellCastEvent.OnCastOne)
endfunction

private function RegisterUnitTwo takes u returns nothing
    call ComboPointListener.create(u, SpellCastEvent.OnCastTwo)
endfunction

endlibrary

or: make a stub method in ComboPointListener called "onSpellCast" or something and have users extend ComboPointListener with their own structs and instantiate those instead of directly instantiating ComboPointListener (in this case you should make the unit the struct is listening to visible; either make the instance field public or use a method operator):

JASS:
struct ComboPointListener
    // ...
    method operator u takes nothing returns unit
        return .listenUnit
    endmethod
    stub method onSpellCast takes integer spellId returns integer
        return 0
    endmethod
    // ...
    private static method action takes nothing returns nothing
        local unit u = GetTriggerUnit()
        local unit tar = GetSpellTargetUnit()
        local thistype Dat = thistype.regTable[u]
        if Dat.b and tar != Dat.curTarget then
            call Dat.resetCombopoints()
            set Dat.curTarget = tar
        endif
        set Dat.cp = Dat.cp + .onSpellCast(GetSpellAbilityId())
        if Dat.cp > Dat.maxCP then
            set Dat.cp = Dat.maxCP
        endif
        set u = null
        set tar = null
    endmethod
    // ...
endstruct

// ...
// And the user would do something like this:

library A

globals
    private Table table
endglobals

struct MyComboListenerOne extends ComboPointListener
    // ...
    stub method onSpellCast takes integer spellId returns integer
        return 1
    endmethod
    // ...
endstruct

struct MyComboListenerTwo extends ComboPointListener
    // ...
    stub method onSpellCast takes integer spellId returns integer
        return table[spellId]
    endmethod
    // ...
endstruct

endlibrary

This way the user determines how the combo points are calculated. I personally prefer the struct extending method since it allows for more customization, but either way is fine.
 
Level 16
Joined
Feb 22, 2006
Messages
960
naa, I would change that in the next patch, but handletable isn't what I need if you read through it, the way I do it, is manipulating the string which saves it into the gc :), therefore only a 2D Table solves my prob

edit: Updated to new version 0.5b => now there is a no use of return bug
 
Last edited:
Level 11
Joined
Feb 22, 2006
Messages
752
Ok, this system as it is right now is too limited for me to approve. I think the KEY thing missing here is a lack of functionality for having combo points reset to 0 after a certain time limit (it doesn't make sense if I can keep getting combos even after 5 min of inactivity). Another thing is that combo points are reset whenever you cast a spell on a different target, which probably makes sense most of the time, but there's definitely cases where a user might not want this. You should give them the option to choose.

And once again more flexibility with awarding combo points would be nice (but I'm prepared to approve this even if this one isn't implemented). Like I said earlier, you can either use function interfaces or stub methods for this, or some other way. I don't really care as long as it works.
 
Level 8
Joined
Oct 3, 2008
Messages
367
Good to see that you've come to fix it up.

First, using that single global timer... I'm quite sure that that'll cause MUI issues.

Second, you should merge your conditions and actions to reduce code length and function calls.

Third, and least important, you should probably give your constant globals STANDARD_NAMING_SCHEMES.
 
Level 16
Joined
Feb 22, 2006
Messages
960
1. One global Timer doesn't cause MUI issues
2. I won't merge the action/condition functions to reduce count of function calls.
there wouldn't be less lines. It's also much better readable like this
3. Yes this thing could be done, I will update this.

Updated to v0.6a
 
Level 8
Joined
Oct 3, 2008
Messages
367
>One global Timer doesn't cause MUI issues

So you tested automatic combopoint decay on multiple units, then?

>there wouldn't be less lines. It's also much better readable like this

YOU LIE.

JASS:
private static method condition takes nothing returns boolean
        local unit u = GetTriggerUnit()
        local thistype this = thistype.regTable[u]
        local boolean b = false
        if this != 0 or this != null then
            set b = Table[I2S(GetHandleId(u))].exists(GetSpellAbilityId())
        endif
        set u = null
        return b
    endmethod

    private static method action takes nothing returns nothing
        local unit u = GetTriggerUnit()
        local unit tar = GetSpellTargetUnit()
        local thistype this = thistype.regTable[u]
        if this.onSwitch and tar != this.curTarget then
            call this.resetCombopoints()
            set this.curTarget = tar
        endif
        set this.cp = this.cp + Table[I2S(GetHandleId(u))][GetSpellAbilityId()]
        if this.cp > this.maxCombopoints then
            set this.cp = this.maxCombopoints
        endif
        set this.time = 0.0
        set u = null
        set tar = null
    endmethod

Something like this looks much better, methinks. Well that is if I'm Tabling correctly. I feel I made a mistake somewhere. I don't use Table.
JASS:
private static method condition takes nothing returns boolean
    local unit u = GetTriggerUnit()
    local unit tar = GetSpellTargetUnit()
    local thistype this = thistype.regTable[u]
    local Table tb
    if this != 0 or this != null then
        set tb = Table[I2S(GetHandleId(u))][GetSpellAbilityId()]
        if tb.exists() then
            if this.onSwitch and tar != this.curTarget then
                call this.resetCombopoints()
                set this.curTarget = tar
            endif
            set this.cp = this.cp + tb
            if this.cp > this.maxCombopoints then
                set this.cp = this.maxCombopoints
            endif
            set this.time = 0
        endif
    endif
    set u = null
    set tar = null
endmethod
 
Level 8
Joined
Oct 3, 2008
Messages
367
I know my example won't work. I don't use Table.

And yes, it doesn't return anything. That was an error.

>ehm like I said with actions it's better readable

I find the combination to be much more readable. And it's more efficient, and shorter.
 
Top