| 06-17-2009, 07:45 AM | #1 |
Hi, I have some questions regarding texttags and to make it short, I'll just show you my code: JASS:struct WeaponCooldownFollowTimer_bungkusan unit orang texttag bar real duration real durationcounter = 0.00 method onDestroy takes nothing returns nothing call DestroyTextTag(this.bar) set this.bar = null endmethod endstruct function WeaponCooldownFollowShooter_TimerPeriod takes nothing returns real return 0.02 endfunction function WeaponCooldownFollowShooter takes nothing returns nothing local timer T = GetExpiredTimer() local WeaponCooldownFollowTimer_bungkusan data = WeaponCooldownFollowTimer_bungkusan(GetHandleInt(T, "FollowBungkusan")) if(data.durationcounter < data.duration)then call SetTextTagPosUnit(data.bar, data.orang, 0.00) set data.durationcounter = data.durationcounter + WeaponCooldownFollowShooter_TimerPeriod() else call PauseTimer(T) call FlushHandleLocals(T) call data.destroy() endif set T = null endfunction function WeaponCooldownStart takes timer CDTimer, unit shooter, real duration returns nothing local integer I = 10 local string S = "" local timer followtimer local WeaponCooldownFollowTimer_bungkusan data local texttag TT //cooldown timer call TimerStart(CDTimer, duration, false, null) loop exitwhen(I <= 0) set TT = CreateTextTag() call ShowTextTagForceBJ( false, TT, GetPlayersAll() ) call ShowTextTagForceBJ( true, TT, GetForceOfPlayer(GetOwningPlayer(shooter)) ) call SetTextTagText(TT, S + "|", TextTagSize2Height(6.0)) call SetTextTagPosUnit(TT, shooter, 0.00) call SetTextTagColor(TT, R2I(I2R(10 - I)/10.0 * 255.0), R2I(I2R(I)/10.0 * 255.0), 0, 255) call SetTextTagPermanent(TT, false) call SetTextTagLifespan(TT, I2R(I)/10.0 * duration) //follow timer //checks whether there is a timer attached to the shooter, if there isn't, creates a new timer if(GetHandleTimer(shooter, "FollowTimer" + I2S(10 - I)) != null)then set followtimer = GetHandleTimer(shooter, "FollowTimer" + I2S(10 - I)) else set followtimer = CreateTimer() call SetHandleHandle(shooter, "FollowTimer" + I2S(10 - I), followtimer) endif call TimerStart(followtimer, WeaponCooldownFollowShooter_TimerPeriod(), true, function WeaponCooldownFollowShooter) set data = WeaponCooldownFollowTimer_bungkusan.create() call SetHandleInt(followtimer, "FollowBungkusan", data) set data.orang = shooter set data.bar = TT set data.duration = I2R(I)/10.0 * duration set I = I - 1 set S = S + " " endloop set followtimer = null endfunction Basically, this function creates bars on top of a unit whenever it shoots a weapon, and those bars represents the cooldown of a weapon. The bars vanishes one by one, and all the bars vanishes when the cooldown is finished (you can fire the weapon again). The WeaponCooldownStart function initializes and creates the bars on top of the shooter while the WeaponCooldownFollowShooter moves the bars on top of the shooter so it follows the shooter continuously. These 2 functions work perfectly alone but when it is run together with this trigger, it has a bug : JASS:function Trig_Gold_Bounty_Actions takes nothing returns nothing local real f = -100.00 local integer unitbounty = 0 local player killingplayer = GetOwningPlayer(GetKillingUnit()) local unit korban = GetTriggerUnit() local texttag bountyTextTag if(killingplayer != null)then //calculates the gold factor for the killed unit if (GetUnitTypeId(korban) == udg_CreepWaveType_1[udg_CurrentWave])then set f = udg_CreepWaveGoldFactorType_1[udg_CurrentWave] elseif (GetUnitTypeId(korban) == udg_CreepWaveType_2[udg_CurrentWave])then set f = udg_CreepWaveGoldFactorType_2[udg_CurrentWave] elseif (GetUnitTypeId(korban) == udg_CreepWaveType_3[udg_CurrentWave])then set f = udg_CreepWaveGoldFactorType_3[udg_CurrentWave] endif if( f != -100.00 ) then //calculates unit bounty set unitbounty = WyeR2I(f * I2R(Trig_Gold_Bounty_FindUnitBountySatuan(udg_CurrentWave)))//yang hasil dari functionnya diconvert jadi real dulu supaya bisa itung koma2. abis itu diconvert balik lagi abis dikaliin sama f jadi real call SetPlayerState(killingplayer, PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(killingplayer, PLAYER_STATE_RESOURCE_GOLD) + unitbounty) set bountyTextTag = CreateTextTag() call ShowTextTagForceBJ( false, bountyTextTag, GetPlayersAll() ) call ShowTextTagForceBJ( true, bountyTextTag, GetForceOfPlayer(killingplayer) ) call SetTextTagText(bountyTextTag, "+" + I2S(unitbounty), TextTagSize2Height(8.0)) call SetTextTagPosUnit(bountyTextTag, korban, 0.00) call SetTextTagColor(bountyTextTag, 255, 255, 0, 255) call SetTextTagPermanent(bountyTextTag, false) call SetTextTagLifespan(bountyTextTag, 2.0) call SetTextTagFadepoint(bountyTextTag, 1.5) call SetTextTagVelocityBJ(bountyTextTag, 50.0, 90.0) else call BJDebugMsg(GetUnitName(GetTriggerUnit()) + " gold factor not found") endif endif set bountyTextTag = null set korban = null set killingplayer = null endfunction This function basically calculates the bounty and creates a texttag above a killed unit when it is killed by a shooter. The bug is, whenever the timer from the first trigger expires, it moves the cooldown bars above the shooter (which is what supposed to happen) BUT it also moves the bounty text tag above the shooter as well... is this supposed to happen? Is there a mistake in my code? Or is it just another annoying bug again?? EDIT : I found that everytime the follow timer expires, the data.bar (struct variable) actually refers to both the bounty texttag and the bar texttag. So whatever I do to the data.bar, it also applies to the bounty text tag. Does this even make sense?? Thanks in advance |
| 06-17-2009, 08:51 AM | #2 |
You should add a "set TT=null" at the end of WeaponCooldownStart Two important things you should know about TextTags: -Never destroy a TextTag that is not permanent and has a lifespan (is that what you are doing when you destroy a WeaponCooldownFollowTimer_bungkusan instance?) Only set the referencing variable to null. -TextTags are limited to a number of 100. When you combine a lot of texttags with improper object destruction they start doing funny things. |
| 06-17-2009, 08:59 AM | #3 | |
Quote:
Oh yeah, I forgot to put that in this one. The real function has that line though, but it still doesn't work. And I don't have that much texttags in the game. Even the first few texttags already act funny. |
| 06-17-2009, 09:04 AM | #4 |
Did you get rid of call DestroyTextTag(this.bar) ? EDIT: You also use SetTextTagPosUnit at a moment where the TextTag in question might have already expired, due to possible inaccuracies in the use of timers to track down their expiration. If used on an already expired TextTag, it could move a completely different TextTag, such as the Gold_Bounty one. Try for example lowering the value of data.duration by 30 seconds then check if the problem still occurs. |
| 06-17-2009, 10:04 AM | #5 |
OOOOOOOOOHH!!! I have never thought of that before!! Come to think of it, it totally makes sense. Let me try doing that for a while and see what happens. And yeah, I have removed the DestroyTextTag(this.bar). EDIT: hmm.... however, the SetUnitTextTagPosUnit function is placed inside an if/then/else and the if condition allows it to only be carried out when the texttag is still there... btw the data.duration is a small number, mostly less than 5 seconds. EDIT: I tried changing some of the code in the WeaponCooldownFollowShooter function into this: JASS:function WeaponCooldownFollowShooter takes nothing returns nothing local timer T = GetExpiredTimer() local WeaponCooldownFollowTimer_bungkusan data = WeaponCooldownFollowTimer_bungkusan(GetHandleInt(T, "FollowBungkusan")) set data.durationcounter = data.durationcounter + WeaponCooldownFollowShooter_TimerPeriod() if(data.durationcounter < data.duration)then call SetTextTagPosUnit(data.bar, data.orang, 0.00) else call PauseTimer(T) call FlushHandleLocals(T) call data.destroy() endif set T = null endfunction and I found that the bug does not occur every time, but it still occurs every once in a while... any ideas on whats happening?? |
| 06-17-2009, 10:16 AM | #6 |
EDIT: Make the TextTag permanent and don't give it a lifespan then manually destroy it after the supposed "lifespan" has expired, using DestroyTextTag this time. The only reason you would do that is because in the end you are tracking down texttag's lifespan... |
| 06-17-2009, 10:29 AM | #7 | |
Just finished trying it a few seconds ago. It works, the bug doesn't occur. However, sometimes the last bar remains undestroyed for some reason.... Anyway, since you are being really helpful I gave a +rep for you :) EDIT: AAAAAAAAAH FINALLY A SOLUTION!! here, take a look what I've done with the code: JASS:function WeaponCooldownFollowShooter takes nothing returns nothing local timer T = GetExpiredTimer() local WeaponCooldownFollowTimer_bungkusan data = WeaponCooldownFollowTimer_bungkusan(GetHandleInt(T, "FollowBungkusan")) local texttag TT = data.bar set data.durationcounter = data.durationcounter + WeaponCooldownFollowShooter_TimerPeriod() if(data.durationcounter < data.duration - 0.03)then //so the SetTextTagPosUnit does not fire when the duration is very close with the texttag expiration call SetTextTagPosUnit(data.bar, data.orang, 0.00) else call PauseTimer(T) call FlushHandleLocals(T) call data.destroy() endif set TT = null set T = null endfunction I have redisabled the permanence of the texttag and added the lifespan again. I think its much better to depend on the texttag lifespan for cleaning up texttags if you don't want any undestroyed texttag in your map. But anyway, I wouldn't have found this solution without your help, so thanks a lot Quote:
I think the reason why sometimes the bug occurs is because sometimes the expiration time of the texttag is less than the time taken by the timer to expire as the counter adds up very small number at every iteration (0.02). |
| 06-17-2009, 12:05 PM | #8 |
Maybe if manual destruction didn't clear the last texttag, it was due to another problem we haven't sorted out yet. |
| 06-17-2009, 01:31 PM | #9 |
Yeah, probably. But this one solved the problem pretty well, so I'm just gonna stick with this one. Anyway, thanks again :) |
