swb_player/PlayerBase.Health.cs
using Sandbox.Sboku.Arena;
using SWB.Base;
using SWB.Shared;
using System;
using System.Collections.Generic;
namespace SWB.Player;
public partial class PlayerBase
{
[Property] public int MaxHealth { get; set; } = 100;
[Property] public float DamageThrottle { get; set; } = 0.3f;
[Property] public int MaxDamageClamp { get; set; } = 15;
[Sync] public int Health { get; set; } = 100;
[Sync] public int Kills { get; set; }
[Sync] public int Deaths { get; set; }
[Sync] public bool GodMode { get; set; }
[Sync] public bool IsDead { get; set; }
public bool IsAlive => !IsDead;
public Dictionary<string, DamageEntry> dmgTable = new();
public sealed class DamageEntry
{
public Shared.DamageInfo Info { get; }
public int Damage { get; set; }
public float Since { get; set; }
public DamageEntry(Shared.DamageInfo info)
{
Info = info;
Damage = 0;
Since = 0f;
}
}
private void HandleDamage()
{
var remove = new List<string>();
foreach (var entry in dmgTable)
{
entry.Value.Since += Time.Delta;
if (entry.Value.Since > DamageThrottle)
{
InflictDamage(entry.Value.Info, entry.Value.Damage);
remove.Add(entry.Key);
}
}
remove.ForEach(x => dmgTable.Remove(x));
}
private void InflictDamage(Shared.DamageInfo info, int dmg)
{
Health -= dmg;
// Flinch
var weapon = WeaponRegistry.Instance.Get(info.Inflictor);
if (weapon is not null)
DoHitFlinch(weapon.Primary.HitFlinch);
if (Health <= 0)
OnDeath(info);
}
[Rpc.Broadcast]
public virtual void TakeDamage( Shared.DamageInfo info )
{
Log.Info($"[PlayerBase.Health] TakeDamage called: dmg={info.Damage} attacker={info.AttackerId}");
if ( !IsValid || !Networking.IsHost || !IsAlive || GodMode )
return;
if ( Array.Exists( info.Tags, tag => tag == "head" ) )
info.Damage *= 2;
float dmgMultiplier = 1;
float armorMultiplier = 1;
var attacker = Scene.Directory.FindByGuid(info.AttackerId);
if (attacker != null && attacker.IsValid)
{
var upgradeHolder = attacker.GetComponent<UpgradeHolder>();
if (upgradeHolder != null)
{
armorMultiplier = upgradeHolder.ArmorMultiplier;
dmgMultiplier = upgradeHolder.DamageMultiplier * upgradeHolder.ArmorMultiplier;
}
}
if (!dmgTable.ContainsKey(info.Inflictor))
{
dmgTable.Add(info.Inflictor, new(info));
}
dmgTable[info.Inflictor].Damage = (int)MathF.Round(Math.Clamp(
dmgTable[info.Inflictor].Damage + info.Damage,
1,
MathF.Round(MaxDamageClamp * armorMultiplier * dmgMultiplier)));
//Log.Info("[TakeDamage]:" + info.Inflictor + " causes " + dmgTable[info.Inflictor].Damage + " damage to " + info.Tags);
}
[Rpc.Broadcast]
public virtual void TakeDamage(int damage)
{
Log.Info($"TakeDamage called: dmg={damage} ");
if (!IsValid || IsProxy || !IsAlive || GodMode)
return;
Health -= damage;
}
}