using System; using System.Collections.Generic; using System.Linq; namespace Ashfall.Core { [Serializable] public class ItemStack { public string id; public int amount; } [Serializable] public class Inventory { public List items = new List(); public int capacity = 10000; public int Count(string id) => items.Where(i => i.id == id).Sum(i => i.amount); public int Total => items.Sum(i => i.amount); public bool Has(string id, int n) => n > 0 && Count(id) >= n; public bool Add(string id, int n) { if (string.IsNullOrEmpty(id) || n <= 0 || (long)Total + n > capacity) return false; var stack = items.Find(i => i.id == id); if (stack == null) items.Add(new ItemStack { id = id, amount = n }); else stack.amount += n; return true; } public bool Take(string id, int n) { if (!Has(id, n)) return false; int remaining = n; foreach (var stack in items.Where(i => i.id == id)) { int take = Math.Min(stack.amount, remaining); stack.amount -= take; remaining -= take; } items.RemoveAll(i => i.amount == 0); return true; } public static bool Transfer(Inventory from, Inventory to, string id, int n) { if (from == null || to == null || ReferenceEquals(from, to) || n <= 0 || !from.Has(id, n) || (long)to.Total + n > to.capacity) return false; from.Take(id, n); to.Add(id, n); return true; } } [Serializable] public class Location { public string spaceId = "world"; public int floor; public V2 position; public float height; public Location Copy() => new Location { spaceId = spaceId, floor = floor, position = position, height = height }; public bool SameFloor(Location other) => other != null && spaceId == other.spaceId && floor == other.floor; } [Serializable] public class PlayerInput { public int sequence; public V2 move, aim; public bool fire, secondary, sprint, brake; } [Serializable] public class PlayerState { public string id, name; public string reconnectTokenHash = ""; public Species species; public BroodForm broodForm = BroodForm.Worm; public Location location = new Location(); public Inventory inventory = new Inventory { capacity = 600 }; public bool connected; public float health = 250, maxHealth = 250, energy = 100; public int humanLevel = 1, broodLevel = 1, experience; public string stationId = "", preferredStationId = "", transitionId = ""; public float transitionProgress, heading; public double portalReadyAt, shotReadyAt, abilityReadyAt, burrowUntil, wingUntil, buffUntil; public long lastCommand; public int acknowledgedInput; public PlayerInput input = new PlayerInput(); public double lastInputAt; public int kills; public int Level => species == Species.Human ? humanLevel : broodLevel; public bool IsWorm => species == Species.Brood && broodForm == BroodForm.Worm; } [Serializable] public class WallState { public string id; public Box2 bounds; public float height = 3; public bool open; } [Serializable] public class FloorState { public int index; public string name; public Box2 bounds; public List walls = new List(); public bool playerBuilt; } [Serializable] public class SpaceState { public string id, name, ownerId; public SpaceKind kind; public Family family; public V2 worldAnchor; public List floors = new List(); } [Serializable] public class PortalState { public string id, name, ownerId = ""; public Location from = new Location(), to = new Location(); public bool stairs, requiresResearch; public float seconds = .3f; } [Serializable] public class StationState { public string id, name, playerId = ""; public StationRole role; public Location location = new Location(); public int weaponGroup; } [Serializable] public class HardpointState { public string id, moduleId = ""; public int size = 1, group; public float arc = 360, arcCenter; public float aimHeading; public double readyAt; public float health = 100; } [Serializable] public class VehicleState { public string id, definitionId, name, spaceId; public Family family; public V2 position; public float heading, speed, maxSpeed = 9, length = 14, width = 8; public float hull = 1000, maxHull = 1000, engine = 100, power = 100; public float energy = 100, maxEnergy = 100, massLimit = 80, powerBudget = 20; public bool flying, cruise, doorOpen = true; public FlightMode flightMode; public string dockedTo = "", berthId = ""; public Inventory cargo = new Inventory { capacity = 4000 }; public List stations = new List(); public List hardpoints = new List(); public V2 DoorPosition => position + new V2(0, -length / 2 - .8f).Rotate(heading); public float Altitude => flightMode == FlightMode.Ground ? 0 : flightMode == FlightMode.Low ? 6 : 24; } [Serializable] public class ProductionJob { public string id, recipeId, outputId; public int outputAmount; public float remaining; } [Serializable] public class FacilityState { public string id, name, ownerId; public FacilityKind kind; public Family family; public Location location = new Location(); public bool powered = true; public int level = 1; public float health = 100; public List jobs = new List(); } [Serializable] public class BuildPiece { public string id, ownerId; public Location location = new Location(); public PieceKind kind; public int rotation; public Family family; } [Serializable] public class EnemyState { public string id; public Location location = new Location(); public float health = 100, maxHealth = 100; public bool boss; public double attackReadyAt; } [Serializable] public class ResourceState { public string id, itemId; public Location location = new Location(); public int amount; } [Serializable] public class ShotEvent { public int id; public string spaceId; public int floor; public V2 from, to; public float height; public Family family; public double expiresAt; } [Serializable] public class WorldState { public const int CurrentVersion = 1; public int version = CurrentVersion, seed = 7616, tick, nextId = 1; public double time; public bool bossDefeated; public Inventory warehouse = new Inventory { capacity = 20000 }; public List research = new List(); public List players = new List(); public List spaces = new List(); public List portals = new List(); public List vehicles = new List(); public List facilities = new List(); public List pieces = new List(); public List enemies = new List(); public List resources = new List(); public List shots = new List(); public string NewId(string prefix) => prefix + "-" + nextId++; public PlayerState Player(string id) => players.Find(p => p.id == id); public SpaceState Space(string id) => spaces.Find(s => s.id == id); public FloorState Floor(Location l) => Space(l.spaceId)?.floors.Find(f => f.index == l.floor); public VehicleState Vehicle(string id) => vehicles.Find(v => v.id == id); public VehicleState VehicleForSpace(string id) => vehicles.Find(v => v.spaceId == id); } [Serializable] public class GameCommand { public long sequence; public CommandKind kind; public string targetId = "", value = "", slot = ""; public V2 position; public int floor, rotation, amount = 1; public PieceKind piece; } }