Calibrated from a controlled slider sweep across 5 real destinations, read from the live APEX Ship Flight Control DOM. Covers STL cruise, FTL jumps/charges, gateway hops (measured LOCK fees for ANT<->HRT/BEN), and per-planet landing fuel. Scoped to this account's one hull/reactor; open gaps (gravity dependence, hull generalization, gateway one-way links, per-gateway volume caps) are documented in the module docstring. tools/shiptrip.py is the simple entry point (ship + from + to, works out jumps/charges/landing itself); tools/shipcost.py takes explicit physics params for when the breakdown is already known. puga/route.py now also resolves CX station codes (ANT, HRT, ...), not just planets/systems - this was needed for the gateway-aware lookups to work at all. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
60 lines
3.9 KiB
Python
60 lines
3.9 KiB
Python
#!/usr/bin/env python3
|
|
"""Fuel/AIC cost for a ship trip FROM EXPLICIT PARAMETERS (jumps, sliders, gateways) - for when
|
|
you already know the trip's physics breakdown (e.g. from tools/route.py, or copying a known
|
|
route). If you just want "ship X from A to B, what's it cost", use tools/shiptrip.py instead -
|
|
it works all of this out for you. SCOPED TO the account's one hull/reactor (blueprint
|
|
BP-STRT-0000, stock reactor), shared by both ships (AVI-07JFB, AVI-07JFC). See puga/shipping.py's
|
|
module docstring for exactly what's confirmed vs still open (generalization to a different
|
|
hull/reactor is untested; gravity vs distance on landing fuel is confounded; v0's meaning is
|
|
relative to current fuel load, not an absolute unit).
|
|
|
|
tools/shipcost.py --v0 0.5 --v1 0.65 --jumps 1 --to ZV-759c # one direct jump to Deimos
|
|
tools/shipcost.py --v0 1.0 --jumps 2 --charges 1 --to ZV-194a # two-jump route to Nike
|
|
tools/shipcost.py --v0 1.0 --gateways 3 --lock-fee 6000:AIC --lock-fee 6000:AIC --lock-fee 4000:CIS # Benten-style - fees read off the live APEX LOCK segment, not formulaic/lookupable
|
|
"""
|
|
import argparse, sys
|
|
from pathlib import Path
|
|
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
|
from puga import config, market, shipping
|
|
|
|
|
|
def main():
|
|
ap = argparse.ArgumentParser()
|
|
ap.add_argument("--v0", type=float, default=1.0, help="fuel-usage slider, 0..1 (relative to current STL tank level, not absolute)")
|
|
ap.add_argument("--v1", type=float, default=1.0, help="reactor-usage slider, 0..1")
|
|
ap.add_argument("--jumps", type=int, default=0, help="number of direct FTL jumps (JMP segments)")
|
|
ap.add_argument("--charges", type=int, default=0, help="number of FTL recharges (CHRG) between consecutive jumps")
|
|
ap.add_argument("--cruise-legs", type=int, default=2, help="number of STL cruise legs (DEP+APP=2 for a simple direct route)")
|
|
ap.add_argument("--gateways", type=int, default=0, help="number of gateway hops (each: free GTW + a LOCK fee you supply)")
|
|
ap.add_argument("--lock-fee", action="append", default=[], help="AMOUNT:CURRENCY per gateway hop, repeatable, matched in order to --gateways - read the fee off the live APEX LOCK segment, there's no API/formula for it")
|
|
ap.add_argument("--to", help="destination planet natural id, for a looked-up (not predicted) landing fuel cost")
|
|
ap.add_argument("--cx", default=config.DEFAULT_CX)
|
|
a = ap.parse_args()
|
|
|
|
if a.gateways and len(a.lock_fee) != a.gateways:
|
|
print(f"warning: {a.gateways} gateways but {len(a.lock_fee)} --lock-fee given - fees you didn't supply are unknown, not zero", file=sys.stderr)
|
|
lock_fees = [(float(amt), cur) for amt, cur in (lf.split(":") for lf in a.lock_fee)]
|
|
|
|
result = shipping.trip_fuel(a.v0, a.v1, a.jumps, a.charges, a.cruise_legs, a.to, lock_fees)
|
|
if a.to and result["landing_fuel_included"] is None:
|
|
print(f"note: landing fuel for {a.to} hasn't been measured - not included in total, see puga/shipping.py LANDING_FUEL", file=sys.stderr)
|
|
|
|
snap = market.snapshot()
|
|
sf_px = (snap.get(("SF", a.cx)) or market.Quote("SF", a.cx)).ask or 0
|
|
ff_px = (snap.get(("FF", a.cx)) or market.Quote("FF", a.cx)).ask or 0
|
|
stl, ftl, fees = result["stl_fuel"], result["ftl_fuel"], result["lock_fees"]
|
|
|
|
lnd = result["landing_fuel_included"]
|
|
print(f"jumps {a.jumps} charges {a.charges} cruise legs {a.cruise_legs}" + (f" landing +{lnd:.0f} STL" if lnd else ""))
|
|
print(f"STL fuel: {stl:.1f} units -> {stl*sf_px:,.0f} AIC")
|
|
print(f"FTL fuel: {ftl:.1f} units -> {ftl*ff_px:,.0f} AIC")
|
|
if fees:
|
|
print("Gateway LOCK fees: " + ", ".join(f"{amt:,.0f} {cur}" for amt, cur in fees))
|
|
total_aic_fuel = stl * sf_px + ftl * ff_px
|
|
aic_fees = sum(amt for amt, cur in fees if cur == "AIC")
|
|
print(f"\nTotal (fuel, AIC-denominated fees only): {total_aic_fuel + aic_fees:,.0f} AIC" + (" + non-AIC fees above" if any(cur != "AIC" for _, cur in fees) else ""))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|