function tick() { // Change this in the other function(s) too. local healthPerSecond = 10; local genericMax = 256; local ent = null; while((ent = Entities.FindByClassname(ent, "func_button_timed"))) { // Target name should contain "health" and "station" ( health_station or health station ) if(NetProps.GetPropString(ent, "m_iName").find("health") == null || NetProps.GetPropString(ent, "m_iName").find("station") == null) continue; local player = NetProps.GetPropEntity(ent, "m_hActivator") if(player == null || player.GetClassname() != "player" || player.IsDead() || !player.IsSurvivor() || player.IsIncapacitated()) { NetProps.SetPropInt(ent, "m_nUseTime", genericMax); continue; } // Ignore health stations that started this instant. else if(NetProps.GetPropFloat(player, "m_flProgressBarStartTime") == Time()) continue; // Ignore situations before we set the progress bar. else if(NetProps.GetPropFloat(player, "m_flProgressBarDuration") == 0 || NetProps.GetPropInt(ent, "m_nUseTime") >= genericMax) continue; local timeLeft = NetProps.GetPropFloat(player, "m_flProgressBarStartTime") + NetProps.GetPropFloat(player, "m_flProgressBarDuration") - Time() // If the remainder of the timeLeft is zero, it's a whole number, apply the healing now. if(timeLeft % 1 == 0) { player.SetHealth(player.GetHealth() + healthPerSecond); // Reached max health? Reduce health to max health. if(player.GetHealth() > player.GetMaxHealth()) { player.SetHealth(player.GetMaxHealth()); } // Temporary health pushes your health beyond the max health? Account for that as well! if(player.GetHealth() + player.GetHealthBuffer() > player.GetMaxHealth()) { player.SetHealthBuffer(player.GetMaxHealth() - player.GetHealth()) } } // Took damage while using? Healed somehow while using? Force restart it. else if(abs(player.GetHealth() + ceil(timeLeft).tointeger() * healthPerSecond - player.GetMaxHealth()) > healthPerSecond) { EntFire("!activator", "Disable", null, 0, ent) EntFire("!activator", "Enable", null, 0.01, ent) } if(timeLeft <= 0) { EntFire("!activator", "Disable", null, 0, ent) EntFire("!activator", "Enable", null, 1.0, ent) } } return 0.001; // can't actually rethink this fast, but returning lower than max think speed will cap to the fastest think possible. } function OnHealthStationUsed() { // Change this in the other function(s) too. local healthPerSecond = 10; local genericMax = 256; local ent = caller; // Fetch player instead of using activator as the player may quickly release E which m_hActivator notices. // There are also less sinister things about this like getting incapped at the split second of trying to heal. local player = NetProps.GetPropEntity(ent, "m_hActivator") if(player == null || player.GetClassname() != "player" || player.IsDead() || !player.IsSurvivor() || player.IsIncapacitated()) return; // We don't care about temporary health just yet, as to calculate duration we pretend the player has 0 temporary health. local duration = ceil((player.GetMaxHealth() - player.GetHealth()).tofloat() / healthPerSecond.tofloat()).tofloat(); NetProps.SetPropInt(ent, "m_nUseTime", duration.tointeger()); NetProps.SetPropFloat(player, "m_flProgressBarDuration", duration) NetProps.SetPropFloat(player, "m_flProgressBarStartTime", Time()) if(duration < 1) { player.SetHealth(player.GetMaxHealth() - 1); duration = 1; } }