Files
unity/Assets/Game/Scripts/Equipment/InventoryGrid.cs

114 lines
4.8 KiB
C#

using System;
using System.Collections.Generic;
namespace Ironspore
{
public enum Hold { Cargo, SafeCase }
// Stable content IDs also resolve the existing four gameplay slot indices.
public static class InventoryGrid
{
public const int CargoSize = 4, CaseSize = 2, PodSize = 2;
static readonly string[][] Slots = {
new[] { "rapid", "coil", "siege" }, new[] { "guided", "pulse" },
new[] { "efficient", "vector" }, new[] { "composite_guard", "reactive_guard" }
};
public static string EquipmentId(int slot, int index) =>
slot >= 0 && slot < Slots.Length && index >= 0 && index < Slots[slot].Length ? Slots[slot][index] : null;
public static int Slot(string id) => Array.FindIndex(Slots, group => Array.IndexOf(group, id) >= 0);
public static int Index(int slot, string id) => Array.IndexOf(Slots[slot], id);
public static bool IsMaterial(string id) => id == "alloy" || id == "cells";
public static bool IsBlueprint(string id) => id != null && id.StartsWith("blueprint_", StringComparison.Ordinal) && id.Length > 10;
public static bool Known(string id) => IsMaterial(id) || IsBlueprint(id) || Slot(id) >= 0;
public static (string item, int alloy, int cells) Recipe(string blueprint)
{
switch (blueprint)
{
case "blueprint_coil_capacitor": return ("coil", 4, 2);
case "blueprint_boost_efficient": return ("vector", 3, 2);
case "blueprint_reactive_guard": return ("reactive_guard", 4, 1);
default: return (null, 0, 0);
}
}
public static void Size(string id, bool rotated, out int width, out int height)
{
width = 1;
height = 1;
switch (id)
{
case "rapid": height = 3; break;
case "coil": width = 2; height = 3; break;
case "siege": width = 2; height = 4; break;
case "pulse": case "reactive_guard": case "vector": width = 2; height = 2; break;
case "guided": case "efficient": case "composite_guard": height = 2; break;
}
if (rotated) (width, height) = (height, width);
}
public static int Area(CargoStack item)
{
Size(item.itemId, false, out int w, out int h);
return w * h;
}
public static bool Fits(List<CargoStack> items, int size, CargoStack item, int x, int y, bool rotated)
{
Size(item.itemId, rotated, out int w, out int h);
if (x < 0 || y < 0 || x > size - w || y > size - h) return false;
foreach (var other in items)
{
if (other == null) return false;
if (ReferenceEquals(item, other)) continue;
Size(other.itemId, other.rotated, out int ow, out int oh);
if (x < other.x + ow && x + w > other.x && y < other.y + oh && y + h > other.y)
return false;
}
return true;
}
public static bool Place(List<CargoStack> items, int size, CargoStack item, int x, int y, bool rotated)
{
if (items.Contains(item) || !Fits(items, size, item, x, y, rotated)) return false;
item.x = x;
item.y = y;
item.rotated = rotated;
items.Add(item);
return true;
}
public static bool AutoPlace(List<CargoStack> items, int size, CargoStack item)
{
for (int turn = 0; turn < 2; turn++)
for (int y = 0; y < size; y++)
for (int x = 0; x < size; x++)
if (Place(items, size, item, x, y, turn == 1)) return true;
return false;
}
// The pod is small. Try alternate placements so a greedy choice cannot reject a valid manifest.
public static bool PodFits(List<CargoStack> selection)
{
if (selection.Count == 0 || selection.Count > PodSize * PodSize) return false;
return Pack(0, new List<CargoStack>());
bool Pack(int index, List<CargoStack> placed)
{
if (index == selection.Count) return true;
var next = new CargoStack(selection[index].itemId, selection[index].count) { uid = selection[index].uid };
for (int turn = 0; turn < 2; turn++)
for (int y = 0; y < PodSize; y++)
for (int x = 0; x < PodSize; x++)
{
if (!Place(placed, PodSize, next, x, y, turn == 1)) continue;
if (Pack(index + 1, placed)) return true;
placed.RemoveAt(placed.Count - 1);
}
return false;
}
}
}
}