#!/usr/bin/env python3 """ ONI Agent — Blueprint Builder ============================== Pre-built building modules for one-click deployment. Usage: python oni_builder.py list List all blueprints python oni_builder.py show Show blueprint details python oni_builder.py build Build blueprint at anchor point """ import json, sys from oni_api import api_post, api_get BLUEPRINTS = { 'spom': { 'name': 'SPOM (Self-Powered Oxygen Module)', 'desc': 'Standard Rodriguez SPOM: electrolyzer + H2 generators + gas pumps', 'size': {'w': 8, 'h': 6}, 'dig': {'dx': -1, 'dy': -1, 'w': 10, 'h': 8}, 'steps': [ {'type': 'build', 'id': 'Electrolyzer', 'x': 3, 'y': 2}, {'type': 'build', 'id': 'GasPump', 'x': 1, 'y': 2}, {'type': 'build', 'id': 'GasPump', 'x': 5, 'y': 2}, {'type': 'build', 'id': 'HydrogenGenerator', 'x': 1, 'y': 0}, {'type': 'build', 'id': 'HydrogenGenerator', 'x': 4, 'y': 0}, ], }, 'spom_mini': { 'name': 'Mini SPOM', 'desc': 'Compact electrolyzer + 1 hydrogen generator for early game', 'size': {'w': 5, 'h': 4}, 'dig': {'dx': -1, 'dy': -1, 'w': 7, 'h': 6}, 'steps': [ {'type': 'build', 'id': 'Electrolyzer', 'x': 2, 'y': 1}, {'type': 'build', 'id': 'GasPump', 'x': 1, 'y': 1}, {'type': 'build', 'id': 'HydrogenGenerator', 'x': 2, 'y': 0}, ], }, 'toilet_loop': { 'name': 'Bathroom Water Loop', 'desc': '2 Lavatories -> Water Purifier closed loop', 'size': {'w': 8, 'h': 4}, 'dig': {'dx': -1, 'dy': -1, 'w': 10, 'h': 6}, 'steps': [ {'type': 'build', 'id': 'Lavatory', 'x': 1, 'y': 1}, {'type': 'build', 'id': 'Lavatory', 'x': 3, 'y': 1}, {'type': 'build', 'id': 'WaterPurifier', 'x': 6, 'y': 1}, ], }, 'farm_mealwood': { 'name': 'Mealwood Farm', 'desc': '5 PlanterBox + 1 StorageLocker', 'size': {'w': 6, 'h': 4}, 'dig': {'dx': -1, 'dy': -1, 'w': 8, 'h': 6}, 'steps': [ {'type': 'build', 'id': 'PlanterBox', 'x': 1, 'y': 1}, {'type': 'build', 'id': 'PlanterBox', 'x': 3, 'y': 1}, {'type': 'build', 'id': 'PlanterBox', 'x': 5, 'y': 1}, {'type': 'build', 'id': 'PlanterBox', 'x': 1, 'y': 3}, {'type': 'build', 'id': 'PlanterBox', 'x': 3, 'y': 3}, {'type': 'build', 'id': 'StorageLocker', 'x': 5, 'y': 3}, ], }, 'bedroom': { 'name': 'Standard Bedroom', 'desc': '4 Cots + decor for bedroom room bonus', 'size': {'w': 8, 'h': 4}, 'dig': {'dx': -1, 'dy': -1, 'w': 10, 'h': 6}, 'steps': [ {'type': 'build', 'id': 'Cot', 'x': 1, 'y': 1}, {'type': 'build', 'id': 'Cot', 'x': 3, 'y': 1}, {'type': 'build', 'id': 'Cot', 'x': 5, 'y': 1}, {'type': 'build', 'id': 'Cot', 'x': 7, 'y': 1}, ], }, 'cooling': { 'name': 'Steam Turbine Cooler', 'desc': 'Aquatuner + Steam Turbine cooling loop', 'size': {'w': 8, 'h': 6}, 'dig': {'dx': -1, 'dy': -1, 'w': 10, 'h': 8}, 'steps': [ {'type': 'build', 'id': 'SteamTurbine', 'x': 1, 'y': 4}, {'type': 'build', 'id': 'SteamTurbine', 'x': 5, 'y': 4}, {'type': 'build', 'id': 'Aquatuner', 'x': 2, 'y': 1}, ], }, 'ranch_hatch': { 'name': 'Hatch Ranch', 'desc': 'RanchStation + Incubator + StorageLocker', 'size': {'w': 10, 'h': 6}, 'dig': {'dx': -1, 'dy': -1, 'w': 12, 'h': 8}, 'steps': [ {'type': 'build', 'id': 'RanchStation', 'x': 1, 'y': 1}, {'type': 'build', 'id': 'Incubator', 'x': 4, 'y': 1}, {'type': 'build', 'id': 'StorageLocker', 'x': 8, 'y': 1}, ], }, } def cmd_list(args): print(f"Available blueprints ({len(BLUEPRINTS)}):") for name, bp in sorted(BLUEPRINTS.items()): print(f" {name:15s} {bp['name']}") print(f" {'':15s} {bp['desc']}") print(f" {'':15s} Size: {bp['size']['w']}x{bp['size']['h']} | {len(bp['steps'])} buildings") print() def cmd_show(args): if not args: print("Usage: show ", file=sys.stderr) return name = args[0] if name not in BLUEPRINTS: print(f"Unknown blueprint: {name}", file=sys.stderr) return bp = BLUEPRINTS[name] print(f"Blueprint: {bp['name']}") print(f" {bp['desc']}") print(f" Size: {bp['size']['w']}x{bp['size']['h']}") if bp.get('dig'): d = bp['dig'] print(f" Dig area: offset ({d['dx']},{d['dy']}) {d['w']}x{d['h']}") print(f" Buildings ({len(bp['steps'])}):") for s in bp['steps']: print(f" {s['id']:25s} at anchor+({s['x']},{s['y']})") def cmd_build(args): if len(args) < 3: print("Usage: build ", file=sys.stderr) return name, ax, ay = args[0], int(args[1]), int(args[2]) if name not in BLUEPRINTS: print(f"Unknown blueprint: {name}", file=sys.stderr) return bp = BLUEPRINTS[name] # 1. Dig the area first if bp.get('dig'): d = bp['dig'] dx, dy = ax + d['dx'], ay + d['dy'] print(f"Digging area: ({dx},{dy}) {d['w']}x{d['h']}...") r = api_post('/api/action/dig', {"x": dx, "y": dy, "width": d['w'], "height": d['h']}) if r.get("success"): info = r.get("data", {}) print(f" Queued {info.get('count', '?')} dig orders") else: print(f" Dig warning: {r.get('errorMessage', r.get('error', 'unknown'))}") # 2. Build each structure results = [] for step in bp['steps']: bx, by = ax + step['x'], ay + step['y'] print(f"Building {step['id']} at ({bx},{by})...") r = api_post('/api/action/build', {"buildingId": step['id'], "x": bx, "y": by}) if r.get("success"): info = r.get("data", {}) has_mat = info.get('hasAllMaterials', False) results.append(f" ✓ {step['id']} at ({bx},{by}) {'(may wait for materials)' if not has_mat else ''}") else: results.append(f" ✗ {step['id']} at ({bx},{by}): {r.get('errorMessage', r.get('error', 'unknown'))}") print(f"\n--- {bp['name']} build results ---") for r in results: print(r) def main(): if len(sys.argv) < 2 or sys.argv[1] in ("-h", "--help", "help"): print(__doc__) return cmd = sys.argv[1] args = sys.argv[2:] if cmd == "list": cmd_list(args) elif cmd == "show": cmd_show(args) elif cmd == "build": cmd_build(args) else: print(f"Unknown: {cmd}", file=sys.stderr) sys.exit(1) if __name__ == "__main__": main()