| 09-25-2008, 02:12 AM | #1 |
JASS:library HR globals private constant real BASE = 5. private constant real LVL_FACTOR = 1.5 endglobals public struct Revive unit a real x real y timer t = CreateTimer() boolean eyecandy = true static method Callback takes nothing returns nothing local Revive dat = Revive.allocate() call ReviveHero(dat.a, dat.x, dat.y, dat.eyecandy) endmethod method Set takes unit a, real x, real y returns nothing local Revive dat = Revive.create() local real Lvl = R2I(GetHeroLevel(a)) set dat.a = a set dat.y = y set dat.x = x call TimerStart(dat.t, BASE+(LVL_FACTOR*Lvl), false, function Revive.Callback) endmethod method Eyecandy takes boolean b returns nothing set this.eyecandy = b endmethod endstruct endlibrary I don't know if the static part is used correctly and I'm pretty sure I'm missing something on the timers. In fact, I think i messed the entire thing up. Some help? Also, are static methods are method that other methods can call? Are non-static methods ever allowed to be called by another method? Operator Q: example from jass maunal:struct operatortest string str="" method operator [] takes integer i returns string return SubString(.str,i,i+1) endmethod method operator[]= takes integer i, string ch returns nothing set .str=SubString(.str,0,i)+ch+SubString(.str,i+1,StringLength(.str)-i) endmethod endstruct function test takes nothing returns nothing local operatortest x=operatortest.create() set x.str="Test" call BJDebugMsg( x[1]) call BJDebugMsg( x[0]+x[3]) set x[1] = "." call BJDebugMsg( x.str) endfunction |
| 09-25-2008, 02:35 AM | #2 |
operator[]= is called when you set x[1] = ".". As for the revive thing, you need a storage method (TimerUtils, gamecache, etc) to pass the struct to the callback. |
| 09-25-2008, 02:47 AM | #3 |
JASS:library HR uses TimerUtils globals private constant real BASE = 5. private constant real LVL_FACTOR = 1.5 endglobals public struct Revive unit a real x real y timer t boolean eyecandy static method Callback takes nothing returns nothing local Revive dat = GetTimerData(GetExpiredTimer()) call ReviveHero(dat.a, dat.x, dat.y, dat.eyecandy) call dat.destroy() //Do I need this? call ReleaseTimer(dat.t) endmethod static method Set takes unit a, real x, real y, boolean eyecandy returns Revive local Revive dat = Revive.create() local real Lvl = R2I(GetHeroLevel(a)) set dat.a = a set dat.y = y set dat.x = x set dat.t = NewTimer() set dat.eyecandy = eyecandy call SetTimerData(dat.t, dat) call TimerStart(dat.t, BASE+(LVL_FACTOR*Lvl), false, function Revive.Callback) return dat endmethod endstruct endlibrary |
| 09-25-2008, 03:02 AM | #4 |
To answer your question about static methods: Any static struct members (methods, objects, variables, etc) are those that behave like global variables in that they don't associate themselves with one struct instance and you can do whatever you want with their values indefinitely. The reason that timer callbacks in structs are static are because code arguments have to be unrelated to a specific structural instances. So, like PurplePoot said, you have to associate an integer (your struct instance) with every timer that you create for the callback method to recognize the proper instance (which you've done). You can always call static methods whenever you want, think of them as regular old JASS functions. Static methods can't refer to specific instances, but on the other hand regular methods are restricted by the instance you call them with (instancename.method()) and can't do anything without knowing the right instance. Your methods and struct look fine. |
| 09-25-2008, 09:45 PM | #5 |
Yeah, that's all right. |
| 09-26-2008, 01:42 AM | #6 |
This is not related to the trigger above: Is it not possible for static methods to get instances without some passer function like ABC? |
| 09-26-2008, 01:46 AM | #7 |
No, they're just functions. Also, as far as attachment systems go, I'd recommend not bothering with ABC. Either go TimerUtils or just gamecache the struct (then there are better methods for fast-running timers for spells and such). |
| 09-26-2008, 01:48 AM | #8 |
I need one for passing through triggers. |
| 09-26-2008, 01:52 AM | #9 |
can he, alternatively, just find w/c Revive instance's timer == the expired timer to identify the Revive instance associated with the timer expiration event? is this less efficient? also, what is the point of keeping the callback function inside the struct? "packaging"? what if i use a global timer? would "packaging" be good in this case or should i keep the callback as a function outside the struct since the timer is global? also, GetTimerData() and ReleaseTimerData() don't show up green in my editor. they extra natives or part of some system? |
| 09-26-2008, 02:01 AM | #10 | |||
In that case, I'd just use gamecache, Joker. However, why you need to pass data through triggers is beyond me. You shouldn't ever have to. -- Quote:
Quote:
Quote:
|
| 09-26-2008, 02:20 AM | #11 |
>However, why you need to pass data through triggers is beyond me. You shouldn't ever have to. Well, I'm trying to make a temp damage detection for things like shields, damage amp, etc. so that I don't have to mess with big damage detection systems. |
| 09-26-2008, 02:34 AM | #12 |
Yes fx_ you can use array lookup, but as Vexorian pointed out to me it is O(n) time complex and is much more taxing on the processor than simply looking up the array with TimerUtils hashtable. I dunno Joker, I've heard coding damage detection systems is very difficult, but its up to you if you can figure it out :P. |
| 09-26-2008, 03:48 AM | #13 |
Depends on how he retrieves his data (algorithm), linear searches are O(n) but a good hashing algorithm would only take O(1) time, like what's being used in TimerUtils (an exception is when the handle count gets past 1056766 (0x 000F FFFF + [0x 0FFF * 2]) EDIT: wait I was wrong in my statement about TimerUtils lol Taken from the TimerUtils thread: The flavors: Blue TimerUtils - Uses CSData's attaching method - Function call, subtraction, O(log(n)) comparisons, array lookup + H2I - The only condition for it to work in your map is that you never exceed 408000 handle ids in it. This limit is very big. Red TimerUtils - Uses the mass timers at init method. - array lookup, subtraction, H2I (Get/SetTimerData get inlined) - Therefore Red flavor is much faster. - However, Red flavor has a timer limit of 256, once you exceed this limit, it might fail to work. - It also requires to create 256 timers in the initializer. |
| 09-26-2008, 06:11 AM | #14 |
simple damage detection i made for my map. all it does is register for all EVENT_UNIT_DAMAGED damaged triggers the event for each unit. JASS://///DAMAGE DETECTION SYSTEM START///// scope DamageDetectionSystem globals private trigger gTRIG_EnterMap private group gUG_Target //index of all EVENT_UNIT_DAMAGED event-concerned units private trigger array gTRIG_Damage private integer gINT_CountTrigger = 0 //count of 'EventDamageTrigger's duh... endglobals //Updates index of all EVENT_UNIT_DAMAGED concerned units. (so redundant unit event triggers won't be //appended to triggers. private function UpdateTargetGroup takes nothing returns nothing local unit U_Target local group UG_Target = CreateGroup() call GroupAddGroup(gUG_Target, UG_Target) call GroupClear(gUG_Target) loop set U_Target = FirstOfGroup(UG_Target) exitwhen U_Target == null if U_Target != null and IsUnitInRegion(gREG_Map, U_Target) then call GroupAddUnit(gUG_Target, U_Target) endif call GroupRemoveUnit(UG_Target, U_Target) endloop call DestroyGroup(UG_Target) set UG_Target = null set U_Target = null endfunction //Updates index concerned units with the new entering unit and appends the EVENT_UNIT_DAMAGED event for it to all //instanciated triggers. private function gTRIG_EnterMap_Actions takes nothing returns nothing local unit U_Target = GetTriggerUnit() local integer INT_CountTrigger = 0 //Update the group then index unit into it. call UpdateTargetGroup() call GroupAddUnit(gUG_Target, U_Target) //Appends EVENT_UNIT_DAMAGED for new unit to all concerned triggers (if there currently are any). if gINT_CountTrigger > 0 then loop set INT_CountTrigger = INT_CountTrigger + 1 call TriggerRegisterUnitEvent(gTRIG_Damage[INT_CountTrigger], U_Target, EVENT_UNIT_DAMAGED) exitwhen INT_CountTrigger == gINT_CountTrigger endloop endif set U_Target = null endfunction //Instanciates a trigger and appends to it EVENT_UNIT_DAMAGED events for all concerned (indexed) units. function AddEventDamageTrigger takes trigger whichTrigger returns nothing local unit U_Target local group UG_Target = CreateGroup() set gINT_CountTrigger = gINT_CountTrigger + 1 set gTRIG_Damage[gINT_CountTrigger] = whichTrigger //Appends EVENT_UNIT_DAMAGED to added trigger for all concerned units (if there currently are any). call GroupAddGroup(gUG_Target, UG_Target) loop set U_Target = FirstOfGroup(UG_Target) exitwhen U_Target == null call TriggerRegisterUnitEvent(whichTrigger, U_Target, EVENT_UNIT_DAMAGED) call GroupRemoveUnit(UG_Target, U_Target) endloop call DestroyGroup(UG_Target) set UG_Target = null set U_Target = null endfunction //Initializer; Indexes all concerned units in the map and sets-up the trigger that indexes //units that enter the map. public function Init takes nothing returns nothing set gTRIG_EnterMap = CreateTrigger() call TriggerRegisterEnterRegion(gTRIG_EnterMap, gREG_Map, null) call TriggerAddAction(gTRIG_EnterMap, function gTRIG_EnterMap_Actions) set gUG_Target = CreateGroup() call GroupEnumUnitsInRect(gUG_Target, gRECT_Map, null) endfunction endscope /////DAMAGE DETECTION SYSTEM END///// JASS:... private function DamageSpellInit takes nothing returns nothing local trigger spell = CreateTrigger() call AddEventDamageTrigger(spell) call TriggerAddCondition(...) call TriggerAddAction(...) endfunction ... |
| 09-26-2008, 10:40 AM | #15 | ||
Quote:
Quote:
|
