Grid/Component/TrapComponent.cs
using Sandbox;
using Sandbox.Grid.Base;
using Sandbox.Sboku;
using SWB.Demo;
using SWB.Shared;
using System.Collections.Generic;
using System.Numerics;
using System.Security.AccessControl;
public sealed class TrapComponent : GridActivatableBase
{
[Property]
public ScreenShake TrapScreenShake { get; set; } = new ScreenShake
{
Duration = 0.35f,
Size = 1.2f,
Rotation = 2.5f,
Delay = 0.02f
};
[Property] public string ClosedModelPath { get; set; }
[Property] public string ActiveModelPath { get; set; }
[Property] public float Damage { get; set; } = 25f;
[Property] public float ActiveTime { get; set; } = 1.5f;
[Property] public float DamageInterval { get; set; } = 0.5f;
private ModelRenderer model;
private BoxCollider trigger;
private bool active;
private TimeSince timeSinceActivated;
private GridMap GridMap;
private Dictionary<GameObject, TimeSince> damageCooldown = new();
public bool IsActive { get { return active; } }
protected override void OnStart()
{
base.OnStart();
GridMap = Scene.GetComponentInChildren<GridSpawner>()?.Map;
model = Components.Get<ModelRenderer>();
trigger = Components.GetOrCreate<BoxCollider>();
trigger.Tags.Add("passable");
trigger.IsTrigger = true;
trigger.Enabled = false;
trigger.OnTriggerEnter += OnTrigger;
Deactivate();
}
protected override void OnUpdate()
{
if (!active)
return;
if (timeSinceActivated >= ActiveTime)
{
Deactivate();
}
}
public override void Activate()
{
if (active)
return;
active = true;
timeSinceActivated = 0;
damageCooldown.Clear();
if (model != null && !string.IsNullOrEmpty(ActiveModelPath))
model.Model = Model.Load(ActiveModelPath);
trigger.Enabled = true;
//Log.Info($"Trap activated at {GridX},{GridY}");
}
public override void Deactivate()
{
active = false;
if (model != null && !string.IsNullOrEmpty(ClosedModelPath))
model.Model = Model.Load(ClosedModelPath);
trigger.Enabled = false;
//Log.($"Trap deactivated at {GridX},{GridY}");
}
private void OnTrigger(Collider other)
{
if (!active)
return;
var go = other.GameObject;
var player = go.GetComponentInParent<DemoPlayer>();
if (player != null && player.Health > 0 && !OnCooldown(go))
{
player.TakeDamage(CreateDamageInfo());
player.ShakeScreen(TrapScreenShake);
return;
}
// 🔹 Botti
var bot = go.GetComponentInParent<BotAdapter>();
if (bot != null && bot.IsAlive && !OnCooldown(go))
{
bot.TakeDamage(CreateDamageInfo());
return;
}
}
private bool OnCooldown(GameObject go)
{
if (damageCooldown.TryGetValue(go, out var since) && since < DamageInterval)
return true;
damageCooldown[go] = 0;
return false;
}
private SWB.Shared.DamageInfo CreateDamageInfo()
{
return new SWB.Shared.DamageInfo
{
Damage = Damage,
AttackerId = GameObject.Id,
Origin = GameObject.WorldPosition,
Force = Vector3.Up * 200f,
Tags = new[] { "trap" },
Inflictor = "trap"
};
}
}