| 08-26-2007, 07:21 AM | #1 |
Heya! I´ve got a serious problem since i involved the Caster System´s Timer Stack in my map. I changed all CreateTimer() parts with NewTimer() and all DestroyTimer() with ReleaseTimer(). Finally, when i´m casting a spell which needs a custom function written by me, there might be a bug that one of 3 illusions created by the spell won´t disappear at a random time. I cant tell you any reason for this. This is my function which is not working sometimes: JASS:function RemoveUnitSFXTimedChild takes nothing returns nothing local timer t = GetExpiredTimer() local real x = GetHandleReal (t,"x") local real y = GetHandleReal (t,"y") if x == 0 then set x = GetUnitX (GetHandleUnit(t,"whichunit")) endif if y == 0 then set y = GetUnitY (GetHandleUnit (t,"whichunit")) endif //call BJDebugMsg ("ruSFXt X - "+R2S(x)) //call BJDebugMsg ("ruSFXt Y - "+R2S(y)) //call BJDebugMsg ("ruSFXt - "+GetUnitName(GetHandleUnit (t,"whichunit"))) //call BJDebugMsg ("ruSFXt - "+GetHandleString(t,"sfx")) //call BJDebugMsg ("ruSFXt - "+I2S(H2I(t))) call RemoveUnit (GetHandleUnit (t,"whichunit")) call DestroyEffect (AddSpecialEffect(GetHandleString(t,"sfx"),x,y)) call FlushHandleLocals (t) call ReleaseTimer(t) //call BJDebugMsg ("ruSFXt - End") endfunction function RemoveUnitSFXTimed takes unit whichunit,real timeout, string sfx,real x, real y returns nothing local timer t = NewTimer() call SetHandleHandle (t,"whichunit",whichunit) call SetHandleString (t,"sfx",sfx) //call BJDebugMsg ("ruSFXt - start") if x != 0 then call SetHandleReal (t,"x",x) endif if y != 0 then call SetHandleReal (t,"y",y) endif call TimerStart (t,timeout,false,function RemoveUnitSFXTimedChild) endfunction Ok, in the spell im calling this function with the following code: JASS:call RemoveUnitSFXTimed (illusion[i],1.3,GetAbilityEffectById(TriBlade_SpellId(),EFFECT_TYPE_AREA_EFFECT,0),0,0) So, one illusion of 3 isnt removed properly, but i know that my RemoveUnitSFXTimed function is called when one of the illusions isnt removed properly. It just doesnt go through the callback so i think it has something to do with the timerstack. I am using the latest timerstack of the Caster System. If you´d like to see my spellcode just request it. Greeting... anX |
| 08-26-2007, 07:39 AM | #2 |
add debug to your functions, code looks like ok. |
| 08-26-2007, 07:46 AM | #3 |
Why are you using KaTTaNa's HandleVar functions in addition to CSCache and the TimerStack functions? Why not just use the CSCache functions? |
| 08-26-2007, 07:52 AM | #4 |
better do not use caster system just for timer stacks... |
| 08-26-2007, 07:53 AM | #5 |
Are there any problems with Kattana´s Handle Vars and Timer Stack? Well I will have a try with CSCache functions today. Any other suggestions? anX |
| 08-26-2007, 08:01 AM | #6 |
It's just that KaTTaNa's are outdated and inferior. In fact, the LocalVars() function usually leaks a gamecache. |
| 08-26-2007, 09:23 AM | #7 |
Well if it doesn't remove the unit, it seems it doesn't have much to remove, right? Maybe you could load the unit into a variable inside the timer callback instead of using GetHandleUnit(t,"whichunit") thrice and check if the unit variable is null at the start of the function. This code seems to be alright, so I would suspect there is something wrong with the way the unit is passed to the RemoveUnitSFXTimed function. Perhaps there is an array issue? Anyways, DioD was right: More debugmessages :) |
| 08-26-2007, 05:18 PM | #8 |
DestroyTimer doesn't malfunction when you destroy a timer that was already destroyed. But ReleaseTimer does. this said if you have a double free somewhere you will make timer stack to break. this version of CSSafety will detect double frees when you compile the map using debug mode: JASS:library CSSafety requires CSCache //****************************************************************************************** //* //* CSSafety 14.deb //* ¯¯¯¯¯¯¯¯ //* //* Utilities to make things safer. Currently this simply includes a timer recycling //* Stack. Once you replace CreateTimer with NewTimer and DestroyTimer with ReleaseTimer //* you no longer have to care about setting timers to null nor about timer related issues //* with the handle index stack. //* //****************************************************************************************** //========================================================================================== globals private timer array T private integer N = 0 endglobals //========================================================================================== function NewTimer takes nothing returns timer if (N==0) then set T[N]=CreateTimer() debug call SetCSData(T[N],0) return T[N] endif set N=N-1 debug call SetCSData(T[N],0) return T[N] endfunction //========================================================================================== function ReleaseTimer takes timer t returns nothing call PauseTimer(t) debug if (GetCSData(t)==-178788822) then debug call BJDebugMsg("you be damned ! double free!!!1") debug else debug call SetCSData(t,-178788822) debug endif if (N==8191) then debug call BJDebugMsg("Warning: Timer stack is full, destroying timer!!") //stack is full, the map already has much more troubles than the chance of bug call DestroyTimer(t) else set T[N]=t set N=N+1 endif endfunction endlibrary |
| 08-27-2007, 02:52 PM | #9 |
thx vex + rep. But i dunno if it is that useful because the bugs always happen when many of my heros are being played at the same time i will try it. greetz, anX |
| 08-27-2007, 02:56 PM | #10 |
that's actually more proof it is an issue with double frees, don't worry, although the manifestation of the bug might require a lot of instances, detecting the double free itself should require a single cast. |
| 08-27-2007, 07:09 PM | #11 |
ok, finally i casted a single cast... didnt create a double free or lets say it didnt show your messages. And what now? Dunno but in other custom functions there also are errors for example here: JASS:function ShowUnitTimedChild takes nothing returns nothing local timer t = GetExpiredTimer() local boolean b = GetAttachedBoolean (t,"show") local boolean c = GetAttachedBoolean (t,"reselect") local unit whichunit = GetAttachedUnit (t,"whichunit") call ShowUnit (whichunit,b) if c == true then call SelectUnitAddForPlayer(whichunit,GetOwningPlayer(whichunit)) endif call CleanAttachedVars (t) call ReleaseTimer (t) set whichunit = null endfunction function ShowUnitTimed takes unit whichunit,boolean show,real timeout,boolean reselect returns nothing local timer t = NewTimer() call AttachObject (t,"whichunit",whichunit) call AttachBoolean (t,"show",show) call AttachBoolean (t,"reselect",reselect) call TimerStart (t,timeout,false,function ShowUnitTimedChild) endfunction JASS:constant function TriBlade_SpellId takes nothing returns integer return 'A01M' endfunction constant function TriBlade_DummyId takes nothing returns integer return 'h00O' endfunction constant function TriBlade_DummyAbilityId takes nothing returns integer return 'A01L' endfunction function Trig_TriBlade_Conditions takes nothing returns boolean return GetSpellAbilityId () == TriBlade_SpellId() endfunction function Trig_TriBlade_Actions2 takes nothing returns nothing local timer t = GetExpiredTimer() local unit array illusion local unit caster = GetAttachedUnit(t,"caster") local unit target = GetAttachedUnit(t,"target") local real x = GetUnitX(target) local real y = GetUnitY(target) local real x2 local real y2 local real dist = GetAttachedReal (t,"dist") - 10 local real angle2 local integer i = 1 call BJDebugMsg ("Tri Blade - Cast") loop exitwhen i >=4 set illusion[i] = GetAttachedUnit(t,"illusion"+I2S(i)) set i = i + 1 endloop set i = 1 loop exitwhen i >= 4 set angle2 = 120*i set x2 = x + dist *Cos (angle2*bj_DEGTORAD) set y2 = y + dist *Sin (angle2*bj_DEGTORAD) call SetUnitX(illusion[i],x2) call SetUnitY(illusion[i],y2) set i = i + 1 endloop if dist <= 120 then set i = 1 loop exitwhen i >=4 call IssueTargetOrder (illusion[i],"attackonce",target) call RemoveUnitSFXTimed (illusion[i],1.3,GetAbilityEffectById(TriBlade_SpellId(),EFFECT_TYPE_AREA_EFFECT,0),0,0) set i = i + 1 endloop call MakeUnitBleed (target,caster,10,GetAbilityEffectById(TriBlade_SpellId(),EFFECT_TYPE_AREA_EFFECT,1),7.0,1.0) call CleanAttachedVars (t) call ReleaseTimer(t) call ShowUnitTimed (caster,true,1.2,true) set caster = null set target = null else call AttachReal (t,"dist",dist) endif endfunction function Trig_TriBlade_Actions takes nothing returns nothing local unit caster = GetTriggerUnit() local unit target = GetSpellTargetUnit() local timer t = NewTimer() local unit array illusion local real x = GetUnitX(target) local real y = GetUnitY(target) local real x2 local real y2 local real dist = 200 local real angle local real angle2 = 0 local real timeout = 0.02 local integer i = 1 call ShowUnit (caster,false) loop exitwhen i >= 4 set angle2 = 120*i set x2 = x + dist *Cos (angle2*bj_DEGTORAD) set y2 = y + dist *Sin (angle2*bj_DEGTORAD) set angle = bj_RADTODEG *Atan2((y2 - y), (x2 -x)) set illusion[i] = CreateUnit (GetOwningPlayer(caster),TriBlade_DummyId(),x2,y2,angle-180) call UnitAddAbility (illusion[i],'Aloc') call UnitAddAbility (illusion[i],TriBlade_DummyAbilityId ()) call SetUnitAbilityLevel (illusion[i],TriBlade_DummyAbilityId (),GetUnitAbilityLevel (caster,TriBlade_SpellId())) call SetUnitAnimationByIndex (illusion[i],3) call DestroyEffect (AddSpecialEffect(GetAbilityEffectById(TriBlade_SpellId(),EFFECT_TYPE_AREA_EFFECT,0),x2,y2)) call SetUnitFacing (illusion[i],angle-180) call AttachObject (t,"illusion"+I2S(i),illusion[i]) set i = i + 1 endloop call AttachReal (t,"dist",dist) call AttachObject (t,"caster",caster) call AttachObject (t,"target",target) call TimerStart (t,timeout,true,function Trig_TriBlade_Actions2) endfunction //==== Init Trigger NewTrigger ==== function InitTrig_TriBlade takes nothing returns nothing set gg_trg_TriBlade = CreateTrigger() call TriggerRegisterAnyUnitEventBJ(gg_trg_TriBlade,EVENT_PLAYER_UNIT_SPELL_EFFECT ) call TriggerAddCondition(gg_trg_TriBlade, Condition(function Trig_TriBlade_Conditions)) call TriggerAddAction(gg_trg_TriBlade, function Trig_TriBlade_Actions) endfunction Any suggestions? Greetz, anX |
| 08-28-2007, 02:35 AM | #12 |
did you use debug mode? You only need one double free to screw anything else up. This is mostly the reason I moved away from using dynamic timers at all, seriously, you can do every spell with only creating a single timer that is used by all the instances. Or you can use timeLib try this one: JASS:library CSSafety requires CSCache //****************************************************************************************** //* //* CSSafety 14.fix //* ¯¯¯¯¯¯¯¯ //* //* Utilities to make things safer. Currently this simply includes a timer recycling //* Stack. Once you replace CreateTimer with NewTimer and DestroyTimer with ReleaseTimer //* you no longer have to care about setting timers to null nor about timer related issues //* with the handle index stack. //* //****************************************************************************************** //========================================================================================== globals private timer array T private integer N = 0 endglobals //========================================================================================== function NewTimer takes nothing returns timer if (N==0) then set T[N]=CreateTimer() call SetCSData(T[N],0) return T[N] endif set N=N-1 call SetCSData(T[N],0) return T[N] endfunction //========================================================================================== function ReleaseTimer takes timer t returns nothing call PauseTimer(t) if (GetCSData(t)==-178788822) then debug call BJDebugMsg("you be damned ! double free!!!1") return else call SetCSData(t,-178788822) endif if (N==8191) then debug call BJDebugMsg("Warning: Timer stack is full, destroying timer!!") //stack is full, the map already has much more troubles than the chance of bug call DestroyTimer(t) else set T[N]=t set N=N+1 endif endfunction endlibrary besides of showing an error message when it detects a double free (and it is debug mode) it will also prevent it from causing issues even if it is not debug mode. Try it with your map in the conditions where it used to have bugs. You should also make sure the bugs were actually there before replacing CreateTimer and DestroyTimer. |
| 08-28-2007, 06:44 PM | #13 |
Well i just played it in MP with debug mode on... didnt show any message nor did grim show something. and the bug reappeared. Well, if i singlecast the spell 400 times on a target, everything is perfect. It even seems that after the first time the bug appears everything is gettin messed up i.e. Revive Timers dont Revive heroes correctly nor are they being destroyed when they hit 0. Some other spells show malfunctions... I dont know why this is the way it is... Well i am going to try the native timer functions now and tell you my results. What can be wrong? I might post my complete header but its kinda long ^_^ greetz, anX EDIT: Just got a double free. While Warden ( A Hero ;P) is in Diffugium (like windwalk , but additionally creating an illusion at her position at cast) is bleeding caused by Tri Blade (see above), when the bleed ends there is a double free. so far for now... here is my header with many useless crap :P JASS:// anXieTys useful custom fkts. constant function MakeUnitBleed_Dummy takes nothing returns unit return udg_BuffDummy endfunction constant function MakeUnitBleed_DummyAbility takes nothing returns integer return 'A01Q' // Ability adding buff and effect endfunction constant function MakeUnitBleed_Buff takes nothing returns integer return 'B003' // Buff being removed after duration endfunction constant function MakeUnitBleed_Order takes nothing returns string return "drunkenhaze" // Buff being removed after duration endfunction function IsUnitRaisable takes unit corpse returns boolean local unit u = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE),'h000',GetUnitX(corpse),GetUnitY(corpse),270.00) if IssueTargetOrder (u,"raisedead",corpse) == true then call RemoveUnit (u) return true else call RemoveUnit (u) return false endif endfunction function CreateUnits takes integer i, integer ut,player p, real X, real Y, real facing returns nothing loop exitwhen i == 0 call CreateUnit ( p , ut, X, Y, facing) set i = i - 1 endloop endfunction function DistanceBetweenCoords takes real x1,real y1,real x2,real y2 returns real local real x = x2 - x1 local real y = y2 -y1 return SquareRoot(x *x + y * y) endfunction function CreateUnitsAtRectAndOrderToRect takes integer count,integer unittypeid,player p , rect cr,rect targetrect, string order, real f returns nothing local real x = GetRectCenterX(cr) local real y = GetRectCenterY(cr) local real x2= GetRectCenterX(targetrect) local real y2= GetRectCenterY(targetrect) local unit u local integer i = 0 loop exitwhen i >=count set u = CreateUnit(p,unittypeid,x,y,f) call IssuePointOrder(u, order,x2,y2) set i = i+ 1 endloop endfunction function CoordsInMapArea takes real x,real y returns boolean local rect r = bj_mapInitialPlayableArea local real MaxX = GetRectMaxX(r) local real MinX = GetRectMinX(r) local real MaxY = GetRectMaxY(r) local real MinY = GetRectMinY(r) if x >MaxX or x<MinX then return false elseif y >MaxY or y<MinY then return false endif return true endfunction function GroupIssueOrderRectCenterXY takes group g, string order, rect r returns nothing local real x = GetRectCenterX(r) local real y = GetRectCenterY(r) call GroupPointOrder(g,order,x,y) endfunction function UnitIssueOrderRectCenterXY takes unit u, string order, rect r returns nothing local real x = GetRectCenterX(r) local real y = GetRectCenterY(r) call IssuePointOrder(u,order,x,y) endfunction function IsNormalAttack takes unit target returns boolean if GetUnitAbilityLevel(target, 'B001')>0 then //normal attacks call UnitRemoveAbility(GetTriggerUnit(), 'B001') return true elseif GetUnitAbilityLevel (target,'B00K')>0 then //orb (bleeding arrows) return true endif return false endfunction // =========================== function H2I takes handle h returns integer return h return 0 endfunction function H2TimerDialog takes handle h returns timerdialog return h endfunction /////////////////////////////////////// ///Custom Stun System by blu_da_noob/// /////////////////////////////////////// ////////////////////////////////////// /////Generic Game Cache functions///// ////////////////////////////////////// function Cache takes nothing returns gamecache if udg_cache == null then call FlushGameCache(InitGameCache("cache.w3v")) set udg_cache = InitGameCache("cache.w3v") endif return udg_cache endfunction function GetUnit takes string mission, string key returns unit return GetStoredInteger(Cache(),mission,key) return null endfunction function GetTimer takes string mission, string key returns timer return GetStoredInteger(Cache(),mission,key) return null endfunction function GetGroup takes string mission, string key returns group return GetStoredInteger(Cache(),mission,key) return null endfunction ////////////////////////////////////// ///End Generic Game Cache Functions/// ////////////////////////////////////// /////////////////////////////// /////Stun System Functions///// /////////////////////////////// //Configuration Functions// function StunDummyId takes nothing returns integer return 'h00L' //The rawcode of your dummy caster unit endfunction function StunAbilityId takes nothing returns integer return 'A01D' //The rawcode of your stormbolt ability endfunction function StunBuffId takes nothing returns integer return 'B00D' //The rawcode of your custom stun buff endfunction function MinimumStunDuration takes nothing returns real return 0.2 //The minimum duration this system can stun //a unit for. May not be stable below this //value, and below 0.1 is not recomended at all endfunction //End of Configuration Functions// function GetStunDummy takes unit target returns unit local gamecache gc = Cache() local group g local unit dummy local integer temp set g = GetGroup("CustomStunSystem","StunDummyGroup") if g == null then set g = CreateGroup() call StoreInteger(gc,"CustomStunSystem","StunDummyGroup",H2I(g)) endif set dummy = FirstOfGroup(g) if dummy == null then set dummy = CreateUnit(GetOwningPlayer(target),StunDummyId(),GetUnitX(target),GetUnitY(target),0) else call SetUnitX(dummy,GetUnitX(target)) call SetUnitY(dummy,GetUnitY(target)) call SetUnitOwner(dummy,GetOwningPlayer(target),false) call GroupRemoveUnit(g,dummy) endif call UnitAddAbility(dummy,'Aloc') call UnitAddAbility(dummy,StunAbilityId()) set temp = H2I(dummy) set gc = null set g = null set dummy = null return temp return null endfunction function ReturnStunDummy takes nothing returns nothing local unit dummy = bj_groupRandomCurrentPick call TriggerSleepAction(5) call GroupAddUnit(GetGroup("CustomStunSystem","StunDummyGroup"),dummy) set dummy = null endfunction function RemoveUnitStun takes unit u returns boolean return UnitRemoveAbility(u,StunBuffId()) endfunction function TimedRemoveStun takes nothing returns nothing local string timertable local unit target local string targettable local gamecache gc = Cache() set bj_crippledTimer[21] = GetExpiredTimer() set timertable = I2S(H2I(bj_crippledTimer[21])) set target = GetUnit(timertable,"stuntarget") set targettable = I2S(H2I(target)) call UnitRemoveAbility(target,StunBuffId()) call FlushStoredMission(gc,timertable) call DestroyTimer(bj_crippledTimer[21]) call FlushStoredInteger(gc,targettable,"stuntimer") set target = null set gc = null endfunction function StunUnit takes unit target, real duration, boolean ignoremagicimmunity returns boolean local boolean immune = IsUnitType(target,UNIT_TYPE_MAGIC_IMMUNE) local boolean stun = (not immune) or ignoremagicimmunity local unit dummy local string targettable local string timertable local gamecache gc if stun then set dummy = GetStunDummy(target) set stun = IssueTargetOrderById(dummy,852095,target) if stun then set gc = Cache() set duration = RMaxBJ(duration,MinimumStunDuration()) set targettable = I2S(H2I(target)) set bj_crippledTimer[21] = GetTimer(targettable,"stuntimer") if bj_crippledTimer[21] == null then set bj_crippledTimer[21] = CreateTimer() call StoreInteger(gc,targettable,"stuntimer",H2I(bj_crippledTimer[21])) endif set timertable = I2S(H2I(bj_crippledTimer[21])) call StoreInteger(gc,timertable,"stuntarget",H2I(target)) call TimerStart(bj_crippledTimer[21],RMaxBJ(duration,TimerGetRemaining(bj_crippledTimer[21])),false,function TimedRemoveStun) endif set bj_groupRandomCurrentPick = dummy call ExecuteFunc("ReturnStunDummy") endif set dummy = null set gc = null return stun endfunction ////////////////////////////////// ///End of Stun System Functions/// ////////////////////////////////// function GetPlayerNameColored takes player id returns string local playercolor col=GetPlayerColor(id) local string r=GetPlayerName(id) if col == PLAYER_COLOR_RED then set r="|cffff0000"+r+"|r" elseif col == PLAYER_COLOR_BLUE then set r="|cff0000ff"+r+"|r" elseif col == PLAYER_COLOR_CYAN then set r="|cff93ffc9"+r+"|r" elseif col == PLAYER_COLOR_PURPLE then set r="|cff400080"+r+"|r" elseif col == PLAYER_COLOR_YELLOW then set r="|cffffff00"+r+"|r" elseif col == PLAYER_COLOR_ORANGE then set r="|cffff8000"+r+"|r" elseif col == PLAYER_COLOR_GREEN then set r="|cff00c400"+r+"|r" elseif col == PLAYER_COLOR_PINK then set r="|cffff80c0"+r+"|r" elseif col == PLAYER_COLOR_LIGHT_GRAY then set r="|cff808080"+r+"|r" elseif col == PLAYER_COLOR_LIGHT_BLUE then set r="|cffc1c1ff"+r+"|r" elseif col == PLAYER_COLOR_AQUA then set r="|cff5e5e2f"+r+"|r" elseif col == PLAYER_COLOR_BROWN then set r="|cff004000"+r+"|r" else set r="|cff000000"+r+"|r" endif set col=null return r endfunction function SimError takes player ForPlayer, string msg returns nothing local sound error=CreateSoundFromLabel( "InterfaceError",false,false,false,10,10) if (GetLocalPlayer() == ForPlayer) then call ClearTextMessages() call DisplayTimedTextToPlayer( ForPlayer, 0.52, -1.00, 2.00, "|cffffcc00"+msg+"|r" ) call StartSound( error ) endif call KillSoundWhenDone( error) set error=null endfunction function AddFadingTextTag takes string text, real x, real y, integer red, integer green, integer blue, integer alpha returns nothing local texttag t = CreateTextTag() call SetTextTagText(t, text, 0.025) call SetTextTagPos(t, x, y, 0.00) call SetTextTagColor(t, red, green, blue, alpha) call SetTextTagVelocity(t, 0, 0.03) call SetTextTagVisibility(t, true) call SetTextTagFadepoint(t, 2) call SetTextTagLifespan(t, 3) call SetTextTagPermanent(t, false) set t = null endfunction function RemoveAbilityTimedChild takes nothing returns nothing local timer t = GetExpiredTimer() local integer abilid = GetAttachedInt(t,"abilid") local unit target = GetAttachedUnit(t,"target") call UnitRemoveAbility (target,abilid) call CleanAttachedVars (t) call ReleaseTimer(t) endfunction function RemoveAbilityTimed takes unit target, integer abilid, real duration returns nothing local timer t = NewTimer() call AttachObject (t,"target",target) call AttachInt (t,"abilid",abilid) call TimerStart(t,duration,false,function RemoveAbilityTimedChild) endfunction function GetFloorHeight takes real x, real y returns real local location whichUnitLocation = Location( x, y ) local real z = GetLocationZ( whichUnitLocation ) call RemoveLocation( whichUnitLocation ) set whichUnitLocation = null return z endfunction function GetUnitZ takes unit whichUnit returns real local real z = ( GetFloorHeight( GetUnitX( whichUnit ), GetUnitY( whichUnit ) ) + GetUnitFlyHeight( whichUnit ) ) set whichUnit = null return z endfunction function SetUnitZ takes unit whichUnit, real z returns nothing local boolean whichUnitHasNotAmrf = ( GetUnitAbilityLevel( whichUnit, 'Amrf' ) <= 0 ) if ( whichUnitHasNotAmrf ) then call UnitAddAbility( whichUnit, 'Amrf' ) endif call SetUnitFlyHeight( whichUnit, z - GetFloorHeight( GetUnitX( whichUnit ), GetUnitY( whichUnit ) ), 0.00 ) if ( whichUnitHasNotAmrf ) then call UnitRemoveAbility( whichUnit, 'Amrf' ) endif set whichUnit = null endfunction function UnitAddAbilityTimedChild takes nothing returns nothing local timer t = GetExpiredTimer() local unit u = GetAttachedUnit (t,"u") local integer abil = GetAttachedInt(t,"abil") call UnitRemoveAbility (u,abil) call CleanAttachedVars (t) call ReleaseTimer(t) endfunction function UnitAddAbilityTimed takes unit whichunit, integer abil, real howlong returns nothing local timer t = NewTimer() local unit u = whichunit call UnitAddAbility (u,abil) call AttachObject (t,"u",u) call AttachInt (t,"abil",abil) call TimerStart (t,howlong,false,function UnitAddAbilityTimedChild) endfunction function SetUnitManaTimedChild takes nothing returns nothing local timer t = GetExpiredTimer() local unit whichunit = GetAttachedUnit (t,"whichunit") local real mana = GetAttachedReal (t,"mana") call SetUnitState (whichunit,UNIT_STATE_MANA,GetUnitState(whichunit,UNIT_STATE_MANA)+mana) call CleanAttachedVars(t) call ReleaseTimer(t) set whichunit = null endfunction function SetUnitManaTimed takes unit whichunit, real addmana, real timeout returns nothing local timer t = NewTimer() call AttachObject (t,"whichunit",whichunit) call AttachReal (t,"mana",addmana) call TimerStart (t,timeout,false,function SetUnitManaTimedChild) endfunction function IssueImmediateOrderTimed takes unit u, integer orderid, real wait returns nothing call PolledWait (wait) call IssueImmediateOrderById (u,orderid) endfunction constant function Dizzyness_SpellId takes nothing returns integer return 'A01F' endfunction function MakeUnitDizzyChild takes nothing returns nothing local timer t = GetExpiredTimer() local unit whichunit = GetAttachedUnit (t,"whichunit") call UnitRemoveAbility (whichunit,Dizzyness_SpellId()) call CleanAttachedVars (t) call ReleaseTimer(t) set whichunit = null endfunction function MakeUnitDizzy takes unit whichunit, real duration, integer percentslow returns nothing local timer t = NewTimer() call UnitAddAbility (whichunit,Dizzyness_SpellId()) call SetUnitAbilityLevel (whichunit,Dizzyness_SpellId(),percentslow) call AttachObject (t,"whichunit",whichunit) call TimerStart (t,duration,false,function MakeUnitDizzyChild) endfunction function RemoveUnitTimedChild takes nothing returns nothing local timer t = GetExpiredTimer() call RemoveUnit (GetAttachedUnit (t,"whichunit")) call CleanAttachedVars (t) call ReleaseTimer(t) endfunction function RemoveUnitSFXTimedChild takes nothing returns nothing local timer t = GetExpiredTimer() local real x = GetAttachedReal (t,"x") local real y = GetAttachedReal (t,"y") local unit u = GetAttachedUnit(t,"whichunit") if x == 0 then set x = GetUnitX (u) endif if y == 0 then set y = GetUnitY (u) endif call RemoveUnit (u) call DestroyEffect (AddSpecialEffect(GetAttachedString(t,"sfx"),x,y)) call CleanAttachedVars (t) call DestroyTimer(t) endfunction function RemoveUnitTimed takes unit whichunit, real timeout returns nothing local timer t = NewTimer() call AttachObject (t,"whichunit",whichunit) call TimerStart (t,timeout,false,function RemoveUnitTimedChild) endfunction function RemoveUnitSFXTimed takes unit whichunit,real timeout, string sfx,real x, real y returns nothing local timer t = CreateTimer() call AttachObject (t,"whichunit",whichunit) call AttachString (t,"sfx",sfx) if x != 0 then call AttachReal (t,"x",x) endif if y != 0 then call AttachReal (t,"y",y) endif call TimerStart (t,timeout,false,function RemoveUnitSFXTimedChild) endfunction function ShowUnitTimedChild takes nothing returns nothing local timer t = GetExpiredTimer() local boolean b = GetAttachedBoolean (t,"show") local boolean c = GetAttachedBoolean (t,"reselect") local unit whichunit = GetAttachedUnit (t,"whichunit") call ShowUnit (whichunit,b) if c == true then call SelectUnitAddForPlayer(whichunit,GetOwningPlayer(whichunit)) endif call CleanAttachedVars (t) call DestroyTimer (t) set whichunit = null endfunction function ShowUnitTimed takes unit whichunit,boolean show,real timeout,boolean reselect returns nothing local timer t = CreateTimer() call AttachObject (t,"whichunit",whichunit) call AttachBoolean (t,"show",show) call AttachBoolean (t,"reselect",reselect) call TimerStart (t,timeout,false,function ShowUnitTimedChild) endfunction function UnitReduceArmorTimedChild takes nothing returns nothing local timer t = GetExpiredTimer() local unit u = GetAttachedUnit(t,"u") call UnitRemoveAbility (u,'A01J') call AttachObject (u,"URATtimer",null) call CleanAttachedVars (t) call ReleaseTimer (t) set u = null endfunction function UnitReduceArmorTimed takes unit whichunit,real duration, integer reduction returns nothing local timer t local real dur local real r if GetUnitAbilityLevel (whichunit,'A01J') > 0 then set t = GetAttachedTimer (whichunit,"URATtimer") set r = TimerGetRemaining(t) + duration call PauseTimer(t) call TimerStart (t,r,false,function UnitReduceArmorTimedChild) else set t = NewTimer() call UnitAddAbility (whichunit,'A01J') call SetUnitAbilityLevel (whichunit,'A01J',reduction) call AttachObject (whichunit,"URATtimer",t) call AttachObject (t,"u",whichunit) call TimerStart (t,duration,false,function UnitReduceArmorTimedChild) endif endfunction function DestroyTriggerTimedChild takes nothing returns nothing local timer t = GetExpiredTimer() local trigger tr = GetAttachedTrigger (t,"trigger") call DestroyTrigger (tr) call CleanAttachedVars (t) call ReleaseTimer (t) set tr = null endfunction function DestroyTriggerTimed takes trigger trig, real timeout returns nothing local timer t =NewTimer() call AttachObject (t,"trigger",trig) call TimerStart (t,timeout,false,function DestroyTriggerTimedChild) endfunction function MakeUnitBleedChild takes nothing returns nothing local timer t = GetExpiredTimer () local unit dmger =GetAttachedUnit (t,"dmger") local unit target = GetAttachedUnit (t,"target") local string str = GetAttachedString (t,"sfxpath") local real dur = GetAttachedReal (t,"dur") local real iv = GetAttachedReal (t,"iv") local real dmg = GetAttachedReal (t,"dmg") set dur = dur - iv if dur > 0 and GetWidgetLife (target) >0.405 then call DestroyEffect (AddSpecialEffectTarget(str,target,"origin")) call UnitDamageTarget(dmger,target,dmg,true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_MAGIC,null) call AttachReal (t,"dur",dur) else call UnitRemoveAbility (target,MakeUnitBleed_Buff()) call CleanAttachedVars (t) call ReleaseTimer(t) set dmger = null set target = null set str = null endif endfunction function MakeUnitBleed takes unit target,unit dmgdealer,real dmg,string sfxpath, real dur,real interval returns nothing local timer t local unit dummy local real r = 0 if GetAttachedTimer (target,"MUBtimer") != null then set t = GetAttachedTimer (target,"MUBtimer") call PauseTimer(t) set r = GetAttachedReal (t,"dur") set dur = dur + r call AttachObject (target,"MUBtimer",t) else set t = NewTimer() call AttachObject (target,"MUBtimer",t) endif set dummy = MakeUnitBleed_Dummy() call UnitAddAbility(dummy,MakeUnitBleed_DummyAbility()) call SetUnitX (dummy,GetUnitX(target)) call SetUnitY(dummy,GetUnitY(target)) call IssueTargetOrder (dummy,MakeUnitBleed_Order(),target) call AttachObject (t,"dmger",dmgdealer) call AttachObject (t,"target",target) call AttachString (t,"sfxpath",sfxpath) call AttachReal (t,"dur",dur) call AttachReal (t,"iv",interval) call AttachReal (t,"dmg",dmg) call TimerStart (t,interval,true,function MakeUnitBleedChild) endfunction function SetUnitTimeScalePercentTimedChild takes nothing returns nothing local timer t = GetExpiredTimer() local unit u = GetAttachedUnit (t,"whichunit") local real r = GetAttachedReal (t,"timescale") call SetUnitTimeScale (u,r*0.01) call CleanAttachedVars (t) call ReleaseTimer(t) endfunction function SetUnitTimeScalePercentTimed takes unit whichunit,real timescale,real timeout returns nothing local timer t = NewTimer() call AttachObject (t,"whichunit",whichunit) call AttachReal (t,"timescale",timescale) call TimerStart (t,timeout,false,function SetUnitTimeScalePercentTimedChild) endfunction function GetLowestHpUnitFromGroup takes group g returns unit local unit u local unit a set a = FirstOfGroup(g) call GroupRemoveUnit(g,a) loop set u = FirstOfGroup (g) exitwhen u == null if GetWidgetLife (u) < GetWidgetLife(a) then set a = u endif call GroupRemoveUnit(g,u) endloop return a endfunction and Diffugium: JASS:constant function Diffugium_SpellId takes nothing returns integer return 'A000' //Rawcode of the Spell endfunction constant function Diffugium_Dummy takes nothing returns integer return 'h000' // Rawcode of the dummy endfunction constant function Diffugium_Dummyitem takes nothing returns integer return 'I000' // Rawcode of the dummyitem added to the dummy endfunction constant function Diffugium_WardenUnitTypeId takes nothing returns integer return 'E000' // Rawcode of the dummyitem added to the dummy endfunction constant function Diffugium_PhyEscSpellId takes nothing returns integer return 'A016' // pysical escape ability if warden has activated so buff appears etc. endfunction constant function Diffugium_PhyEscBuffId takes nothing returns integer return 'B00B' // see above endfunction function Trig_Diffugium_Conditions takes nothing returns boolean return GetSpellAbilityId() == Diffugium_SpellId() endfunction function Trig_Diffugium_Conditions2 takes nothing returns boolean return GetUnitTypeId (GetTriggerUnit()) == Diffugium_WardenUnitTypeId() and IsUnitIllusion( GetTriggerUnit()) == true endfunction function Trig_Diffugium_Actions2 takes nothing returns nothing local unit illusion = GetTriggerUnit() call SetUnitX (illusion,GetAttachedReal(GetPlayableMapRect(),"wardenx")) call SetUnitY (illusion,GetAttachedReal(GetPlayableMapRect(),"wardeny")) //if GetUnitAbilityLevel (caster,Diffugium_PhyEscSpellId()) > 0 and GetUnitAbilityLevel(caster,Diffugium_PhyEscBuffId())>0 then //call UnitAddAbility (illusion,Diffugium_PhyEscSpellId()) //endif call CleanAttachedVars (GetPlayableMapRect()) endfunction function Trig_Diffugium_Actions takes nothing returns nothing local unit caster = GetTriggerUnit () local unit u local real X = GetUnitX (caster) local real Y = GetUnitY (caster) call AttachReal (GetPlayableMapRect(),"wardenx",X) call AttachReal (GetPlayableMapRect(),"wardeny",Y) set u = CreateUnit (GetOwningPlayer(caster), Diffugium_Dummy(), X, Y, 270) call UnitApplyTimedLife (u, 'BTLF', 1.00 ) call UnitAddItemByIdSwapped(Diffugium_Dummyitem(),u) call UnitUseItemTarget(u,bj_lastCreatedItem,caster) set caster = null set u = null endfunction //========================================================= function InitTrig_Diffugium takes nothing returns nothing local trigger t = CreateTrigger() set gg_trg_Diffugium = CreateTrigger() call TriggerRegisterAnyUnitEventBJ( gg_trg_Diffugium, EVENT_PLAYER_UNIT_SPELL_EFFECT ) call TriggerAddCondition(gg_trg_Diffugium, Condition(function Trig_Diffugium_Conditions)) call TriggerAddAction(gg_trg_Diffugium, function Trig_Diffugium_Actions) call TriggerRegisterEnterRectSimple (t,GetPlayableMapRect()) call TriggerAddCondition (t, Condition (function Trig_Diffugium_Conditions2)) call TriggerAddAction (t,function Trig_Diffugium_Actions2) endfunction |
| 08-30-2007, 02:25 PM | #14 |
sry for doubleposting, but i now know the reason for the bug: Its my function MakeUnitBleed in my header. Why it causes a double free isnt solved yet. im on it, any suggestions? |
| 08-30-2007, 05:14 PM | #15 |
JASS:if GetAttachedTimer (target,"MUBtimer") != null then set t = GetAttachedTimer (target,"MUBtimer") call PauseTimer(t) set r = GetAttachedReal (t,"dur") set dur = dur + r call AttachObject (target,"MUBtimer",t) else set t = NewTimer() call AttachObject (target,"MUBtimer",t) endif But the thing is that you never set "MUBtimer" to null on the unit once it dies. What happens is that probably the unit's handle id gets reused as a unit and then when bleed is applied it is considered it already got a timer, and possibly frees it again later... |
