125 lines
4.3 KiB
C#
125 lines
4.3 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using Fusion;
|
|
using UnityEngine;
|
|
using Opsive.UltimateCharacterController.Traits;
|
|
|
|
public class PoisonGasTrap : TrapBase
|
|
{
|
|
private List<GameObject> affectedPlayers = new List<GameObject>();
|
|
|
|
protected override void OnTriggered(GameObject victim)
|
|
{
|
|
// Start the server-side poison gas zone routine
|
|
StartCoroutine(GasZoneRoutine());
|
|
}
|
|
|
|
private IEnumerator GasZoneRoutine()
|
|
{
|
|
float elapsed = 0f;
|
|
float tickInterval = 1.0f; // Deal damage every 1 second
|
|
float duration = trapData.EffectDuration;
|
|
float radius = trapData.EffectRadius;
|
|
float damagePerTick = trapData.Damage; // Sát thương mỗi tick
|
|
|
|
Debug.Log($"[Server] Poison Gas Trap activated. Duration: {duration}s, Radius: {radius}m");
|
|
|
|
while (elapsed < duration)
|
|
{
|
|
// Find all potential targets in radius
|
|
Collider[] overlaps = Physics.OverlapSphere(transform.position, radius, LayerMask.GetMask("Player"));
|
|
List<GameObject> currentTicks = new List<GameObject>();
|
|
|
|
foreach (var col in overlaps)
|
|
{
|
|
if (IsTargetValid(col.gameObject))
|
|
{
|
|
currentTicks.Add(col.gameObject);
|
|
|
|
// Apply damage
|
|
var health = col.gameObject.GetComponent<Health>();
|
|
if (health != null && health.IsAlive())
|
|
{
|
|
health.Damage(damagePerTick, transform.position, Vector3.zero, 0);
|
|
Debug.Log($"[Server] Poison Gas applied {damagePerTick} damage to {col.gameObject.name}");
|
|
}
|
|
|
|
// If player is newly entered the gas, turn on their UI overlay
|
|
if (!affectedPlayers.Contains(col.gameObject))
|
|
{
|
|
affectedPlayers.Add(col.gameObject);
|
|
var netObj = col.gameObject.GetComponent<NetworkObject>();
|
|
if (netObj != null)
|
|
{
|
|
RPC_TogglePoisonOverlay(netObj.InputAuthority, netObj.Id, true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// If player left the gas area, turn off their UI overlay
|
|
for (int i = affectedPlayers.Count - 1; i >= 0; --i)
|
|
{
|
|
var p = affectedPlayers[i];
|
|
if (p == null || !currentTicks.Contains(p))
|
|
{
|
|
if (p != null)
|
|
{
|
|
var netObj = p.GetComponent<NetworkObject>();
|
|
if (netObj != null)
|
|
{
|
|
RPC_TogglePoisonOverlay(netObj.InputAuthority, netObj.Id, false);
|
|
}
|
|
}
|
|
affectedPlayers.RemoveAt(i);
|
|
}
|
|
}
|
|
|
|
yield return new WaitForSeconds(tickInterval);
|
|
elapsed += tickInterval;
|
|
}
|
|
|
|
// Clean up: turn off overlay for any remaining players in zone
|
|
foreach (var p in affectedPlayers)
|
|
{
|
|
if (p != null)
|
|
{
|
|
var netObj = p.GetComponent<NetworkObject>();
|
|
if (netObj != null)
|
|
{
|
|
RPC_TogglePoisonOverlay(netObj.InputAuthority, netObj.Id, false);
|
|
}
|
|
}
|
|
}
|
|
affectedPlayers.Clear();
|
|
|
|
// Despawn the trap
|
|
DespawnTrap();
|
|
}
|
|
|
|
[Rpc(RpcSources.StateAuthority, RpcTargets.InputAuthority)]
|
|
private void RPC_TogglePoisonOverlay([RpcTarget] PlayerRef targetPlayer, NetworkId victimId, bool show)
|
|
{
|
|
// Resolve the victim GameObject using NetworkId on the client
|
|
var victimNetObj = Runner.FindObject(victimId);
|
|
if (victimNetObj != null)
|
|
{
|
|
var overlay = victimNetObj.GetComponentInChildren<PoisonScreenOverlay>();
|
|
if (overlay != null)
|
|
{
|
|
overlay.SetOverlayActive(show);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Draw the gas radius in editor for debugging
|
|
private void OnDrawGizmosSelected()
|
|
{
|
|
if (trapData != null)
|
|
{
|
|
Gizmos.color = new Color(0, 1, 0, 0.3f);
|
|
Gizmos.DrawSphere(transform.position, trapData.EffectRadius);
|
|
}
|
|
}
|
|
}
|