Files
unity/Assets/Game/Scripts/UI/GameHudInventory.cs
T

242 lines
10 KiB
C#
Raw Normal View History

using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UIElements;
namespace Ironspore
{
public sealed partial class GameHud
{
string selectedUid;
Hold selectedHold;
int selectedSlot = -1;
bool rotated;
int quantity;
const int CellWidth = 103, CellHeight = 55;
sealed class GridCell
{
public Hold hold;
public int x, y;
public CargoStack occupant;
}
CargoStack dragItem;
Hold dragHold;
int dragSlot, dragPointer;
Vector2 dragStart;
VisualElement dragPreview;
CargoStack Selection => selectedSlot >= 0 ? game.Run.installed.Find(i => i.uid == selectedUid) :
Contents(selectedHold).Find(i => i.uid == selectedUid);
List<CargoStack> Contents(Hold hold) => hold == Hold.Cargo ? game.Run.cargo : game.Run.safeCase;
void SelectInventoryItem(CargoStack item, Hold hold, int slot = -1)
{
selectedUid = item?.uid;
selectedSlot = slot;
selectedHold = hold;
rotated = item?.rotated ?? false;
quantity = item?.count ?? 0;
ShowCargo();
}
void RotateSelection()
{
rotated = !rotated;
if (dragPreview == null) ShowCargo();
else SizePreview();
}
public void ShowCargo()
{
var panel = Overlay(L("ui.cargo.title"), L(game.Run.podUsed ? "ui.cargo.used" : "ui.cargo.help"));
view = View.Cargo;
var installed = Element(panel, "row");
foreach (var part in game.Run.installed)
{
int slot = InventoryGrid.Slot(part.itemId);
var button = Button(installed, part.Name, () => SelectInventoryItem(part, Hold.Cargo, slot),
part.uid == selectedUid ? "loadout selected" : "loadout");
EnableDrag(button, part, Hold.Cargo, slot);
}
var grids = Element(panel, "row");
DrawHold(grids, Hold.Cargo, InventoryGrid.CargoSize);
DrawHold(grids, Hold.SafeCase, InventoryGrid.CaseSize);
Text(panel, L("ui.cargo.capacity", game.Run.cargo.Sum(InventoryGrid.Area),
game.Run.cargo.Where(i => game.SelectedCargo.Contains(i.uid)).Sum(InventoryGrid.Area)), "budget");
var item = Selection;
if (item != null)
{
InventoryGrid.Size(item.itemId, rotated, out int w, out int h);
Text(panel, L("ui.cargo.selection", item.Name, w, h, quantity), "body");
var actions = Element(panel, "row");
Button(actions, L("ui.cargo.rotate"), RotateSelection);
if (item.count > 1)
{
Button(actions, "−", () => { quantity--; ShowCargo(); }).SetEnabled(quantity > 1);
Button(actions, "+", () => { quantity++; ShowCargo(); }).SetEnabled(quantity < item.count);
}
if (selectedSlot < 0)
{
if (selectedHold == Hold.Cargo && !game.Run.podUsed)
Button(actions, L(game.SelectedCargo.Contains(item.uid) ? "ui.cargo.unmark" : "ui.cargo.mark"), () => game.ToggleCargo(item.uid));
if (InventoryGrid.Slot(item.itemId) >= 0)
Button(actions, L("ui.cargo.install"), () =>
{
if (game.InstallItem(item, selectedHold)) selectedUid = null;
ShowCargo();
});
}
Button(actions, L("ui.cargo.cancel"), () => SelectInventoryItem(null, Hold.Cargo));
}
Text(panel, game.Notice, "warning");
Button(panel, L("ui.return"), game.CloseMenu, "primary");
}
void DrawHold(VisualElement parent, Hold hold, int size)
{
var column = Element(parent, "inventory-column");
Text(column, L(hold == Hold.Cargo ? "ui.cargo.hold" : "ui.cargo.case"), "section");
var grid = new VisualElement();
column.Add(grid);
grid.style.width = size * CellWidth;
grid.style.height = size * CellHeight;
var items = Contents(hold);
for (int y = 0; y < size; y++)
for (int x = 0; x < size; x++)
{
int cx = x, cy = y;
var occupant = items.Find(i =>
{
InventoryGrid.Size(i.itemId, i.rotated, out int w, out int h);
return cx >= i.x && cy >= i.y && cx < i.x + w && cy < i.y + h;
});
var cell = Button(grid, "", () => InventoryClick(hold, cx, cy, occupant), "inventory-cell");
cell.name = hold + "-" + x + "-" + y;
cell.tooltip = occupant?.Name ?? "";
cell.userData = new GridCell { hold = hold, x = x, y = y, occupant = occupant };
if (occupant != null) EnableDrag(cell, occupant, hold, -1);
PositionInGrid(cell, x, y, 1, 1);
}
foreach (var item in items)
{
InventoryGrid.Size(item.itemId, item.rotated, out int w, out int h);
string prefix = game.SelectedCargo.Contains(item.uid) ? "✓ " : "";
var label = Text(grid, prefix + item.Name + (item.count > 1 ? " ×" + item.count : ""), "inventory-item");
label.pickingMode = PickingMode.Ignore;
if (item.uid == selectedUid) label.AddToClassList("selected");
PositionInGrid(label, item.x, item.y, w, h);
}
}
void EnableDrag(Button button, CargoStack item, Hold hold, int slot)
{
// Captured pointer events can be dispatched directly to the pressed button.
button.RegisterCallback<PointerMoveEvent>(DragMove, TrickleDown.TrickleDown);
button.RegisterCallback<PointerUpEvent>(DragEnd, TrickleDown.TrickleDown);
button.RegisterCallback<PointerDownEvent>(evt =>
{
if (evt.button != 0) return;
dragItem = item;
dragHold = hold;
dragSlot = slot;
dragStart = evt.position;
dragPointer = evt.pointerId;
}, TrickleDown.TrickleDown);
}
void DragMove(PointerMoveEvent evt)
{
if (dragItem == null || evt.pointerId != dragPointer) return;
Vector2 pos = evt.position;
if (dragPreview == null)
{
if ((pos - dragStart).sqrMagnitude < 36) return;
if (selectedUid != dragItem.uid)
{
quantity = dragItem.count;
rotated = dragItem.rotated;
}
selectedUid = dragItem.uid;
selectedSlot = dragSlot;
selectedHold = dragHold;
dragPreview = Text(root, dragItem.Name, "inventory-item selected");
dragPreview.pickingMode = PickingMode.Ignore;
dragPreview.style.position = UnityEngine.UIElements.Position.Absolute;
SizePreview();
}
var target = root.panel.Pick(pos);
Vector2 anchor = target?.userData is GridCell ? target.worldBound.min : pos;
Vector2 local = root.WorldToLocal(anchor);
dragPreview.style.left = local.x;
dragPreview.style.top = local.y;
}
void SizePreview()
{
InventoryGrid.Size(dragItem.itemId, rotated, out int w, out int h);
dragPreview.style.width = CellWidth * w - 2;
dragPreview.style.height = CellHeight * h - 2;
}
void DragEnd(PointerUpEvent evt)
{
if (dragItem == null || evt.pointerId != dragPointer) return;
bool dragged = dragPreview != null;
ResetDrag();
if (!dragged) return;
evt.StopImmediatePropagation();
var owner = root.panel.GetCapturingElement(evt.pointerId) as VisualElement;
owner?.ReleasePointer(evt.pointerId);
var target = root.panel.Pick(evt.position)?.userData as GridCell;
if (target != null) InventoryClick(target.hold, target.x, target.y, target.occupant);
else ShowCargo();
}
void ResetDrag()
{
dragPreview?.RemoveFromHierarchy();
dragPreview = null;
dragItem = null;
}
static void PositionInGrid(VisualElement element, int x, int y, int w, int h)
{
element.style.position = UnityEngine.UIElements.Position.Absolute;
element.style.left = x * CellWidth;
element.style.top = y * CellHeight;
element.style.width = w * CellWidth - 2;
element.style.height = h * CellHeight - 2;
}
void InventoryClick(Hold hold, int x, int y, CargoStack occupant)
{
var item = Selection;
if (item == null)
{
SelectInventoryItem(occupant, hold);
return;
}
bool ok;
if (selectedSlot >= 0)
ok = game.Store.Uninstall(selectedSlot, hold, x, y, rotated);
else if (occupant == null || item.uid == occupant.uid)
ok = game.Store.MoveItem(item.uid, selectedHold, hold, x, y, rotated, quantity);
else if (item.itemId == occupant.itemId && InventoryGrid.IsMaterial(item.itemId))
ok = game.Store.MergeMaterial(item.uid, selectedHold, occupant.uid, hold, quantity);
else
ok = quantity == item.count && game.Store.SwapItems(item.uid, selectedHold, occupant.uid, hold, rotated);
if (ok)
{
selectedUid = null;
game.SelectedCargo.RemoveAll(uid => !game.Run.cargo.Exists(i => i.uid == uid));
game.Pilot.ApplyLoadout();
}
else game.Notify(string.IsNullOrEmpty(game.Store.Error) ? "notice.placement" : "notice.saveFailed");
ShowCargo();
}
}
}