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

242 lines
10 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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();
}
}
}