Updates to spells, HUD, Gold, and Camera Controls. New sound effects!
This commit is contained in:
parent
689fe7be88
commit
a33d951abd
27 changed files with 578 additions and 68 deletions
|
|
@ -116,13 +116,17 @@ namespace TD.UI
|
|||
private bool draftSubscribed;
|
||||
private PlayerDraft subscribedDraft;
|
||||
|
||||
// Spell hotbar (bottom-ui Section 6). Frame is display:none while the local player
|
||||
// Spell hotbar (bottom-ui Section 6). Frame is visibility:hidden (but still occupies
|
||||
// its reserved width, so the centered command bar never shifts) while the local player
|
||||
// has no granted spells; rebuilt on grant (append-only, so this is rare). Cooldown
|
||||
// state changes continuously and has no change event, so it's polled every Update.
|
||||
private VisualElement spellHotbarFrame;
|
||||
private VisualElement spellHotbar;
|
||||
private bool spellLoadoutSubscribed;
|
||||
private PlayerSpellLoadout subscribedSpellLoadout;
|
||||
// The loadout the hotbar is currently showing — the SELECTED builder's, or null when
|
||||
// no builder is selected (hotbar hidden). Cooldown polling reads this.
|
||||
private PlayerSpellLoadout displayedSpellLoadout;
|
||||
private readonly List<SpellSlotUi> spellSlotUis = new List<SpellSlotUi>();
|
||||
|
||||
private readonly struct SpellSlotUi
|
||||
|
|
@ -419,9 +423,10 @@ namespace TD.UI
|
|||
title.style.marginBottom = 6;
|
||||
card.Add(title);
|
||||
|
||||
if (option.Icon != null)
|
||||
var iconSprite = option.ResolveIcon();
|
||||
if (iconSprite != null)
|
||||
{
|
||||
var img = new Image { sprite = option.Icon };
|
||||
var img = new Image { sprite = iconSprite };
|
||||
img.style.width = 48;
|
||||
img.style.height = 48;
|
||||
img.style.marginBottom = 6;
|
||||
|
|
@ -475,23 +480,41 @@ namespace TD.UI
|
|||
|
||||
// ----- Spell hotbar -------------------------------------------------
|
||||
|
||||
// Rebuilds the hotbar cells from the local player's current loadout. Called on
|
||||
// OnLoadoutChanged (a new spell granted) — spells are append-only, so this is rare,
|
||||
// not a per-frame concern.
|
||||
// Rebuilds the hotbar cells for the SELECTED builder's loadout. Called on selection
|
||||
// change and on OnLoadoutChanged (a new spell granted). Spells are append-only, so
|
||||
// this is rare, not a per-frame concern.
|
||||
//
|
||||
// The hotbar follows selection: it shows the selected builder's spells and is removed
|
||||
// entirely when no builder is selected (spells belong to the builder). While a builder
|
||||
// IS selected, the frame keeps its reserved width (visibility toggle, not display) so
|
||||
// granting a spell mid-selection doesn't reflow/shift the centered command bar.
|
||||
private void RebuildSpellHotbar()
|
||||
{
|
||||
if (spellHotbar == null) return;
|
||||
spellHotbar.Clear();
|
||||
spellSlotUis.Clear();
|
||||
|
||||
var loadout = PlayerSpellLoadout.Local;
|
||||
int slotCount = loadout?.SlotCount ?? 0;
|
||||
var loadout = GetSelectedBuilderLoadout();
|
||||
displayedSpellLoadout = loadout;
|
||||
|
||||
if (spellHotbarFrame != null)
|
||||
spellHotbarFrame.style.display = slotCount > 0 ? DisplayStyle.Flex : DisplayStyle.None;
|
||||
{
|
||||
if (loadout == null)
|
||||
{
|
||||
// No builder selected → remove the slot (the command grid is hidden too).
|
||||
spellHotbarFrame.style.display = DisplayStyle.None;
|
||||
return;
|
||||
}
|
||||
// Builder selected → keep the reserved slot in layout; toggle only visibility so
|
||||
// a mid-selection spell grant doesn't jump the command bar.
|
||||
spellHotbarFrame.style.display = DisplayStyle.Flex;
|
||||
spellHotbarFrame.style.visibility =
|
||||
loadout.SlotCount > 0 ? Visibility.Visible : Visibility.Hidden;
|
||||
}
|
||||
|
||||
if (loadout == null) return;
|
||||
|
||||
int slotCount = loadout.SlotCount;
|
||||
var layout = SpellHotkeys.Layout;
|
||||
for (int i = 0; i < slotCount; i++)
|
||||
{
|
||||
|
|
@ -531,6 +554,17 @@ namespace TD.UI
|
|||
}
|
||||
}
|
||||
|
||||
// The loadout the spell hotbar should display: the currently-selected builder's
|
||||
// (resolved via its owner, so it shows whichever builder is selected — normally the
|
||||
// local player's), or null when the selection isn't a builder → hotbar hidden.
|
||||
private PlayerSpellLoadout GetSelectedBuilderLoadout()
|
||||
{
|
||||
var selected = SelectionState.Instance?.SelectedObject;
|
||||
if (selected is Builder builder)
|
||||
return PlayerSpellLoadout.GetForClient(builder.OwnerClientId);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Per-frame: dims each slot while on cooldown and shows the remaining whole seconds.
|
||||
// Cooldown has no change event (it advances continuously with server time), so this
|
||||
// has to be polled — cheap at hotbar scale (at most MaxSpellSlots cells).
|
||||
|
|
@ -538,7 +572,7 @@ namespace TD.UI
|
|||
{
|
||||
if (spellSlotUis.Count == 0) return;
|
||||
|
||||
var loadout = PlayerSpellLoadout.Local;
|
||||
var loadout = displayedSpellLoadout;
|
||||
if (loadout == null) return;
|
||||
|
||||
for (int i = 0; i < spellSlotUis.Count; i++)
|
||||
|
|
@ -1403,6 +1437,10 @@ namespace TD.UI
|
|||
// hides via PopulateGridForSelection when there are no actions.
|
||||
PopulateInfoPanel(selection);
|
||||
PopulateGridForSelection(selection);
|
||||
|
||||
// Section 6 (spell hotbar) follows selection: show the selected builder's spells,
|
||||
// hide entirely when the selection isn't a builder.
|
||||
RebuildSpellHotbar();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue