feat: draws trigger Purgatory Duel for the Queen + post-defeat restart menu

This commit is contained in:
2026-08-25 02:31:58 -03:00
parent 916acd3d79
commit 58fcf0fa5c
3 changed files with 225 additions and 17 deletions
@@ -513,8 +513,13 @@ public class CampaignManager : MonoBehaviour
private void OnGameDraw(string reason)
{
if (!_campaignActive) return;
Debug.LogWarning($"[CampaignManager] Tablas ({reason}). Tratando como derrota.");
Debug.Log($"[CampaignManager] Tablas ({reason}). El purgatorio se jugará por una reina.");
if (PurgatoryDuelManager.TryStartFromDraw(this, reason))
return; // Capturar a La Muerte resuelve la victoria del capítulo
Debug.LogWarning($"[CampaignManager] Duelo por tablas no iniciable ({reason}). Tratando como derrota.");
OnChapterDefeat();
}
@@ -24,6 +24,7 @@ public class PurgatoryDuelManager : MonoBehaviour
private Phase _phase = Phase.Idle;
private int _turn;
private bool _rescueUsed;
private string _drawReason;
private Piece _playerPiece;
private Piece _boss;
@@ -61,10 +62,41 @@ public class PurgatoryDuelManager : MonoBehaviour
if (matingPiece == null)
return false;
return StartDuel(campaign, matingPiece, drawReason: null);
}
/// <summary>
/// Punto de entrada para TABLAS: el purgatorio se juega "por una reina".
/// El campeón del jugador es la blanca viva de mayor valor (el Rey como
/// último recurso). Si el duelo termina en captura de La Muerte, la campaña
/// resuelve la victoria del capítulo; si el jugador cae, flujo de derrota.
/// Retorna false si el duelo no puede iniciarse y la campaña debe resolver derrota.
/// </summary>
public static bool TryStartFromDraw(CampaignManager campaign, string reason)
{
if (Instance != null && Instance.IsActive)
return false;
if (campaign == null || GameManager.Instance == null || BoardManager.Instance == null)
return false;
Piece[,] board = GameManager.Instance.board;
if (board == null)
return false;
Piece champion = FindChampionPiece(board);
if (champion == null)
return false;
return StartDuel(campaign, champion, reason);
}
private static bool StartDuel(CampaignManager campaign, Piece playerPiece, string drawReason)
{
GameObject go = new GameObject(typeof(PurgatoryDuelManager).Name);
go.transform.SetParent(campaign.transform, worldPositionStays: false);
Instance = go.AddComponent<PurgatoryDuelManager>();
Instance.Begin(campaign, matingPiece);
Instance.Begin(campaign, playerPiece, drawReason);
return true;
}
@@ -104,10 +136,30 @@ public class PurgatoryDuelManager : MonoBehaviour
return best;
}
private void Begin(CampaignManager campaign, Piece matingPiece)
/// <summary>
/// Campeón de las tablas: la blanca viva de mayor valor en el tablero.
/// El Rey es el fallback (siempre existe en una posición legal).
/// </summary>
private static Piece FindChampionPiece(Piece[,] board)
{
Piece best = null;
foreach (Piece piece in board)
{
if (piece == null || !piece.isWhite)
continue;
if (best == null || piece.pieceValue > best.pieceValue)
best = piece;
}
return best;
}
private void Begin(CampaignManager campaign, Piece playerPiece, string drawReason)
{
_campaign = campaign;
_playerPiece = matingPiece;
_playerPiece = playerPiece;
_drawReason = drawReason;
_turn = 0;
_rescueUsed = false;
_devoured.Clear();
@@ -224,7 +276,12 @@ public class PurgatoryDuelManager : MonoBehaviour
{
_ui = gameObject.AddComponent<PurgatoryDuelUI>();
_ui.Build();
_ui.ShowQuote(MuerteQuotes.GetIntro());
if (_drawReason != null)
_ui.ShowQuote($"Tablas ({_drawReason}). El purgatorio se jugará por una reina.");
else
_ui.ShowQuote(MuerteQuotes.GetIntro());
_ui.SetTurn(1);
}
@@ -336,7 +393,7 @@ public class PurgatoryDuelManager : MonoBehaviour
AudioManager.Instance.PlayCapture();
_ui.ShowQuote(MuerteQuotes.GetPlayerWin());
_ui.ShowVictory("EL TABLERO ES TUYO");
_ui.ShowVictory(_drawReason != null ? "LA REINA ES TUYA" : "EL TABLERO ES TUYO");
CleanupDuel(restorePieces: true);
+156 -10
View File
@@ -234,22 +234,16 @@ namespace AjedrezPurgatorio.UI
// Wait for feedback display time
yield return new WaitForSeconds(_feedbackDisplayTime);
// Show transition message
// Hide feedback and input panel
if (_feedbackText != null)
{
_feedbackText.text = "Regresando al menú...";
_feedbackText.gameObject.SetActive(false);
}
yield return new WaitForSeconds(0.5f);
// Hide panel
Hide();
// Wait for fade out to complete
yield return new WaitForSeconds(_fadeOutDuration);
// Transition to Main Menu
TransitionToMainMenu();
// El jugador decide el desenlace: reintentar o volver al menú.
ShowPostSubmitMenu();
_isSubmitting = false;
}
@@ -301,6 +295,158 @@ namespace AjedrezPurgatorio.UI
#endregion
#region Post-Submit Menu (runtime UI)
private GameObject _postSubmitRoot;
/// <summary>
/// Menú final tras la inscripción en el Memorial: reintentar el
/// capítulo o volver al menú principal. Construido 100% en runtime
/// (mismo patrón que PurgatoryDuelUI, sin edición de escenas).
/// </summary>
private void ShowPostSubmitMenu()
{
if (_postSubmitRoot == null)
{
BuildPostSubmitMenu();
}
_postSubmitRoot.SetActive(true);
if (_enableDebugLogging)
{
Debug.Log("[DeadKingInputUI] Post-submit menu shown.");
}
}
private void HidePostSubmitMenu()
{
if (_postSubmitRoot != null)
{
Destroy(_postSubmitRoot);
_postSubmitRoot = null;
}
}
private void BuildPostSubmitMenu()
{
TMP_FontAsset font = TMP_Settings.defaultFontAsset;
var canvasGO = new GameObject("DeadKingPostSubmitCanvas");
var canvas = canvasGO.AddComponent<Canvas>();
canvas.renderMode = RenderMode.ScreenSpaceOverlay;
canvas.sortingOrder = 450;
canvasGO.AddComponent<CanvasScaler>().uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
canvasGO.AddComponent<GraphicRaycaster>();
_postSubmitRoot = canvasGO;
var panel = new GameObject("Panel");
panel.transform.SetParent(canvasGO.transform, false);
var bg = panel.AddComponent<Image>();
bg.color = new Color(0.03f, 0.02f, 0.04f, 0.96f);
bg.raycastTarget = true;
Stretch(bg.rectTransform);
var title = CreateText("Title", "EL MEMORIAL REGISTRA TU NOMBRE", 34, new Color(0.9f, 0.82f, 0.55f), font);
title.transform.SetParent(panel.transform, false);
Anchor(title.rectTransform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0, -140), new Vector2(1100, 60));
var subtitle = CreateText("Subtitle", "¿Qué será de tu alma?", 24, new Color(0.75f, 0.72f, 0.65f), font);
subtitle.fontStyle = FontStyles.Italic;
subtitle.transform.SetParent(panel.transform, false);
Anchor(subtitle.rectTransform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0, -195), new Vector2(800, 45));
var retryButton = CreateButton("RetryButton", "Reintentar capítulo", font, new Color(0.45f, 0.08f, 0.08f));
retryButton.transform.SetParent(panel.transform, false);
Anchor((RectTransform)retryButton.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0, 30), new Vector2(360, 64));
retryButton.onClick.AddListener(OnRestartClicked);
var menuButton = CreateButton("MenuButton", "Volver al menú principal", font, new Color(0.15f, 0.15f, 0.17f));
menuButton.transform.SetParent(panel.transform, false);
Anchor((RectTransform)menuButton.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0, -55), new Vector2(360, 64));
menuButton.onClick.AddListener(OnReturnToMenuClicked);
}
private void OnRestartClicked()
{
if (_enableDebugLogging)
{
Debug.Log("[DeadKingInputUI] Retry chapter chosen.");
}
HidePostSubmitMenu();
if (CampaignManager.Instance != null)
{
CampaignManager.Instance.RetryChapter();
}
else
{
Debug.LogWarning("[DeadKingInputUI] CampaignManager no disponible. Volviendo al menú.");
TransitionToMainMenu();
}
}
private void OnReturnToMenuClicked()
{
if (_enableDebugLogging)
{
Debug.Log("[DeadKingInputUI] Return to main menu chosen.");
}
HidePostSubmitMenu();
TransitionToMainMenu();
}
private static TextMeshProUGUI CreateText(string name, string content, int size, Color color, TMP_FontAsset font)
{
var go = new GameObject(name);
var tmp = go.AddComponent<TextMeshProUGUI>();
tmp.text = content;
tmp.fontSize = size;
tmp.color = color;
tmp.alignment = TextAlignmentOptions.Center;
tmp.raycastTarget = false;
if (font != null)
{
tmp.font = font;
}
return tmp;
}
private static Button CreateButton(string name, string label, TMP_FontAsset font, Color color)
{
var go = new GameObject(name);
var image = go.AddComponent<Image>();
image.color = color;
var button = go.AddComponent<Button>();
var text = CreateText("Label", label, 26, Color.white, font);
text.transform.SetParent(go.transform, false);
Stretch(text.rectTransform);
return button;
}
private static void Anchor(RectTransform rt, Vector2 anchorMin, Vector2 anchorMax, Vector2 offset, Vector2 size)
{
rt.anchorMin = anchorMin;
rt.anchorMax = anchorMax;
rt.pivot = new Vector2(0.5f, 0.5f);
rt.anchoredPosition = offset;
rt.sizeDelta = size;
}
private static void Stretch(RectTransform rt)
{
rt.anchorMin = Vector2.zero;
rt.anchorMax = Vector2.one;
rt.offsetMin = Vector2.zero;
rt.offsetMax = Vector2.zero;
}
#endregion
#region Fade Effects
/// <summary>