255 lines
8.4 KiB
C#
255 lines
8.4 KiB
C#
using System.Collections.Generic;
|
|
using BumpCombat.Audio;
|
|
using BumpCombat.Constants;
|
|
using BumpCombat.Core;
|
|
using BumpCombat.Player;
|
|
using BumpCombat.UI;
|
|
using UnityEngine;
|
|
using UnityEngine.InputSystem;
|
|
using UnityEngine.UI;
|
|
|
|
namespace BumpCombat.Progression
|
|
{
|
|
public sealed class LevelUpController : MonoBehaviour
|
|
{
|
|
private const int MaximumSupportedOptions = 3;
|
|
|
|
[SerializeField] private GameObject panel;
|
|
[SerializeField] private Text[] optionTexts;
|
|
[System.NonSerialized] private ModifierDefinition[] modifierCatalog;
|
|
|
|
private readonly ModifierDefinition[] shownModifiers =
|
|
new ModifierDefinition[MaximumSupportedOptions];
|
|
private Image[] optionCardImages = System.Array.Empty<Image>();
|
|
private ExperienceSystem experienceSystem;
|
|
private PlayerStats playerStats;
|
|
private PlayerHealth playerHealth;
|
|
private int selectedIndex;
|
|
private int shownCount;
|
|
private int pendingSelections;
|
|
private int ignoreInputThroughFrame;
|
|
|
|
private void Start()
|
|
{
|
|
experienceSystem = FindAnyObjectByType<ExperienceSystem>();
|
|
if (experienceSystem == null || panel == null)
|
|
{
|
|
enabled = false;
|
|
return;
|
|
}
|
|
|
|
playerStats = experienceSystem.GetComponent<PlayerStats>();
|
|
playerHealth = experienceSystem.GetComponent<PlayerHealth>();
|
|
experienceSystem.OnLevelGained += QueueSelection;
|
|
if (RunManager.Instance != null)
|
|
{
|
|
RunManager.Instance.OnSelectionChanged += HandleSelectionChanged;
|
|
}
|
|
PresentationUiStyle.ApplyPanel(panel.GetComponent<Image>());
|
|
ApplySelectionTextStyle();
|
|
CreateCardBackdrops();
|
|
panel.SetActive(false);
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
if (experienceSystem != null)
|
|
{
|
|
experienceSystem.OnLevelGained -= QueueSelection;
|
|
}
|
|
if (RunManager.Instance != null)
|
|
{
|
|
RunManager.Instance.OnSelectionChanged -= HandleSelectionChanged;
|
|
}
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
if (!panel.activeSelf
|
|
|| shownCount == 0
|
|
|| Time.frameCount <= ignoreInputThroughFrame
|
|
|| Keyboard.current == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (Keyboard.current.leftArrowKey.wasPressedThisFrame
|
|
|| Keyboard.current.upArrowKey.wasPressedThisFrame)
|
|
{
|
|
selectedIndex = (selectedIndex + shownCount - 1) % shownCount;
|
|
BumpCombatAudioService.Instance?.PlayUi("ui_move");
|
|
UpdateSelectionVisual();
|
|
}
|
|
else if (Keyboard.current.rightArrowKey.wasPressedThisFrame
|
|
|| Keyboard.current.downArrowKey.wasPressedThisFrame)
|
|
{
|
|
selectedIndex = (selectedIndex + 1) % shownCount;
|
|
BumpCombatAudioService.Instance?.PlayUi("ui_move");
|
|
UpdateSelectionVisual();
|
|
}
|
|
else if (Keyboard.current.spaceKey.wasPressedThisFrame)
|
|
{
|
|
bool applied = shownModifiers[selectedIndex].TryApply(
|
|
playerStats,
|
|
playerHealth);
|
|
if (applied)
|
|
{
|
|
BumpCombatAudioService.Instance?.PlayUi("ui_confirm");
|
|
}
|
|
panel.SetActive(false);
|
|
RunManager.Instance?.CloseSelection(this);
|
|
}
|
|
}
|
|
|
|
private void QueueSelection(int level)
|
|
{
|
|
pendingSelections++;
|
|
TryOpenPendingSelection();
|
|
}
|
|
|
|
private void TryOpenPendingSelection()
|
|
{
|
|
if (pendingSelections == 0
|
|
|| RunManager.Instance == null
|
|
|| !RunManager.Instance.TryOpenSelection(this))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!BuildChoices())
|
|
{
|
|
pendingSelections--;
|
|
RunManager.Instance.CloseSelection(this);
|
|
return;
|
|
}
|
|
|
|
pendingSelections--;
|
|
selectedIndex = 0;
|
|
panel.SetActive(true);
|
|
ignoreInputThroughFrame = Time.frameCount;
|
|
UpdateSelectionVisual();
|
|
}
|
|
|
|
private bool BuildChoices()
|
|
{
|
|
List<ModifierDefinition> pool = new();
|
|
ModifierDefinition[] definitions =
|
|
modifierCatalog ?? GameplayConstants.Current.LevelUp.ModifierDefinitions;
|
|
if (definitions != null)
|
|
{
|
|
foreach (ModifierDefinition definition in definitions)
|
|
{
|
|
if (definition != null && definition.CanApply(playerStats))
|
|
{
|
|
pool.Add(definition);
|
|
}
|
|
}
|
|
}
|
|
|
|
shownCount = Mathf.Min(
|
|
Mathf.Clamp(
|
|
GameplayConstants.Current.LevelUp.OptionCount,
|
|
1,
|
|
MaximumSupportedOptions),
|
|
optionTexts?.Length ?? 0,
|
|
pool.Count);
|
|
for (int i = 0; i < shownCount; i++)
|
|
{
|
|
int choiceIndex = Random.Range(0, pool.Count);
|
|
shownModifiers[i] = pool[choiceIndex];
|
|
pool.RemoveAt(choiceIndex);
|
|
optionTexts[i].text = shownModifiers[i].DisplayName;
|
|
optionTexts[i].gameObject.SetActive(true);
|
|
}
|
|
for (int i = shownCount; i < (optionTexts?.Length ?? 0); i++)
|
|
{
|
|
optionTexts[i].gameObject.SetActive(false);
|
|
}
|
|
return shownCount > 0;
|
|
}
|
|
|
|
private void HandleSelectionChanged(bool isOpen)
|
|
{
|
|
if (!isOpen && !panel.activeSelf)
|
|
{
|
|
TryOpenPendingSelection();
|
|
}
|
|
}
|
|
|
|
private void UpdateSelectionVisual()
|
|
{
|
|
for (int i = 0; i < (optionTexts?.Length ?? 0); i++)
|
|
{
|
|
bool selected = i == selectedIndex && i < shownCount;
|
|
optionTexts[i].color = selected
|
|
? new Color(1f, 0.85f, 0.2f)
|
|
: Color.white;
|
|
if (i < optionCardImages.Length)
|
|
{
|
|
PresentationUiStyle.ApplyCard(
|
|
optionCardImages[i],
|
|
selected);
|
|
optionCardImages[i].gameObject.SetActive(
|
|
optionTexts[i].gameObject.activeSelf);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ApplySelectionTextStyle()
|
|
{
|
|
Text[] texts = panel.GetComponentsInChildren<Text>(true);
|
|
foreach (Text text in texts)
|
|
{
|
|
PresentationUiStyle.ApplyText(text, Mathf.Max(1, text.fontSize));
|
|
if (text.name == "Title")
|
|
{
|
|
text.horizontalOverflow = HorizontalWrapMode.Overflow;
|
|
text.verticalOverflow = VerticalWrapMode.Truncate;
|
|
text.resizeTextForBestFit = true;
|
|
text.resizeTextMinSize = 24;
|
|
text.resizeTextMaxSize = 38;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void CreateCardBackdrops()
|
|
{
|
|
optionCardImages = new Image[optionTexts?.Length ?? 0];
|
|
for (int i = 0; i < optionCardImages.Length; i++)
|
|
{
|
|
Text optionText = optionTexts[i];
|
|
if (optionText == null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
optionCardImages[i] = PresentationUiStyle.CreateCardBackdrop(
|
|
optionText,
|
|
$"Option Card {i + 1}",
|
|
optionText.rectTransform.sizeDelta);
|
|
}
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
public bool DebugIsSelectionVisible => panel != null && panel.activeSelf;
|
|
|
|
public void Configure(
|
|
GameObject selectionPanel,
|
|
Text[] options,
|
|
ModifierDefinition[] definitions)
|
|
{
|
|
panel = selectionPanel;
|
|
optionTexts = options;
|
|
modifierCatalog = definitions;
|
|
}
|
|
|
|
public ModifierDefinition GetShownModifier(int index)
|
|
{
|
|
return index >= 0 && index < shownCount
|
|
? shownModifiers[index]
|
|
: null;
|
|
}
|
|
#endif
|
|
}
|
|
}
|