PurplePoot who reminded me to use a generic trigger
aznricepuff for general and upcoming help
Script 1.24
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
globalsprivateconstantinteger STANDARD_MAX_CP =5privateconstantreal STANDARD_INTERVAL =0.03125endglobalsstruct CombopointListener
publicinteger maxCombopoints = STANDARD_MAX_CP
publicreal autoResetTime =90.0privateinteger cp =0privateboolean autoR =falseprivateboolean onSwitch =trueprivateunit listenUnit =nullprivateunit curTarget =nullprivatereal time =0.0privateinteger dataNum =0privatestaticinteger size =0privatestaticthistypearray data
privatestatictimer tim
readonlystatic HandleTable regTable =0methodoperator combopoints=takesinteger i returnsnothingdebugif i >this.maxCombopointsor i <0thendebugcallBJDebugMsg("Warning: This number isn't supported by the system!")returndebugendifdebugsetthis.cp= i
endmethodmethodoperator combopoints takesnothingreturnsintegerreturnthis.cpendmethodmethod resetCombopoints takesnothingreturnsnothingsetthis.cp=0endmethodmethod newSpellData takesinteger rawCode,integer cpps returnsnothingset Table[I2S(GetHandleId(this.listenUnit))][rawCode]= cpps
endmethodstaticmethod autoResetCallback takesnothingreturnsnothinglocalinteger i =0localthistypethisloopexitwhen i >=thistype.sizesetthis=thistype.data[i]setthis.time=this.time+ STANDARD_INTERVAL
ifthis.time>=this.autoResetTimethencallthis.resetCombopoints()setthis.time=0.0endifendloopifthis.size==0thencallPauseTimer(this.tim)endifendmethodmethod autoReset takesboolean b returnsnothingif b thenifthis.size==0thencallTimerStart(this.tim,STANDARD_INTERVAL,true,functionthistype.autoResetCallback)endifsetthis.dataNum=this.sizesetthis.data[this.size]=thissetthis.size=this.size+1setthis.autoR=trueelseifthis.size>0andthis.autoRthencallthis.stackRemove()setthis.autoR=falseendifendmethodprivatemethod stackRemove takesnothingreturnsnothingifthis.size>1thensetthis.size=this.size-1setthis.data[this.dataNum]=this.data[this.size]setthis.data[this.size]=0setthis.data[this.dataNum].dataNum=this.dataNumelsesetthis.size=this.size-1setthis.data[this.size]=0endififthis.size==0thencallPauseTimer(this.tim)endifendmethodprivatestaticmethod condition takesnothingreturnsbooleanlocalunit u =GetTriggerUnit()localthistypethis=thistype.regTable[u]localboolean b =falseifthis!=0orthis!=nullthenset b = Table[I2S(GetHandleId(u))].exists(GetSpellAbilityId())endifset u =nullreturn b
endmethodprivatestaticmethod action takesnothingreturnsnothinglocalunit u =GetTriggerUnit()localunit tar =GetSpellTargetUnit()localthistypethis=thistype.regTable[u]ifthis.onSwitchand tar !=this.curTargetthencallthis.resetCombopoints()setthis.curTarget= tar
endifsetthis.cp=this.cp+ Table[I2S(GetHandleId(u))][GetSpellAbilityId()]ifthis.cp>this.maxCombopointsthensetthis.cp=this.maxCombopointsendifsetthis.time=0.0set u =nullset tar =nullendmethodstaticmethod create takesunit u returnsthistypelocalthistypethis=thistype.allocate()setthis.listenUnit= u
setthistype.regTable[u]=thisreturnthisendmethodprivatemethod onDestroy takesnothingreturnsnothingifthis.autoRthencallthis.stackRemove()endifcallthis.regTable.flush(this.listenUnit)call Table.flush2D(I2S(GetHandleId(this.listenUnit)))setthis.listenUnit=nullsetthis.curTarget=nullendmethodprivatestaticmethod onInit takesnothingreturnsnothinglocaltrigger int =CreateTrigger()localinteger i =0loopcallTriggerRegisterPlayerUnitEvent(int,Player(i),EVENT_PLAYER_UNIT_SPELL_EFFECT,null)set i = i +1exitwhen i >=bj_MAX_PLAYER_SLOTSendloopcallTriggerAddCondition(int,Condition(functionthistype.condition))callTriggerAddAction(int,functionthistype.action)setthistype.regTable= HandleTable.create()setthistype.tim=CreateTimer()set int =nullendmethodendstructfunction GetCombopointListener takesunit u returns CombopointListener
debugif u ==nullthendebugcallBJDebugMsg("Warning: Attempted to get an instance for a null unit!")debugreturn0debugelseif CombopointListener.regTable.exists(u)!=truethendebugcallBJDebugMsg("Warning: There is no instance registered for this unit!")debugreturn0debugendifreturn CombopointListener.regTable[u]endfunctionendlibrary
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.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
__________________
My Spells & Systems
Last edited by xD.Schurke; 02-06-2010 at 09:19 AM.
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.
Quote:
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.
ok I will fix the Trigger stuff will move it to onInit etc. also I will use handletable for saving lines, by the way TriggerRegisterAnyUnitEvent leaks,
will rework it ;)
functionTriggerRegisterAnyUnitEventBJtakestrigger trig,playerunitevent whichEvent returnsnothinglocalinteger index
set index =0loopcallTriggerRegisterPlayerUnitEvent(trig,Player(index), whichEvent,null)set index = index +1exitwhen index ==bj_MAX_PLAYER_SLOTSendloopendfunction
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?
Sample:
Jass:
library CombopointListener requires Table, BoolexprUtils
globalsprivate HandleTable regTable =0endglobalsstruct CombopointListener
privateinteger cp =0privateinteger maxCP =5privateboolean b =falseprivateunit listenUnit =nullprivateunit curTarget =nullprivatestatic Table spellCPPS // <<---methodoperator maxCombopoints takesnothingreturnsintegerreturn.maxCPendmethodmethodoperator maxCombopoints=takesinteger value returnsnothingset.maxCP= value
endmethodmethodoperator combopoints=takesinteger i returnsnothingset.cp= i
endmethodmethodoperator combopoints takesnothingreturnsintegerif.cp==.maxCPthenreturn.cpendifreturn.cp+1endmethodmethodoperator resetCPOnTargetSwitch=takesboolean b returnsnothingset.b= b
endmethodmethod resetCombopoints takesnothingreturnsnothingset.cp=0endmethodstaticmethod newSpellData takesinteger rawCode,integer cpps returnsnothingset.spellCPPS[rawCode]= cpps // <<---endmethodprivatestaticmethod condition takesnothingreturnsbooleanreturn CombopointListener.spellCPPS.exists(GetSpellAbilityId())and regTable.exists(GetTriggerUnit())// <<---endmethodprivatestaticmethod action takesnothingreturnsnothinglocalunit u =GetTriggerUnit()localunit tar =GetSpellTargetUnit()localthistype Dat = regTable[u]if Dat.band tar != Dat.curTargetthen// <<---call Dat.resetCombopoints()set Dat.curTarget= tar
endifset Dat.cp=Dat.cp+Dat.spellCPPS[GetSpellAbilityId()]// <<---if Dat.cp> Dat.maxCPthenset Dat.cp= Dat.maxCPendifset u =nullset tar =nullendmethodstaticmethod create takesunit u returnsthistypelocalthistype Dat =thistype.allocate()set Dat.listenUnit= u
set regTable[u]= Dat
return Dat
endmethodprivatemethod onDestroy takesnothingreturnsnothingcall regTable.flush(.listenUnit)set.listenUnit=nullset.curTarget=nullendmethodprivatestaticmethod onInit takesnothingreturnsnothinglocaltrigger int =CreateTrigger()localinteger i =0loopcallTriggerRegisterPlayerUnitEvent(int,Player(i),EVENT_PLAYER_UNIT_SPELL_EFFECT,BOOLEXPR_TRUE)set i = i +1exitwhen i >=bj_MAX_PLAYER_SLOTSendloopcallTriggerAddCondition(int,Condition(functionthistype.condition))callTriggerAddAction(int,functionthistype.action)set regTable = Table.create()set CombopointListener.spellCPPS= Table.create()set int =nullendmethodendstructfunction GetCombopointListener takesunit u returns CombopointListener
debugif u ==nullthendebugcallBJDebugMsg("Warning: Attempted to get an instance for a null unit!")debugreturn0debugelseif regTable[u]==0or regTable[u]==nullthendebugcallBJDebugMsg("Warning: There is no instance registered for this unit!")debugreturn0debugendifreturn regTable[u]endfunctionendlibrary
Also, the maxCp should be changeable via a global constant.
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.
Quote:
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.
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?
Sample:
Jass:
library CombopointListener requires Table, BoolexprUtils
globalsprivate HandleTable regTable =0endglobalsstruct CombopointListener
privateinteger cp =0privateinteger maxCP =5privateboolean b =falseprivateunit listenUnit =nullprivateunit curTarget =nullprivatestatic Table spellCPPS // <<---methodoperator maxCombopoints takesnothingreturnsintegerreturn.maxCPendmethodmethodoperator maxCombopoints=takesinteger value returnsnothingset.maxCP= value
endmethodmethodoperator combopoints=takesinteger i returnsnothingset.cp= i
endmethodmethodoperator combopoints takesnothingreturnsintegerif.cp==.maxCPthenreturn.cpendifreturn.cp+1endmethodmethodoperator resetCPOnTargetSwitch=takesboolean b returnsnothingset.b= b
endmethodmethod resetCombopoints takesnothingreturnsnothingset.cp=0endmethodstaticmethod newSpellData takesinteger rawCode,integer cpps returnsnothingset.spellCPPS[rawCode]= cpps // <<---endmethodprivatestaticmethod condition takesnothingreturnsbooleanreturn CombopointListener.spellCPPS.exists(GetSpellAbilityId())and regTable.exists(GetTriggerUnit())// <<---endmethodprivatestaticmethod action takesnothingreturnsnothinglocalunit u =GetTriggerUnit()localunit tar =GetSpellTargetUnit()localthistype Dat = regTable[u]if Dat.band tar != Dat.curTargetthen// <<---call Dat.resetCombopoints()set Dat.curTarget= tar
endifset Dat.cp=Dat.cp+Dat.spellCPPS[GetSpellAbilityId()]// <<---if Dat.cp> Dat.maxCPthenset Dat.cp= Dat.maxCPendifset u =nullset tar =nullendmethodstaticmethod create takesunit u returnsthistypelocalthistype Dat =thistype.allocate()set Dat.listenUnit= u
set regTable[u]= Dat
return Dat
endmethodprivatemethod onDestroy takesnothingreturnsnothingcall regTable.flush(.listenUnit)set.listenUnit=nullset.curTarget=nullendmethodprivatestaticmethod onInit takesnothingreturnsnothinglocaltrigger int =CreateTrigger()localinteger i =0loopcallTriggerRegisterPlayerUnitEvent(int,Player(i),EVENT_PLAYER_UNIT_SPELL_EFFECT,BOOLEXPR_TRUE)set i = i +1exitwhen i >=bj_MAX_PLAYER_SLOTSendloopcallTriggerAddCondition(int,Condition(functionthistype.condition))callTriggerAddAction(int,functionthistype.action)set regTable = Table.create()set CombopointListener.spellCPPS= Table.create()set int =nullendmethodendstructfunction GetCombopointListener takesunit u returns CombopointListener
debugif u ==nullthendebugcallBJDebugMsg("Warning: Attempted to get an instance for a null unit!")debugreturn0debugelseif regTable[u]==0or regTable[u]==nullthendebugcallBJDebugMsg("Warning: There is no instance registered for this unit!")debugreturn0debugendifreturn regTable[u]endfunctionendlibrary
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
__________________
My Spells & Systems
Last edited by xD.Schurke; 06-07-2009 at 09:57 AM.
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.
functioninterface SpellCastEvent takesunit caster,integer spellId returnsintegerstruct ComboPointListener
private SpellCastEvent onCast
// ...staticmethod create takes ... SpellCastEvent onCast returns ComboPointListener
local ComboPointListener this= ComboPointListener.allocate()setthis.onCast= onCast
endmethod// ...privatestaticmethod action takesnothingreturnsnothinglocalunit u =GetTriggerUnit()localunit tar =GetSpellTargetUnit()localthistype Dat =thistype.regTable[u]if Dat.band tar != Dat.curTargetthencall Dat.resetCombopoints()set Dat.curTarget= tar
endifset Dat.cp= Dat.cp+.onCast.evaluate(u,GetSpellAbilityId())if Dat.cp> Dat.maxCPthenset Dat.cp= Dat.maxCPendifset u =nullset tar =nullendmethod// ...endstruct// ...// And the user would do something like this:library A
globalsprivate Table table
endglobalsprivatefunction OnCastOne takesunit u,integer spellId returnsintegerreturn1// always adds one combo point on spell castendfunctionprivatefunction OnCastTwo takesunit u,integer spellId returnsintegerreturn table[spellId]// adds combo point based on global spell dataendfunctionprivatefunction RegisterUnitOne takesunit u returnsnothingcall ComboPointListener.create(u, SpellCastEvent.OnCastOne)endfunctionprivatefunction RegisterUnitTwo takes u returnsnothingcall ComboPointListener.create(u, SpellCastEvent.OnCastTwo)endfunctionendlibrary
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
// ...methodoperator u takesnothingreturnsunitreturn.listenUnitendmethodstubmethod onSpellCast takesinteger spellId returnsintegerreturn0endmethod// ...privatestaticmethod action takesnothingreturnsnothinglocalunit u =GetTriggerUnit()localunit tar =GetSpellTargetUnit()localthistype Dat =thistype.regTable[u]if Dat.band tar != Dat.curTargetthencall Dat.resetCombopoints()set Dat.curTarget= tar
endifset Dat.cp= Dat.cp+.onSpellCast(GetSpellAbilityId())if Dat.cp> Dat.maxCPthenset Dat.cp= Dat.maxCPendifset u =nullset tar =nullendmethod// ...endstruct// ...// And the user would do something like this:library A
globalsprivate Table table
endglobalsstruct MyComboListenerOne extends ComboPointListener
// ...stubmethod onSpellCast takesinteger spellId returnsintegerreturn1endmethod// ...endstructstruct MyComboListenerTwo extends ComboPointListener
// ...stubmethod onSpellCast takesinteger spellId returnsintegerreturn table[spellId]endmethod// ...endstructendlibrary
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.
uh, the second thing was the one i was thinking about but i prefer the function interface ;). There is only one thing I don't like, therefor the user would have to create a listener for each spell