150 lines
5.6 KiB
Python
150 lines
5.6 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
ONI Agent — Game State Analyzer
|
||
================================
|
||
Fetches comprehensive game state and produces actionable analysis across
|
||
6 dimensions: oxygen, food, power, temperature, water, research.
|
||
"""
|
||
|
||
import json, sys, io
|
||
# Fix GBK encoding
|
||
if sys.stdout.encoding and sys.stdout.encoding.upper() in ('GBK', 'GB2312', 'CP936'):
|
||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')
|
||
|
||
from oni_api import api_get
|
||
|
||
def get_data(endpoint):
|
||
r = api_get(endpoint)
|
||
if r.get("success"):
|
||
return r.get("data", r)
|
||
return None
|
||
|
||
def main():
|
||
game = get_data('/api/state/game')
|
||
resources = get_data('/api/state/resources') or []
|
||
buildings = get_data('/api/state/buildings') or []
|
||
dups = get_data('/api/state/duplicants') or []
|
||
alert_data = get_data('/api/state/alert') or []
|
||
research = get_data('/api/state/research') or {}
|
||
|
||
rdict = {}
|
||
if isinstance(resources, list):
|
||
for r in resources:
|
||
rdict[r.get('name', '')] = r.get('amountKg', 0)
|
||
|
||
# Building type counts
|
||
btypes = {}
|
||
for b in buildings if isinstance(buildings, list) else []:
|
||
bid = b.get('id', '')
|
||
btypes[bid] = btypes.get(bid, 0) + 1
|
||
|
||
print("=" * 56)
|
||
print(" ONI Agent — Game Analysis")
|
||
print("=" * 56)
|
||
if game:
|
||
speed_str = f"{game.get('gameSpeed','?')}x speed" if not game.get('isPaused') else "PAUSED"
|
||
print(f" Cycle {game.get('cycle','?')} | {game.get('duplicantCount','?')} dupes | "
|
||
f"{game.get('gridWidth','?')}x{game.get('gridHeight','?')} grid | {speed_str}")
|
||
print()
|
||
|
||
# 1. Oxygen
|
||
print("─── Oxygen ───")
|
||
o2 = rdict.get('Oxygen', 0)
|
||
algae = rdict.get('Algae', 0)
|
||
pw = rdict.get('PollutedWater', 0)
|
||
water = rdict.get('Water', 0)
|
||
has_elec = 'Electrolyzer' in btypes
|
||
has_diff = 'OxygenDiffuser' in btypes
|
||
|
||
print(f" O2: {o2:.0f} kg Algae: {algae:.0f} kg Water: {water:.0f} kg")
|
||
if o2 < 500:
|
||
print(f" ⚠ CRITICAL: Oxygen low! {o2:.0f} kg remaining")
|
||
if not has_elec and not has_diff:
|
||
print(f" ⚠ No oxygen production. Build OxygenDiffuser or plan SPOM")
|
||
elif not has_elec and algae < 1000:
|
||
print(f" ⚠ Algae running out ({algae:.0f} kg). Build Electrolyzer (SPOM)")
|
||
if water > 50000 and not has_elec:
|
||
print(f" ℹ Water abundant ({water:.0f} kg). Good time for SPOM")
|
||
if pw > 100000:
|
||
print(f" ℹ Polluted Water: {pw:.0f} kg — sieve into water or use for thimble reed")
|
||
|
||
# 2. Food
|
||
print(f"\n─── Food ───")
|
||
calories = rdict.get('Calories', 0)
|
||
dirt = rdict.get('Dirt', 0)
|
||
has_farm = any(bid in ('PlanterBox', 'FarmTile') for bid in btypes)
|
||
has_grill = 'ElectricGrill' in btypes
|
||
print(f" Calories: {calories:.0f} kcal Dirt: {dirt:.0f} kg")
|
||
if calories < 200000:
|
||
print(f" ⚠ CRITICAL: Food shortage! {calories:.0f} kcal")
|
||
elif calories < 500000:
|
||
print(f" ⚠ Food declining ({calories:.0f} kcal). Build farm")
|
||
if not has_farm:
|
||
print(f" ℹ No farm. Build 5x PlanterBox + plant Mealwood (uses Dirt)")
|
||
if not has_grill and has_farm:
|
||
print(f" ℹ No grill. Build ElectricGrill for better food quality")
|
||
|
||
# 3. Power
|
||
print(f"\n─── Power ───")
|
||
coal = rdict.get('Carbon', 0)
|
||
hydrogen = rdict.get('Hydrogen', 0)
|
||
has_manual = 'ManualGenerator' in btypes
|
||
has_coal = 'CoalGenerator' in btypes
|
||
has_hydro = 'HydrogenGenerator' in btypes
|
||
has_solar = 'SolarPanel' in btypes
|
||
has_natgas = 'NaturalGasGenerator' in btypes
|
||
print(f" Coal: {coal:.0f} kg Hydrogen: {hydrogen:.0f} kg")
|
||
gen_list = []
|
||
if has_manual: gen_list.append('Manual')
|
||
if has_coal: gen_list.append('Coal')
|
||
if has_hydro: gen_list.append('Hydrogen')
|
||
if has_natgas: gen_list.append('NaturalGas')
|
||
if has_solar: gen_list.append('Solar')
|
||
print(f" Generators: {', '.join(gen_list) if gen_list else 'None'}")
|
||
if coal < 1000 and has_coal:
|
||
print(f" ⚠ Coal low ({coal:.0f} kg). Diversify power production")
|
||
if not has_hydro and 'Electrolyzer' in btypes:
|
||
print(f" ℹ Have Electrolyzer but no HydrogenGenerator — wasting H2!")
|
||
if not any([has_manual, has_coal, has_hydro, has_natgas, has_solar]):
|
||
print(f" ⚠ No power generation! Build ManualGenerator or CoalGenerator")
|
||
|
||
# 4. Temperature
|
||
print(f"\n─── Temperature ───")
|
||
ice = rdict.get('Ice', 0) + rdict.get('CrushedIce', 0) + rdict.get('Snow', 0)
|
||
granite = rdict.get('Granite', 0)
|
||
igneous = rdict.get('IgneousRock', 0)
|
||
print(f" Ice/Snow: {ice:.0f} kg")
|
||
if ice > 0:
|
||
print(f" ℹ Ice available for cooling if melted")
|
||
|
||
# 5. Water
|
||
print(f"\n─── Water ───")
|
||
salt_water = rdict.get('SaltWater', 0)
|
||
brine = rdict.get('Brine', 0)
|
||
print(f" Water: {water:.0f} kg Polluted Water: {pw:.0f} kg Salt Water: {salt_water:.0f} kg")
|
||
if water < 10000 and pw < 10000:
|
||
print(f" ⚠ Low water! Collect from geysers or filter polluted water")
|
||
if water < 1000:
|
||
print(f" ⚠ CRITICAL: Water nearly empty!")
|
||
|
||
# 6. Research
|
||
print(f"\n─── Research ───")
|
||
completed = research.get('completedTechs', [])
|
||
print(f" Completed: {len(completed)} techs")
|
||
if completed:
|
||
print(f" Last: {completed[-1] if completed else 'none'}")
|
||
|
||
# 7. Alerts
|
||
if alert_data:
|
||
print(f"\n─── Active Alerts ───")
|
||
for a in alert_data:
|
||
print(f" [{a.get('severity','?')}] {a.get('title','?')}")
|
||
|
||
print()
|
||
print("=" * 56)
|
||
print(" Analysis complete.")
|
||
print("=" * 56)
|
||
|
||
if __name__ == "__main__":
|
||
main()
|