242 lines
10 KiB
C#
242 lines
10 KiB
C#
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();
|
||
}
|
||
}
|
||
}
|