A SpaceTraders Agent
at main 351 lines 8.8 kB view raw
1const std = @import("std"); 2const Allocator = std.mem.Allocator; 3const json = std.json; 4 5const prettym = @import("pretty"); 6 7const m = @import("../models.zig"); 8 9pub const Symbol = union(Symbol.Type) { 10 sector: u8, 11 system: Symbol.System, 12 waypoint: Symbol.Waypoint, 13 14 pub const Type = enum { sector, system, waypoint }; 15 16 pub const System = struct { 17 sector: u8, 18 symbol: []const u8, 19 20 pub fn format(this: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void { 21 try writer.print("X{}-{s}", .{ this.sector, this.symbol }); 22 } 23 }; 24 25 pub const Waypoint = struct { 26 system: Symbol.System, 27 symbol: []const u8, 28 29 pub fn format(this: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void { 30 try writer.print("{f}-{s}", .{ this.system, this.symbol }); 31 } 32 }; 33 34 pub fn parseSlice(slice: []const u8) !Symbol { 35 var tokens = std.mem.tokenizeScalar(u8, slice, '-'); 36 const sector_raw = tokens.next() orelse return error.InvalidSymbol; 37 38 std.debug.assert(sector_raw.len == 2); 39 std.debug.assert(sector_raw[0] == 'X'); 40 41 const sector = std.fmt.parseInt(u8, sector_raw[1..], 10) catch return error.InvalidSector; 42 const system_raw = tokens.next(); 43 44 if (system_raw) |system| { 45 const sys = Symbol.System{ .sector = sector, .symbol = system }; 46 if (tokens.next()) |waypoint| { 47 return Symbol{ .waypoint = .{ 48 .system = sys, 49 .symbol = waypoint, 50 } }; 51 } 52 return Symbol{ .system = sys }; 53 } else { 54 return Symbol{ .sector = sector }; 55 } 56 } 57 58 pub fn jsonParse( 59 allocator: Allocator, 60 source: anytype, 61 options: json.ParseOptions, 62 ) json.ParseError(@TypeOf(source.*))!Symbol { 63 const string = try json.innerParse([]const u8, allocator, source, options); 64 return parseSlice(string) catch return error.MissingField; 65 } 66 67 pub fn format(this: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void { 68 switch (this) { 69 .sector => |sector| { 70 try writer.print("X{}", .{sector}); 71 }, 72 inline else => |e| try writer.print("{f}", .{e}), 73 } 74 } 75 76 pub fn pretty( 77 this: *const @This(), 78 comptime ctx: prettym.Context, 79 run: *const prettym.Runtime, 80 ) error{WriteFailed}!void { 81 run.setColor(ctx, .value); 82 try run.print("{f}", .{this}); 83 run.resetColor(); 84 } 85}; 86 87pub const System = struct { 88 constellation: []const u8, 89 symbol: Symbol, 90 sectorSymbol: Symbol, 91 type: Type, 92 x: i64, 93 y: i64, 94 waypoints: []WaypointPreview, 95 factions: []Faction, 96 name: []const u8, 97 98 pub const Type = enum { 99 NEUTRON_STAR, 100 RED_STAR, 101 ORANGE_STAR, 102 BLUE_STAR, 103 YOUNG_STAR, 104 WHITE_DWARF, 105 BLACK_HOLE, 106 HYPERGIANT, 107 NEBULA, 108 UNSTABLE, 109 }; 110}; 111 112pub const Waypoint = struct { 113 symbol: Symbol, 114 systemSymbol: Symbol, 115 type: Type, 116 x: i64, 117 y: i64, 118 faction: Faction, 119 traits: []m.SymbolWrapper(Trait), 120 modifiers: []Modifier, 121 chart: Chart, 122 isUnderConstruction: bool, 123 124 orbitals: []m.SymbolWrapper([]const u8), 125 orbits: ?[]const u8 = null, 126 127 pub fn unwrapTraits(this: *const @This(), alloc: std.mem.Allocator) ![]Trait { 128 var buf = try alloc.alloc(Trait, this.traits.len); 129 for (this.traits, 0..) |trait, i| { 130 buf[i] = trait.symbol; 131 } 132 return buf; 133 } 134 135 pub const Type = enum { 136 PLANET, 137 GAS_GIANT, 138 MOON, 139 ORBITAL_STATION, 140 JUMP_GATE, 141 ASTEROID_FIELD, 142 ASTEROID, 143 ENGINEERED_ASTEROID, 144 ASTEROID_BASE, 145 NEBULA, 146 DEBRIS_FIELD, 147 GRAVITY_WELL, 148 ARTIFICIAL_GRAVITY_WELL, 149 FUEL_STATION, 150 }; 151 152 pub const Trait = enum { 153 UNCHARTED, 154 UNDER_CONSTRUCTION, 155 MARKETPLACE, 156 SHIPYARD, 157 OUTPOST, 158 SCATTERED_SETTLEMENTS, 159 SPRAWLING_CITIES, 160 MEGA_STRUCTURES, 161 PIRATE_BASE, 162 OVERCROWDED, 163 HIGH_TECH, 164 CORRUPT, 165 BUREAUCRATIC, 166 TRADING_HUB, 167 INDUSTRIAL, 168 BLACK_MARKET, 169 RESEARCH_FACILITY, 170 MILITARY_BASE, 171 SURVEILLANCE_OUTPOST, 172 EXPLORATION_OUTPOST, 173 MINERAL_DEPOSITS, 174 COMMON_METAL_DEPOSITS, 175 PRECIOUS_METAL_DEPOSITS, 176 RARE_METAL_DEPOSITS, 177 METHANE_POOLS, 178 ICE_CRYSTALS, 179 EXPLOSIVE_GASES, 180 STRONG_MAGNETOSPHERE, 181 VIBRANT_AURORAS, 182 SALT_FLATS, 183 CANYONS, 184 PERPETUAL_DAYLIGHT, 185 PERPETUAL_OVERCAST, 186 DRY_SEABEDS, 187 MAGMA_SEAS, 188 SUPERVOLCANOES, 189 ASH_CLOUDS, 190 VAST_RUINS, 191 MUTATED_FLORA, 192 TERRAFORMED, 193 EXTREME_TEMPERATURES, 194 EXTREME_PRESSURE, 195 DIVERSE_LIFE, 196 SCARCE_LIFE, 197 FOSSILS, 198 WEAK_GRAVITY, 199 STRONG_GRAVITY, 200 CRUSHING_GRAVITY, 201 TOXIC_ATMOSPHERE, 202 CORROSIVE_ATMOSPHERE, 203 BREATHABLE_ATMOSPHERE, 204 THIN_ATMOSPHERE, 205 JOVIAN, 206 ROCKY, 207 VOLCANIC, 208 FROZEN, 209 SWAMP, 210 BARREN, 211 TEMPERATE, 212 JUNGLE, 213 OCEAN, 214 RADIOACTIVE, 215 MICRO_GRAVITY_ANOMALIES, 216 DEBRIS_CLUSTER, 217 DEEP_CRATERS, 218 SHALLOW_CRATERS, 219 UNSTABLE_COMPOSITION, 220 HOLLOWED_INTERIOR, 221 STRIPPED, 222 }; 223 224 pub const Modifier = struct { 225 symbol: ModSymbol, 226 name: []const u8, 227 description: []const u8, 228 229 pub const ModSymbol = enum { 230 STRIPPED, 231 UNSTABLE, 232 RADIATION_LEAK, 233 CRITICAL_LIMIT, 234 CIVIL_UNREST, 235 }; 236 }; 237 238 pub const Chart = struct { 239 waypointSymbol: Symbol, 240 submittedBy: []const u8, 241 submittedOn: []const u8, 242 }; 243}; 244 245pub const WaypointPreview = struct { 246 symbol: Symbol, 247 type: Waypoint.Type, 248 x: i64, 249 y: i64, 250 orbitals: []m.SymbolWrapper(Symbol) = &.{}, 251 orbits: ?Symbol = null, 252 253 pub fn prettyInline( 254 this: *const @This(), 255 comptime ctx: prettym.Context, 256 run: *const prettym.Runtime, 257 ) error{WriteFailed}!void { 258 run.setColor(ctx, .value); 259 try run.print("{f}", .{this.symbol}); 260 run.setColor(ctx, .dim); 261 try run.print("[{s}]({}, {}) ", .{ @tagName(this.type), this.x, this.y }); 262 run.resetColor(); 263 } 264}; 265 266pub const ConstructionSite = struct { 267 symbol: Symbol, 268 isComplete: bool, 269 materials: []Material, 270 271 pub const Material = struct { 272 tradeSymbol: m.inventory.AllItems.Combined, 273 required: i64, 274 fulfilled: i64, 275 }; 276}; 277 278pub const Market = struct { 279 symbol: Symbol, 280 exports: []m.inventory.Item = &.{}, 281 imports: []m.inventory.Item = &.{}, 282 exchange: []m.inventory.Item = &.{}, 283 transactions: ?[]Transaction = null, 284 tradeGoods: ?[]TradeGood = null, 285 286 pub const Transaction = struct { 287 waypointSymbol: Symbol, 288 shipSymbol: []const u8, 289 tradeSymbol: []const u8, 290 type: Type, 291 units: u64, 292 pricePerUnit: u64, 293 totalPrice: u64, 294 timestamp: []const u8, 295 296 pub const Type = enum { PURCHASE, SELL }; 297 }; 298 299 pub const TradeGood = struct { 300 symbol: m.inventory.AllItems.Combined, 301 type: TradeGood.Type, 302 tradeVolume: u64, 303 supply: Supply, 304 activity: ?Activity = null, 305 purchasePrice: u64, 306 sellPrice: u64, 307 308 pub const Type = enum { EXPORT, IMPORT, EXCHANGE }; 309 }; 310 311 pub const Supply = enum { SCARCE, LIMITED, MODERATE, HIGH, ABUNDANT }; 312 pub const Activity = enum { WEAK, GROWING, STRONG, RESTRICTED }; 313}; 314 315pub const JumpGate = struct { 316 symbol: Symbol, 317 connections: []Symbol, 318}; 319 320pub const Shipyard = struct { 321 symbol: Symbol, 322 shipTypes: struct { type: m.ships.Type }, 323 transactions: []Transaction, 324 modificationsFee: i64, 325 326 pub const Transaction = struct { 327 waypointSymbol: Symbol, 328 shipType: m.ships.Type, 329 price: u64, 330 agentSymbol: []const u8, 331 timestamp: []const u8, 332 }; 333 334 pub const Ship = struct { 335 activity: Market.Activity, 336 supply: Market.Supply, 337 purchasePrice: u64, 338 339 type: m.ships.Type, 340 name: []const u8, 341 description: []const u8, 342 crew: m.ships.Crew, 343 frame: m.ships.Frame, 344 reactor: m.ships.Reactor, 345 engine: m.ships.Engine, 346 modules: []m.ships.Module, 347 mounts: []m.ships.Mount, 348 }; 349}; 350 351pub const Faction = m.SymbolWrapper(m.factions.Symbol);