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
}