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<ItemStack> items = new List<ItemStack>();
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<WallState> walls = new List<WallState>();
public bool playerBuilt;
}
[Serializable]
public class SpaceState
{
public string id, name, ownerId;
public SpaceKind kind;
public Family family;
public V2 worldAnchor;
public List<FloorState> floors = new List<FloorState>();
}
[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<StationState> stations = new List<StationState>();
public List<HardpointState> hardpoints = new List<HardpointState>();
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<ProductionJob> jobs = new List<ProductionJob>();
}
[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<string> research = new List<string>();
public List<PlayerState> players = new List<PlayerState>();
public List<SpaceState> spaces = new List<SpaceState>();
public List<PortalState> portals = new List<PortalState>();
public List<VehicleState> vehicles = new List<VehicleState>();
public List<FacilityState> facilities = new List<FacilityState>();
public List<BuildPiece> pieces = new List<BuildPiece>();
public List<EnemyState> enemies = new List<EnemyState>();
public List<ResourceState> resources = new List<ResourceState>();
public List<ShotEvent> shots = new List<ShotEvent>();
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;
}
}
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<ItemStack> items = new List<ItemStack>();
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<WallState> walls = new List<WallState>();
public bool playerBuilt;
}
[Serializable]
public class SpaceState
{
public string id, name, ownerId;
public SpaceKind kind;
public Family family;
public V2 worldAnchor;
public List<FloorState> floors = new List<FloorState>();
}
[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<StationState> stations = new List<StationState>();
public List<HardpointState> hardpoints = new List<HardpointState>();
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<ProductionJob> jobs = new List<ProductionJob>();
}
[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<string> research = new List<string>();
public List<PlayerState> players = new List<PlayerState>();
public List<SpaceState> spaces = new List<SpaceState>();
public List<PortalState> portals = new List<PortalState>();
public List<VehicleState> vehicles = new List<VehicleState>();
public List<FacilityState> facilities = new List<FacilityState>();
public List<BuildPiece> pieces = new List<BuildPiece>();
public List<EnemyState> enemies = new List<EnemyState>();
public List<ResourceState> resources = new List<ResourceState>();
public List<ShotEvent> shots = new List<ShotEvent>();
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;
}
}