using UnityEngine; using UnityEngine.Rendering; // Potrzebne dla Volume using Beyond; // Dla dostępu do Twojej klasy Player using Invector; // Dla vDamage public class PoisonZone : MonoBehaviour { [Header("Damage Settings")] [Tooltip("Amount of damage dealt at each interval.")] public int damageAmount = 5; [Tooltip("Time in seconds between each damage tick.")] public float damageInterval = 1.0f; [Header("Volume Animation Settings")] [Tooltip("Reference to the Volume component to animate.")] public Volume poisonVolume; [Tooltip("Animation curve for ONE CYCLE of the looping Volume weight. X-axis (Time) from 0 to 1. Y-axis (Value) is the weight intensity (e.g., 0 to 1, where 1 is full effect defined by the curve values).")] public AnimationCurve loopingVolumeWeightCurve = new AnimationCurve( new Keyframe(0, 0), new Keyframe(0.5f, 0.8f), new Keyframe(1, 0) ); [Tooltip("Duration of one full cycle of the looping animation, in seconds. Must be greater than 0.")] public float loopCycleDuration = 2.0f; [Tooltip("Duration of the fade-in/fade-out effect for the looping animation, in seconds. Set to 0 for instant on/off of the loop.")] public float volumeFadeDuration = 1.0f; [Header("Sound Settings")] [Tooltip("Coughing sound effect to play.")] public AudioClip coughSound; [Tooltip("Interval in seconds for repeating the cough sound while player is in the zone. Set to 0 for no repeat (only on enter).")] public float coughInterval = 4.0f; private Player currentPlayerInZone; private float timeSinceLastDamage = 0f; private float timeSinceLastCough = 0f; private bool playerCurrentlyInZone = false; // Ta flaga jest kluczowa dla logiki ponownego wejścia private float currentLoopProgress = 0f; private float currentFadeProgress = 0f; void Start() { Collider col = GetComponent(); if (col == null || !col.isTrigger) { Debug.LogWarning($"PoisonZone: Collider not found or not set to 'Is Trigger' on GameObject: {gameObject.name}", this); } if (poisonVolume == null) { Debug.LogWarning($"PoisonZone: No Volume assigned in Inspector. Post-processing effects will not be animated for {gameObject.name}", this); } else { poisonVolume.weight = 0f; poisonVolume.enabled = false; } if (loopCycleDuration <= 0.001f) { Debug.LogWarning("PoisonZone: Loop Cycle Duration should be greater than 0 for looping animation. Setting to 1s.", this); loopCycleDuration = 1f; } } void Update() { if (poisonVolume != null) { float targetFadeProgress = playerCurrentlyInZone ? 1.0f : 0.0f; if (volumeFadeDuration > 0.001f) { float fadeStep = (1.0f / volumeFadeDuration) * Time.deltaTime; currentFadeProgress = Mathf.MoveTowards(currentFadeProgress, targetFadeProgress, fadeStep); } else { currentFadeProgress = targetFadeProgress; } if (playerCurrentlyInZone || currentFadeProgress > 0.001f) { currentLoopProgress += Time.deltaTime / loopCycleDuration; currentLoopProgress = currentLoopProgress % 1.0f; } float loopedWeightValue = loopingVolumeWeightCurve.Evaluate(currentLoopProgress); poisonVolume.weight = loopedWeightValue * currentFadeProgress; bool shouldBeEnabled; if (currentFadeProgress > 0.001f) { shouldBeEnabled = true; } else { shouldBeEnabled = false; } if (poisonVolume.enabled != shouldBeEnabled) { poisonVolume.enabled = shouldBeEnabled; } } if (playerCurrentlyInZone && currentPlayerInZone != null) // Upewnij się, że currentPlayerInZone nie jest null { timeSinceLastDamage += Time.deltaTime; if (timeSinceLastDamage >= damageInterval) { ApplyPoisonDamage(); timeSinceLastDamage = 0f; } if (coughSound != null && coughInterval > 0) { timeSinceLastCough += Time.deltaTime; if (timeSinceLastCough >= coughInterval) { PlayCoughSound(); timeSinceLastCough = 0f; } } } } void OnTriggerEnter(Collider other) { Player enteredPlayer = other.GetComponent(); if (enteredPlayer != null) { // Ta logika powinna poprawnie obsługiwać ponowne wejście tego samego gracza // oraz wejście nowego gracza. if (currentPlayerInZone != enteredPlayer || !playerCurrentlyInZone) { // Jeśli to faktycznie nowy gracz LUB ten sam gracz, ale nie był 'aktywny' (playerCurrentlyInZone było false) if (currentPlayerInZone != enteredPlayer) { currentPlayerInZone = enteredPlayer; // Zaktualizuj referencję tylko jeśli to inny gracz } playerCurrentlyInZone = true; // Zawsze ustawiaj na true przy "aktywnym" wejściu timeSinceLastDamage = 0f; timeSinceLastCough = 0f; currentLoopProgress = 0f; // Resetuj pętlę animacji Volume if (coughSound != null) { PlayCoughSound(); } // Debug.Log($"{enteredPlayer.name} ENTERED/RE-ENTERED zone. playerCurrentlyInZone: {playerCurrentlyInZone}"); } } } void OnTriggerExit(Collider other) { Player exitedPlayer = other.GetComponent(); // Sprawdzamy, czy to TEN gracz, który był aktywnie śledzony w strefie i właśnie opuszcza. if (exitedPlayer != null && exitedPlayer == currentPlayerInZone && playerCurrentlyInZone) { playerCurrentlyInZone = false; // Oznacz, że gracz (ten konkretny) już nie jest aktywnie w strefie // Debug.Log($"{exitedPlayer.name} EXITED zone. playerCurrentlyInZone: {playerCurrentlyInZone}"); // Nie zerujemy currentPlayerInZone, aby OnTriggerEnter mogło poprawnie wykryć powrót tego samego gracza. } } private void ApplyPoisonDamage() { if (currentPlayerInZone != null && currentPlayerInZone.ThirdPersonController != null) { var healthController = currentPlayerInZone.ThirdPersonController; if (healthController != null && !healthController.isDead) { // Ta linia jest kluczowa dla pomijania animacji hita. // Zakłada, że masz zmodyfikowany vDamage.cs (z polem ignoreHitEffects) // oraz odpowiednie warunki w Player.cs i vHealthController.cs. vDamage damageInstance = new vDamage(damageAmount, true); // Jeśli vDamage(int, bool) nie istnieje, a vDamage.cs jest zmodyfikowane: // vDamage damageInstance = new vDamage(damageAmount); // damageInstance.ignoreHitEffects = true; healthController.TakeDamage(damageInstance); } } } private void PlayCoughSound() { if (currentPlayerInZone != null && coughSound != null) { currentPlayerInZone.PlaySingleSound(coughSound, true); } } }