| 02-11-2008, 11:54 AM | #1 |
http://www.wc3campaigns.net/showthread.php?t=90186 In response to this, it helped answer my question of why my map slowed down and got choppy at times. This function, for example runs every 2 seconds on a timer while the building's ability is active for at most 30 seconds: JASS:private function FrostInfliction takes nothing returns nothing local integer t = ST_GetExpiredTimer() local integer level = ST_GetInt1(t) local unit cast = ST_GetUnit1(t) local unit u local group g = CreateGroup() local real x = ST_GetReal1(t) local real y = ST_GetReal2(t) local integer i = GetPlayerId(GetOwningPlayer(cast)) local boolexpr cond = Condition(function FrostFilter) if GetUnitAbilityLevel(cast,'B00I') > 0 and GetUnitState(cast, UNIT_STATE_LIFE) > 0 then call GroupEnumUnitsInRangeCounted(g,x,y,1000.00, cond, 5) loop set u = FirstOfGroup(g) exitwhen u == null if (GetUnitAbilityLevel(u,'B00C') > 0) then call UnitRemoveAbility(u,'B00C') call CasterCastAbility(Player(i), 'A02O', "cripple", u, true) // Level 2 Slow elseif (GetUnitAbilityLevel(u,'B00E') > 0) then call UnitRemoveAbility(u,'B00E') call CasterCastAbility(Player(i), 'A02R', "cripple", u, true) // Level 3 Slow elseif (GetUnitAbilityLevel(u,'B00H') > 0) then call UnitRemoveAbility(u,'B00H') call CasterCastAbility(Player(i), 'A02G', "thunderbolt", u, true) // Stun elseif (GetUnitAbilityLevel(u,'B00G') > 0) then call UnitRemoveAbility(u,'B00G') call UnitDamageTarget(cast, u, 50, true, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, null ) call SpecialEffectTarget( "Abilities\\Spells\\Undead\\FrostNova\\FrostNovaTarget.mdl", u, "origin", 2) else call CasterCastAbility(Player(i), 'A02H', "cripple", u, true) // Level 1 Slow endif call GroupRemoveUnit(g,u) endloop call DestroyGroup(g) else call ST_Destroy(t) endif call DestroyBoolExpr(cond) set cond = null set u = null set g = null set cast = null endfunction |
| 02-11-2008, 12:08 PM | #2 |
What attachment system are you using? I have never heard of ST. If you are using vJASS (new gen jass), then a better approach than attaching everything is to use structs for this. Might give you quite a speed boost. JASS:struct FrostInflictionData integer level unit unit1 endstruct function FrostInfliction takes nothing returns nothing local FrostInflictionData t=ST_GetExpiredTimer() local integer level=t.level local integer cast=t.unit1 // etc... endfunction Vexorian has published a nice manual on structs here. If you feel really at home with vJASS, then the currently best option would probably be Cohadar's collections (since you mentioned that this script may be used by a lot of units at the same time). You can find them under resources. |
| 02-11-2008, 12:16 PM | #3 | |
Quote:
Oh I'm using SafeTimers from the resources section. I never really had a good grasp on structs, and it's still confusing me on how to use it (object oriented programming class never really sunk in). How can I use it to relieve the groupenum spam? |
| 02-11-2008, 12:34 PM | #4 |
You cannot use it to relieve "GroupEnumSpam". Still, I think that the main issue with your code is not GroupEnum. Attaching is a known performance eater, and most people around here seems to try to reduce it as much as possible. In other words, I think your script would run a bit faster if you reduced the number of attachments. With structs, your code would look somthing like: JASS:struct FrostInflictionData integer level unit cast real x real y endstruct private function FrostInfliction takes nothing returns nothing local integer i = ST_GetExpiredTimer() local FrostInflictionData t=ST_GetInt1(i) local integer level=t.level local unit cast=t.cast local unit u local group g = CreateGroup() local real x=t.x local real y=t.y local integer i=GetPlayerId(GetOwningPlayer(cast)) local boolexpr cond=Condition(function FrostFilter) if GetUnitAbilityLevel(cast,'B00I') > 0 and GetUnitState(cast, UNIT_STATE_LIFE) > 0 then call GroupEnumUnitsInRangeCounted(g,x,y,1000.00, cond, 5) loop set u = FirstOfGroup(g) exitwhen u == null if (GetUnitAbilityLevel(u,'B00C') > 0) then call UnitRemoveAbility(u,'B00C') call CasterCastAbility(Player(i), 'A02O', "cripple", u, true) // Level 2 Slow elseif (GetUnitAbilityLevel(u,'B00E') > 0) then call UnitRemoveAbility(u,'B00E') call CasterCastAbility(Player(i), 'A02R', "cripple", u, true) // Level 3 Slow elseif (GetUnitAbilityLevel(u,'B00H') > 0) then call UnitRemoveAbility(u,'B00H') call CasterCastAbility(Player(i), 'A02G', "thunderbolt", u, true) // Stun elseif (GetUnitAbilityLevel(u,'B00G') > 0) then call UnitRemoveAbility(u,'B00G') call UnitDamageTarget(cast, u, 50, true, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, null ) call SpecialEffectTarget( "Abilities\\Spells\\Undead\\FrostNova\\FrostNovaTarget.mdl", u, "origin", 2) else call CasterCastAbility(Player(i), 'A02H', "cripple", u, true) // Level 1 Slow endif call GroupRemoveUnit(g,u) endloop call DestroyGroup(g) else call t.destroy() call ST_Destroy(i) endif call DestroyBoolExpr(cond) set cond = null set u = null set g = null set cast = null endfunction And the creation: JASS:local FrostInflictionData t=FrostInflictionData.create() //set t.cast=The Casting Unit //set t.x=The X Point //set t.y=The Y Point // etc. // IMPORTANT // You have to attach the FrostInflictionData as Int1. Also, I think I recall that Vexorian mentioned something about function ForGroup(group g,code functionName) in combination with temporary global variables being faster than the standard method of looping. EDIT The point of this struct thingy is that there can be multiple instances of each struct. If you have a struct containing a unit and an integer; then for each time a struct of that type, a new unit variable and a new integer variable is assigned for the newly created struct. |
| 02-11-2008, 12:53 PM | #5 |
Gotcha I'll give it a shot, but one thing that I'm still confused about is how there would be multiple instances of this function running on different timers (since more than one of the buildings w/ ability can exist) - what is it that I can do to ensure each struct I create is unique only to that function it was created for: ability cast -> run function -> create struct and start associated timer that runs FrostInfliction -> when ability is over destroy that specific struct |
| 02-11-2008, 01:10 PM | #6 |
Let's make an analogy with a unit. Each unit has a lot of different values...
When you create a new unit; it will have it's own values for all of the above. It is the same with structs. Each struct of a certain type has it's own variables! In the following example, I use 1 struct type, but three individual structs of that type. JASS:struct song integer seconds string name string author endstruct function MySongs takes nothing returns nothing local song s1=song.create() local song s2=song.create() local song lullaby=song.create() // s1 has it's own variables... set s1.seconds=3954 set s1.name="requiem" set s1.author="mozart" // s2 has it's own variables... set s2.seconds=190 set s2.name="She loves you" set s2.author="The Beetles" // lullaby has it's own variables... set lullaby.seconds=32 set lullaby.name="Zelda's Lullaby" set lullaby.author="Koji Japaneese" call BJDebugMsg(s1.name) call BJDebugMsg(s2.name) call BJDebugMsg(lullaby.name) // This will display: // // requiem // She Loves You // Zelda's Lullaby endfunction |
| 02-11-2008, 01:25 PM | #7 |
wait a sec, when you put in: JASS:local FrostInflictionData t=ST_GetInt1(i) |
| 02-11-2008, 02:04 PM | #8 |
Actually strcuts are only arrays working parallel. So the struct returns the integer for the corrisponding slot. I personally prefer using loops for structs instead of attachment systems. I wrote how i would do your triggers, however i'm kinda lazy atm to explain everything detailed, also i don't have WE atm so i can not check for any syntax errors, etc. JASS:scope FrostInfliction private keyword Data globals Data array gdat timer CallbackTimer = CreateTimer() integer loopi = 0 integer DAmount = 0 group PickGroup = CreateGroup() boolexpr PickCondition = null endglobals struct Data unit Caster = null player p real x = 0. real y = 0. integer level = 0 static method create takes unit u, real x, real y, integer i returns Data local Data d = Data.allocate() set d.Caster = u set d.p = GetOwningPlayer(u) set d.x = x set d.y = y set d.level = i return d endmethod endstruct function PickAction takes nothing returns nothing local unit u = GetEnumUnit() local Data dat = gdat[loopi] if (GetUnitAbilityLevel(u,'B00C') > 0) then call UnitRemoveAbility(u,'B00C') call CasterCastAbility(dat.p, 'A02O', "cripple", u, true) // Level 2 Slow elseif (GetUnitAbilityLevel(u,'B00E') > 0) then call UnitRemoveAbility(u,'B00E') call CasterCastAbility(dat.p, 'A02R', "cripple", u, true) // Level 3 Slow elseif (GetUnitAbilityLevel(u,'B00H') > 0) then call UnitRemoveAbility(u,'B00H') call CasterCastAbility(dat.p, 'A02G', "thunderbolt", u, true) // Stun elseif (GetUnitAbilityLevel(u,'B00G') > 0) then call UnitRemoveAbility(u,'B00G') call UnitDamageTarget(dat.Caster, u, 50, true, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, null ) call SpecialEffectTarget( "Abilities\\Spells\\Undead\\FrostNova\\FrostNovaTarget.mdl", u, "origin", 2) else call CasterCastAbility(Player(OwnerCaster), 'A02H', "cripple", u, true) // Level 1 Slow endif call GroupRemoveUnit(PickGroup,u) endfunction private function Callback takes nothing returns nothing local Data dat set loopi = 0 loop exitwhen loopi >= DAmount set dat = gdat[loopi] if GetUnitAbilityLevel(dat.Caster,'B00I') > 0 and GetWidgetLife(dat.Caster) > 0.405 then call GroupEnumUnitsInRangeCounted(PickGroup,x,y,1000.00, PickCondition, 5) call ForGroup(PickGroup,function PickAction) set loopi = loopi + 1 else set dat.Caster = null call dat.destroy() set DAmount = DAmount - 1 if DAmount > 0 then set gdat[loopi] = gdat[DAmount] endif endif endloop if DAmount == 0 then call PauseTimer(CallbackTimer) endif endfunction private function Cast takes nothing returns nothing //Your Code still need to be added, then use the following line: //local Data dat = Data.create(<Casting Unit>,<Target X>,<Target Y>,<Level of Ability>) set gdat[DAmount] = dat set DAmount = Damount + 1 if DAmount == 1 then call TimerStart(CallbackTimer,true,2,function Callback) endif endfunction public function InitTrig takes nothing returns nothing local trigger tr = CreateTrigger() set PickCondition = Condition(function FrostFilter) //You still need to add the event call TriggerAddAction(tr,function Cast) endfunction endscope |
| 02-11-2008, 02:35 PM | #9 | |
Quote:
Yes! |
| 02-11-2008, 03:28 PM | #10 | |
Quote:
Nice! Much appreciated man for the crash course on structs! I'm gonna have to start using these more often ![]() |
