How do I destroy this timer on round end??

This thing is driving me crazy. I can’t figure out how to destroy this timer when the round ends. Anytime I try to destroy “_timerName” nothing happens. I’m guessing that’s because the true name is probably different because of this right?** local _timerName = self:UniqueID( ) … “_bleeding” … CurTime( );
**
Soo what do I destroy then OnEndRound to make the bleeding stop?


//// Make a player bleed properly using TakeDamageInfo - Josh 'Acecool' Moser
//




//
// Call this when a player is to start bleeding, make sure you call the inflictor and attacker so a kill can be properly credited
//
local PLAYER = FindMetaTable( "Player" );
function PLAYER:Bleed( _bleedDelay, _bloodLoss, _totalLoss, _inflictor, _attacker )
    local _bloodLost = 0;
    local _timerName = self:UniqueID( ) .. "_bleeding" .. CurTime( );
    timer.Create( _timerName, _bleedDelay, 0, function( )
        // They've lost enough blood, or they've died
        if ( _bloodLost >= _totalLoss || !self:Alive( ) ) then
            timer.Destroy( _timerName );
        else
            // Set up the damage info
            local _dmginfo = DamageInfo( );


            // Attacker is a player
            _dmginfo:SetAttacker( _attacker );


            // How much blood to lose per tick
            _dmginfo:SetDamage( _bloodLoss );
            _dmginfo:SetMaxDamage( _bloodLoss );


            // Inflictor is usually a weapon / entity the player used to do the damage
            _dmginfo:SetInflictor( _inflictor );


            // Damage force
            _dmginfo:SetDamageForce( Vector( 0, 0, 0 ) );


            // Type of damage
            _dmginfo:SetDamageType( DMG_SLASH ); // http://wiki.garrysmod.com/page/Enums/DMG


            // Do the damage
            self:TakeDamageInfo( _dmginfo );


            // Increment our counter
            _bloodLost = _bloodLost + _bloodLoss;
        end
    end );
end


//
// When a Player takes damage, start bleeding
//


hook.Add( "EntityTakeDamage", "EntityTakeDamage:BleedPotential", function( _victim, _dmgInfo )
    // Make sure the victim is valid and is a player; in addition to making sure the attacker is valid and is a player.
    if ( !IsValid( _victim ) || !_victim:IsPlayer( ) ) then return; end
    if ( !IsValid( _dmgInfo:GetAttacker( ) ) || !_dmgInfo:GetAttacker( ):IsPlayer( ) ) then return; end


    // 30% chance to bleed
    if ( math.random( 1, 10 ) >= 7 ) then
        // Bleed the victim every 3 seconds, for 1 damage, up to 20 damage or death and pass in the Inflictor item and Attacker Player
        _victim:Bleed( 3, 1, 20, _dmgInfo:GetInflictor( ), _dmgInfo:GetAttacker( ) );
    end
end );

Just before you create your actual “bleed” timer in the PLAYER:Bleed function, and after you’ve setup _timerName, add a hook to round end which will destroy the timer:



