Stash work

This commit is contained in:
Michal Pikulski
2025-12-02 23:56:13 +01:00
parent dc038b8c4c
commit f69db57bd7
103 changed files with 10123 additions and 903 deletions

View File

@@ -0,0 +1,198 @@
using Core;
using Core.Lifecycle;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using Minigames.FortFight.Fort;
namespace Minigames.FortFight.UI
{
/// <summary>
/// Displays HP bar and percentage for a fort
/// </summary>
public class FortHealthUI : ManagedBehaviour
{
#region Inspector Properties
[Header("UI References")]
[SerializeField] private Slider hpSlider;
[SerializeField] private TextMeshProUGUI hpPercentageText;
[SerializeField] private TextMeshProUGUI fortNameText;
[Header("Visual Feedback")]
[SerializeField] private Image fillImage;
[SerializeField] private Color healthyColor = Color.green;
[SerializeField] private Color damagedColor = Color.yellow;
[SerializeField] private Color criticalColor = Color.red;
[Header("Auto-Binding (for Dynamic Spawning)")]
[SerializeField] private bool autoBindToFort = true;
[SerializeField] private bool isPlayerFort = true;
[Tooltip("Leave empty to auto-find")]
[SerializeField] private Core.FortManager fortManager;
#endregion
#region Private State
private FortController trackedFort;
#endregion
#region Lifecycle
internal override void OnManagedStart()
{
base.OnManagedStart();
// Auto-bind to dynamically spawned forts
if (autoBindToFort)
{
SetupAutoBinding();
}
}
internal override void OnManagedDestroy()
{
base.OnManagedDestroy();
// Unsubscribe from fort events
if (trackedFort != null)
{
trackedFort.OnFortDamaged -= OnFortDamaged;
}
// Unsubscribe from fort manager
if (fortManager != null)
{
fortManager.OnPlayerFortSpawned -= OnFortSpawned;
fortManager.OnEnemyFortSpawned -= OnFortSpawned;
}
}
#endregion
#region Auto-Binding
private void SetupAutoBinding()
{
// Find FortManager if not assigned
if (fortManager == null)
{
fortManager = FindFirstObjectByType<Core.FortManager>();
}
if (fortManager == null)
{
Logging.Warning($"[FortHealthUI] Cannot auto-bind: FortManager not found. HP UI will not update.");
return;
}
// Subscribe to appropriate spawn event
if (isPlayerFort)
{
fortManager.OnPlayerFortSpawned += OnFortSpawned;
Logging.Debug($"[FortHealthUI] Subscribed to PLAYER fort spawn");
}
else
{
fortManager.OnEnemyFortSpawned += OnFortSpawned;
Logging.Debug($"[FortHealthUI] Subscribed to ENEMY fort spawn");
}
}
private void OnFortSpawned(FortController fort)
{
BindToFort(fort);
}
#endregion
#region Setup
/// <summary>
/// Bind this UI to a specific fort
/// </summary>
public void BindToFort(FortController fort)
{
if (fort == null)
{
Logging.Warning("[FortHealthUI] Cannot bind to null fort!");
return;
}
// Unsubscribe from previous fort
if (trackedFort != null)
{
trackedFort.OnFortDamaged -= OnFortDamaged;
}
trackedFort = fort;
// Subscribe to fort events
trackedFort.OnFortDamaged += OnFortDamaged;
// Initialize UI
if (fortNameText != null)
{
fortNameText.text = fort.FortName;
}
UpdateDisplay();
Logging.Debug($"[FortHealthUI] Bound to fort: {fort.FortName}");
}
#endregion
#region Event Handlers
private void OnFortDamaged(float damage, float hpPercentage)
{
UpdateDisplay();
}
#endregion
#region Display Update
private void UpdateDisplay()
{
if (trackedFort == null) return;
float hpPercent = trackedFort.HpPercentage;
// Update slider
if (hpSlider != null)
{
hpSlider.value = hpPercent / 100f;
}
// Update text
if (hpPercentageText != null)
{
hpPercentageText.text = $"{hpPercent:F0}%";
}
// Update color based on HP
if (fillImage != null)
{
if (hpPercent > 60f)
{
fillImage.color = healthyColor;
}
else if (hpPercent > 30f)
{
fillImage.color = damagedColor;
}
else
{
fillImage.color = criticalColor;
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ed9e5253aa2a40c9a9028767466456b1
timeCreated: 1764592117

View File

@@ -0,0 +1,266 @@
using Core;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using UI.Core;
using Minigames.FortFight.Core;
using Minigames.FortFight.Data;
using Pixelplacement;
namespace Minigames.FortFight.UI
{
/// <summary>
/// Main gameplay UI page for Fort Fight minigame.
/// Displays turn info and allows player to take actions (stubbed for Phase 1).
/// </summary>
public class GameplayPage : UIPage
{
[Header("UI Elements")]
[SerializeField] private TextMeshProUGUI turnIndicatorText;
[SerializeField] private TextMeshProUGUI currentPlayerText;
[SerializeField] private Button takeActionButton;
[SerializeField] private TextMeshProUGUI actionButtonText;
[Header("Optional Visual Elements")]
[SerializeField] private CanvasGroup canvasGroup;
[SerializeField] private GameObject playerActionPanel;
[SerializeField] private GameObject aiTurnPanel;
private TurnManager turnManager;
#region Initialization
internal override void OnManagedAwake()
{
base.OnManagedAwake();
// Validate references
ValidateReferences();
// Set up button
if (takeActionButton != null)
{
takeActionButton.onClick.AddListener(OnTakeActionClicked);
}
// Set up canvas group
if (canvasGroup == null)
{
canvasGroup = GetComponent<CanvasGroup>();
}
}
internal override void OnManagedStart()
{
base.OnManagedStart();
// Get turn manager reference
turnManager = FindObjectOfType<TurnManager>();
if (turnManager != null)
{
turnManager.OnTurnStarted += OnTurnStarted;
turnManager.OnTurnEnded += OnTurnEnded;
}
else
{
Logging.Error("[GameplayPage] TurnManager not found!");
}
}
private void ValidateReferences()
{
if (turnIndicatorText == null)
{
Logging.Warning("[GameplayPage] Turn indicator text not assigned!");
}
if (currentPlayerText == null)
{
Logging.Warning("[GameplayPage] Current player text not assigned!");
}
if (takeActionButton == null)
{
Logging.Error("[GameplayPage] Take action button not assigned!");
}
if (actionButtonText == null)
{
Logging.Warning("[GameplayPage] Action button text not assigned!");
}
}
#endregion
#region Turn Events
/// <summary>
/// Called when a new turn starts
/// </summary>
private void OnTurnStarted(PlayerData currentPlayer, TurnState turnState)
{
Logging.Debug($"[GameplayPage] Turn started - Player: {currentPlayer.PlayerName}, State: {turnState}");
UpdateTurnUI(currentPlayer, turnState);
}
/// <summary>
/// Called when the current turn ends
/// </summary>
private void OnTurnEnded(PlayerData player)
{
Logging.Debug($"[GameplayPage] Turn ended for {player.PlayerName}");
}
#endregion
#region UI Updates
/// <summary>
/// Update the UI to reflect current turn state
/// </summary>
private void UpdateTurnUI(PlayerData currentPlayer, TurnState turnState)
{
// Update turn counter
if (turnIndicatorText != null && turnManager != null)
{
turnIndicatorText.text = $"Turn {turnManager.TurnCount + 1}";
}
// Update current player display
if (currentPlayerText != null)
{
currentPlayerText.text = $"{currentPlayer.PlayerName}'s Turn";
}
// Show/hide appropriate panels based on turn state
if (turnState == TurnState.AITurn)
{
// AI turn - hide player controls
if (playerActionPanel != null)
{
playerActionPanel.SetActive(false);
}
if (aiTurnPanel != null)
{
aiTurnPanel.SetActive(true);
}
if (takeActionButton != null)
{
takeActionButton.gameObject.SetActive(false);
}
}
else if (turnState == TurnState.PlayerOneTurn || turnState == TurnState.PlayerTwoTurn)
{
// Player turn - show controls
if (playerActionPanel != null)
{
playerActionPanel.SetActive(true);
}
if (aiTurnPanel != null)
{
aiTurnPanel.SetActive(false);
}
if (takeActionButton != null)
{
takeActionButton.gameObject.SetActive(true);
}
if (actionButtonText != null)
{
actionButtonText.text = "Take Action (Stubbed)";
}
}
}
#endregion
#region Button Callbacks
/// <summary>
/// Called when player clicks the "Take Action" button
/// STUBBED for Phase 1 - just logs and ends turn
/// </summary>
private void OnTakeActionClicked()
{
if (turnManager == null)
{
Logging.Error("[GameplayPage] Cannot take action - TurnManager not found!");
return;
}
PlayerData currentPlayer = turnManager.CurrentPlayer;
// STUBBED: Log the action
Logging.Debug($"[GameplayPage] {currentPlayer.PlayerName} takes action! (STUBBED - no actual combat yet)");
// TODO Phase 3: Replace with actual slingshot/shooting interface
// End the turn
turnManager.EndTurn();
}
#endregion
#region Transitions
protected override void DoTransitionIn(System.Action onComplete)
{
// Simple fade in if canvas group is available
if (canvasGroup != null)
{
canvasGroup.alpha = 0f;
Tween.CanvasGroupAlpha(canvasGroup, 1f, transitionDuration, 0f, Tween.EaseOut,
completeCallback: () => onComplete?.Invoke());
}
else
{
onComplete?.Invoke();
}
}
protected override void DoTransitionOut(System.Action onComplete)
{
// Simple fade out if canvas group is available
if (canvasGroup != null)
{
Tween.CanvasGroupAlpha(canvasGroup, 0f, transitionDuration, 0f, Tween.EaseIn,
completeCallback: () => onComplete?.Invoke());
}
else
{
onComplete?.Invoke();
}
}
#endregion
#region Cleanup
internal override void OnManagedDestroy()
{
base.OnManagedDestroy();
// Unsubscribe from turn manager events
if (turnManager != null)
{
turnManager.OnTurnStarted -= OnTurnStarted;
turnManager.OnTurnEnded -= OnTurnEnded;
}
// Unsubscribe from button
if (takeActionButton != null)
{
takeActionButton.onClick.RemoveListener(OnTakeActionClicked);
}
}
#endregion
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: e22e2729514a5ee40bb2d4c23fbeb75f

View File

@@ -0,0 +1,150 @@
using Core;
using UnityEngine;
using UnityEngine.UI;
using UI.Core;
using Minigames.FortFight.Core;
using Minigames.FortFight.Data;
using Pixelplacement;
namespace Minigames.FortFight.UI
{
/// <summary>
/// UI page for selecting single-player or two-player mode
/// </summary>
public class ModeSelectionPage : UIPage
{
[Header("Mode Selection Buttons")]
[SerializeField] private Button singlePlayerButton;
[SerializeField] private Button twoPlayerButton;
[Header("Optional Visual Elements")]
[SerializeField] private GameObject titleText;
[SerializeField] private CanvasGroup canvasGroup;
#region Initialization
internal override void OnManagedAwake()
{
base.OnManagedAwake();
// Validate button references
if (singlePlayerButton == null)
{
Logging.Error("[ModeSelectionPage] Single player button not assigned!");
}
else
{
singlePlayerButton.onClick.AddListener(OnSinglePlayerSelected);
}
if (twoPlayerButton == null)
{
Logging.Error("[ModeSelectionPage] Two player button not assigned!");
}
else
{
twoPlayerButton.onClick.AddListener(OnTwoPlayerSelected);
}
// Set up canvas group if available
if (canvasGroup == null)
{
canvasGroup = GetComponent<CanvasGroup>();
}
}
#endregion
#region Button Callbacks
/// <summary>
/// Called when single player button is clicked
/// </summary>
private void OnSinglePlayerSelected()
{
Logging.Debug("[ModeSelectionPage] Single player mode selected");
if (FortFightGameManager.Instance != null)
{
FortFightGameManager.Instance.SelectGameMode(FortFightGameMode.SinglePlayer);
}
else
{
Logging.Error("[ModeSelectionPage] FortFightGameManager instance not found!");
}
}
/// <summary>
/// Called when two player button is clicked
/// </summary>
private void OnTwoPlayerSelected()
{
Logging.Debug("[ModeSelectionPage] Two player mode selected");
if (FortFightGameManager.Instance != null)
{
FortFightGameManager.Instance.SelectGameMode(FortFightGameMode.TwoPlayer);
}
else
{
Logging.Error("[ModeSelectionPage] FortFightGameManager instance not found!");
}
}
#endregion
#region Transitions
protected override void DoTransitionIn(System.Action onComplete)
{
// Simple fade in if canvas group is available
if (canvasGroup != null)
{
canvasGroup.alpha = 0f;
Tween.CanvasGroupAlpha(canvasGroup, 1f, transitionDuration, 0f, Tween.EaseOut,
completeCallback: () => onComplete?.Invoke());
}
else
{
onComplete?.Invoke();
}
}
protected override void DoTransitionOut(System.Action onComplete)
{
// Simple fade out if canvas group is available
if (canvasGroup != null)
{
Tween.CanvasGroupAlpha(canvasGroup, 0f, transitionDuration, 0f, Tween.EaseIn,
completeCallback: () => onComplete?.Invoke());
}
else
{
onComplete?.Invoke();
}
}
#endregion
#region Cleanup
internal override void OnManagedDestroy()
{
base.OnManagedDestroy();
// Unsubscribe from button events
if (singlePlayerButton != null)
{
singlePlayerButton.onClick.RemoveListener(OnSinglePlayerSelected);
}
if (twoPlayerButton != null)
{
twoPlayerButton.onClick.RemoveListener(OnTwoPlayerSelected);
}
}
#endregion
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 3c1ab5687204db54eaa4ea7f812b3c06