using UnityEngine; using System.Collections.Generic; using TMPro; /// /// Manages checkpoint saving and loading for the respawn system. /// Automatically captures player's start position as fallback respawn point. /// public class CheckpointSystem : MonoBehaviour { public static CheckpointSystem Instance { get; private set; } [Header("References")] public TeamCohesionManager cohesionManager; public Transform playerTransform; public GridMovement playerMovement; [Header("Settings")] public bool autoSaveOnCheckpoint = true; public float checkpointRadius = 3f; public Vector3 respawnRotation = new Vector3(0, 90, 0); // to look east at respawnss [Header("Respawn UI")] public TextMeshProUGUI respawnText; public CanvasGroup respawnCanvasGroup; public string respawnMessage = "Respawned at Checkpoint"; [Header("Fade Animation")] public float fadeDuration = 0.5f; public float displayDuration = 2f; private Vector3 savedPlayerPosition; private int savedFloorLevel; private List savedCharacters = new List(); private bool hasCheckpoint = false; [System.Serializable] // This class is used to save the characters data when the checkpoint is saved private class SavedCharacterData { public CharacterInGroup character; public int hp; public int fatigue; public int mana; public int gridX; public int gridY; public SavedCharacterData(CharacterInGroup chara) { character = chara; hp = chara.currentHP; fatigue = chara.currentFatigue; mana = chara.currentMana; gridX = chara.gridX; gridY = chara.gridY; } } #region Initialization private void Awake() { if (Instance != null && Instance != this) { Destroy(gameObject); return; } Instance = this; } private void Start() { FindReferences(); SaveInitialCheckpoint(); } private void FindReferences() { if (cohesionManager == null) cohesionManager = FindFirstObjectByType(); if (playerTransform == null) { GameObject player = GameObject.FindGameObjectWithTag("Player"); if (player != null) playerTransform = player.transform; } if (playerMovement == null) playerMovement = FindFirstObjectByType(); } private void SaveInitialCheckpoint() { // Wait a frame to ensure all systems are initialized StartCoroutine(SaveInitialCheckpointDelayed()); } private System.Collections.IEnumerator SaveInitialCheckpointDelayed() { yield return new WaitForSeconds(0.5f); // Save the starting position as initial checkpoint SaveCheckpoint(); Debug.Log("[CheckpointSystem] Initial checkpoint saved at start position"); } #endregion #region Checkpoint Save public void SaveCheckpoint() { if (playerTransform == null || cohesionManager == null) { Debug.LogWarning("[CheckpointSystem] Cannot save checkpoint: missing references"); return; } savedPlayerPosition = playerTransform.position; if (playerMovement != null) savedFloorLevel = playerMovement.currentFloorLevel; savedCharacters.Clear(); foreach (var character in cohesionManager.groupMembers) { savedCharacters.Add(new SavedCharacterData(character)); } hasCheckpoint = true; Debug.Log($"[CheckpointSystem] Checkpoint saved with {savedCharacters.Count} characters"); } public void SaveCheckpointAt(Vector3 position) { savedPlayerPosition = position; if (playerMovement != null) savedFloorLevel = playerMovement.currentFloorLevel; savedCharacters.Clear(); if (cohesionManager != null) { foreach (var character in cohesionManager.groupMembers) { savedCharacters.Add(new SavedCharacterData(character)); } } hasCheckpoint = true; Debug.Log($"[CheckpointSystem] Manual checkpoint saved at {savedPlayerPosition}"); } #endregion #region Checkpoint Load public void LoadCheckpoint() { if (!hasCheckpoint) { Debug.LogWarning("[CheckpointSystem] No checkpoint available"); return; } if (playerTransform != null) { playerTransform.position = savedPlayerPosition; playerTransform.rotation = Quaternion.Euler(respawnRotation); } if (playerMovement != null) playerMovement.currentFloorLevel = savedFloorLevel; RestoreCharacters(); // Show respawn UI message ShowRespawnMessage(); } private void RestoreCharacters() { if (cohesionManager == null) return; cohesionManager.groupMembers.Clear(); foreach (var saved in savedCharacters) { CharacterInGroup character = saved.character; character.currentHP = character.maxHP; character.currentFatigue = character.maxFatigue; character.currentMana = character.maxMana; character.gridX = saved.gridX; character.gridY = saved.gridY; cohesionManager.groupMembers.Add(character); } RecreatePartyUI(); } private void RecreatePartyUI() { PartyUIManager partyUI = FindFirstObjectByType(); if (partyUI != null) { partyUI.DisplayPartyUI(); } } #endregion #region Checkpoint Triggers private void OnTriggerEnter(Collider other) { if (other.CompareTag("Checkpoint") && autoSaveOnCheckpoint) { SaveCheckpoint(); } } #endregion #region Public API public bool HasCheckpoint() => hasCheckpoint; public Vector3 GetCheckpointPosition() => savedPlayerPosition; #endregion #region Respawn UI private void ShowRespawnMessage() { if (respawnText != null && respawnCanvasGroup != null) { respawnText.text = respawnMessage; respawnText.gameObject.SetActive(true); StartCoroutine(FadeRespawnTextInOut()); } } private System.Collections.IEnumerator FadeRespawnTextInOut() { // Fade in from 0 to 1 float elapsed = 0f; while (elapsed < fadeDuration) { elapsed += Time.deltaTime; respawnCanvasGroup.alpha = Mathf.Lerp(0f, 1f, elapsed / fadeDuration); yield return null; } respawnCanvasGroup.alpha = 1f; // Display at full opacity yield return new WaitForSeconds(displayDuration); // Fade out from 1 to 0 elapsed = 0f; while (elapsed < fadeDuration) { elapsed += Time.deltaTime; respawnCanvasGroup.alpha = Mathf.Lerp(1f, 0f, elapsed / fadeDuration); yield return null; } respawnCanvasGroup.alpha = 0f; // Deactivate text object respawnText.gameObject.SetActive(false); } #endregion }