local PLAYER = FindMetaTable( "Player" );
function PLAYER:Bleed( _bleedDelay, _bloodLoss, _totalLoss, _inflictor, _attacker )
    local _bloodLost = 0;
    local _timerName = self:UniqueID( ) .. "_bleeding" .. CurTime( );

    --create a hook for RoundEnd event, unique hook ID
    hook.Add("RoundEnd", "Bleed_RoundEnd_" .. self:UniqueID(), function()
    	timer.Destroy( _timerName );
    end)

    timer.Create( _timerName, _bleedDelay, 0, function( )
        // They've lost enough blood, or they've died
        if ( _bloodLost >= _totalLoss || !self:Alive( ) ) then
            timer.Destroy( _timerName );
        else
            // Set up the damage info
            local _dmginfo = DamageInfo( );

            ...


Thanks for the quick reply!

I tried that, but no change. The player still bleeds if he has time left on the timer and a new round starts without him dying.

Here is the code I have. I tried RoundEnd and OnEndRound (for the murderer gamemode). Both didn’t work. Maybe the OnEndRound needs to have a ()? This is what I found in the intuit.lua of murderer gamemode function GM:OnEndRound()


//
// Make a player bleed properly using TakeDamageInfo - Josh 'Acecool' Moser
//


//
// Call this when a player is to start bleeding, make sure you call the inflictor and attacker so a kill can be properly credited
//
local PLAYER = FindMetaTable( "Player" );
function PLAYER:Bleed( _bleedDelay, _bloodLoss, _totalLoss, _inflictor, _attacker )
    local _bloodLost = 0;
    local _timerName = self:UniqueID( ) .. "_bleeding" .. CurTime( );

    --create a hook for RoundEnd event, unique hook ID
    hook.Add("OnEndRound", "Bleed_RoundEnd_" .. self:UniqueID(), function()
        timer.Destroy( _timerName );
    end)

    timer.Create( _timerName, _bleedDelay, 0, function( )
        // They've lost enough blood, or they've died
        if ( _bloodLost >= _totalLoss || !self:Alive( ) ) then
            timer.Destroy( _timerName );
        else
            // Set up the damage info
            local _dmginfo = DamageInfo( );

            // Attacker is a player
            _dmginfo:SetAttacker( _attacker );

            // How much blood to lose per tick
            _dmginfo:SetDamage( _bloodLoss );
            _dmginfo:SetMaxDamage( _bloodLoss );

            // Inflictor is usually a weapon / entity the player used to do the damage
            _dmginfo:SetInflictor( _inflictor );

            // Damage force
            _dmginfo:SetDamageForce( Vector( 0, 0, 0 ) );

            // Type of damage
            _dmginfo:SetDamageType( DMG_SLASH ); // http://wiki.garrysmod.com/page/Enums/DMG

            // Do the damage
            self:TakeDamageInfo( _dmginfo );

            // Increment our counter
            _bloodLost = _bloodLost + _bloodLoss;
        end
    end );
end

//
// When a Player takes damage, start bleeding
//


hook.Add( "EntityTakeDamage", "EntityTakeDamage:BleedPotential", function( _victim, _dmgInfo )
    // Make sure the victim is valid and is a player; in addition to making sure the attacker is valid and is a player.
    if ( !IsValid( _victim ) || !_victim:IsPlayer( ) ) then return; end
    if ( !IsValid( _dmgInfo:GetAttacker( ) ) || !_dmgInfo:GetAttacker( ):IsPlayer( ) ) then return; end

    // 30% chance to bleed
    if ( math.random( 1, 10 ) >= 7 ) then
        // Bleed the victim every 3 seconds, for 1 damage, up to 20 damage or death and pass in the Inflictor item and Attacker Player
        _victim:Bleed( 3, 1, 20, _dmgInfo:GetInflictor( ), _dmgInfo:GetAttacker( ) );
    end
    
hook.Add("PlayerDeath", "RDM", function(victim, inflictor, attacker )

    if IsValid(attacker) && attacker:IsPlayer() && not attacker:GetMurderer() && not victim:GetMurderer() then
    attacker:Bleed( 1, 1, 100, _dmgInfo:GetInflictor( ), _dmgInfo:GetAttacker( ) );
    end    

end)

end );

Hmm, does it by chance work if you only call the bleed method once? I have a feeling that if you make this part:



    --create a hook for RoundEnd event, unique hook ID
    hook.Add("OnEndRound", "Bleed_RoundEnd_" .. self:UniqueID(), function()
        timer.Destroy( _timerName );
    end)


Into this:



    --create a hook for RoundEnd event, unique hook ID
    hook.Add("OnEndRound", "Bleed_RoundEnd_" .. self:UniqueID() .. CurTime(), function()
        timer.Destroy( _timerName );
    end)


(make the hook unique in time, too)

However, this is a poor solution as you’ll end up with hundreds of hooks

If you keep my addition, you could keep track of whether or not the player is already bleeding. If the player is already bleeding, then do not start another bleed timer (this would work if you only want a max of 1 bleed timer)

An alternative solution is to keep a table/array of the _timerNames that are currently active. You could then, at the round’s end, have a single hook which destroys all of these timers. Again, perhaps a little hacky

Another solution would be to have a variable indicating the round number. If the present round number is not equal to the number the bleed timer was started on, destroy this timer:



local PLAYER = FindMetaTable( "Player" );
function PLAYER:Bleed( _bleedDelay, _bloodLoss, _totalLoss, _inflictor, _attacker )
    local _bloodLost = 0;
    local _timerName = self:UniqueID( ) .. "_bleeding" .. CurTime( );
    local _roundCount = globalRoundCount --make sure you increment globalRoundCount each round (use OnEndRound hook)

    timer.Create( _timerName, _bleedDelay, 0, function( )
    	if (_roundCount ~= globalRoundCount) then
    		timer.Destroy( _timerName )
    	end
        // They've lost enough blood, or they've died
        if ( _bloodLost >= _totalLoss || !self:Alive( ) ) then
            timer.Destroy( _timerName );
        else
            // Set up the damage info
            local _dmginfo = DamageInfo( );

            ...


I’m going out for a bit, I might think up some other solution when I’m out

https://dl.dropboxusercontent.com/u/26074909/tutoring/takedamageinfo_example.lua.html

I updated to remove CurTime( ) meaning they can only be forced to bleed once and it won’t get called again so stacking won’t be an issue. I also added two hooks for TTT; EndRound and BeginRound for the bleeding to stop on both cases…

Let me know if it works / doesn’t work. Add me on Steam; if results change I’ll update this post, or post a response.

Seems to be working great now. Thank you both so much.

I spent hours on this yesterday and couldn’t figure it out. I owe you guys.