from .base import Base from time import time, strftime from nullptr.util import * from nullptr.models import Waypoint import os class Ship(Base): def define(self): self.cargo:dict = {} self.mission_state:dict = {} self.status:str = '' self.cargo_capacity:int = 0 self.cargo_units:int = 0 self.location = None self.cooldown:int = 0 self.arrival:int = 0 self.fuel_current:int = 0 self.fuel_capacity:int = 0 self.mission:str = None self.mission_status:str = 'init' self.role = None self.crew = None self.frame = '' self.speed = "CRUISE" self._log_file = None self._log_level = 5 def log(self, m, l=3): if m is None: return if type(m) != str: m = pretty(m) if self._log_file is None: fn = os.path.join(self.store.data_dir, f'{self.symbol}.{self.ext()}.log') self._log_file = open(fn, 'a') ts = strftime('%Y%m%d %H%M%S') sts = strftime('%H%M%S') m = m.strip() self._log_file.write(f'{ts} {m}\n') self._log_file.flush() if l <= self._log_level: print(f'{self} {sts} {m}') @classmethod def ext(self): return 'shp' def range(self): if self.fuel_capacity == 0: return 100000 return self.fuel_capacity def update(self, d): self.seta('status', d, 'nav.status') self.seta('speed', d, "nav.flightMode") self.seta('frame', d, 'frame.name') getter = self.store.getter(Waypoint, create=True) self.seta('location', d, 'nav.waypointSymbol', interp=getter) self.seta('cargo_capacity', d, 'cargo.capacity') self.seta('cargo_units', d, 'cargo.units') self.seta('fuel_capacity', d, 'fuel.capacity') self.seta('fuel_current', d,'fuel.current') cargo = sg(d, 'cargo.inventory') if cargo is not None: self.load_cargo(cargo) self.seta('cooldown', d, 'cooldown.expiration', parse_timestamp) self.seta('arrival', d, 'nav.route.arrival', parse_timestamp) def tick(self): if self.status == 'IN_TRANSIT' and self.arrival < time(): self.status = 'IN_ORBIT' def is_cooldown(self): return self.cooldown > time() def is_travelling(self): return self.status == 'IN_TRANSIT' def set_mission_state(self, nm, val): self.mission_state[nm] = val self.store.dirty(self) def get_cargo(self, typ): if typ not in self.cargo: return 0 return self.cargo[typ] def take_cargo(self, typ, amt): if typ not in self.cargo: return if self.cargo[typ] <= amt: del self.cargo[typ] else: self.cargo[typ] -= amt self.cargo_units = sum(self.cargo.values()) def put_cargo(self, typ, amt): if typ not in self.cargo: self.cargo[typ] = amt else: self.cargo[typ] += amt self.cargo_units = sum(self.cargo.values()) def load_cargo(self, cargo): result = {} total = 0 for i in cargo: symbol = must_get(i, 'symbol') units = must_get(i, 'units') result[symbol] = units total += units self.cargo_units = total self.cargo = result def deliverable_cargo(self, contract): result = [] if contract is None: return result for d in contract.deliveries: if self.get_cargo(d['trade_symbol']) > 0: result.append(d['trade_symbol']) return result def nondeliverable_cargo(self, contract): cargo = self.cargo.keys() deliveries = [d['trade_symbol'] for d in contract.deliveries] garbage = [c for c in cargo if c not in deliveries] return garbage def cargo_space(self): return self.cargo_capacity - self.cargo_units def update_timers(self): if self.status == 'IN_TRANSIT' and self.arrival < time(): self.status = 'IN_ORBIT' def f(self, detail=1): self.update_timers() arrival = int(self.arrival - time()) cooldown = int(self.cooldown - time()) role = self.role if role is None: role = 'none' crew = 'none' if self.crew is not None: crew = self.crew.symbol mstatus = self.mission_status if mstatus == 'error': mstatus = mstatus.upper() if mstatus is None: mstatus = 'none' status = self.status.lower() if status.startswith('in_'): status = status[3:] if detail < 2: r = self.symbol elif detail == 2: symbol = self.symbol.split('-')[1] r = f'{symbol:<2} {role:7} {mstatus:8} {str(self.location):11}' if self.is_travelling(): r += f' [A: {arrival}]' if self.is_cooldown(): r += f' [C: {cooldown}]' else: r = f'== {self.symbol} {self.frame} ==\n' r += f'Role: {crew} / {role}\n' r += f'Mission: {self.mission} ({mstatus})\n' for k, v in self.mission_state.items(): if type(v) == list: v = f'[{len(v)} items]' r += f' {k}: {v}\n' adj = 'to' if self.status == 'IN_TRANSIT' else 'at' r += f'Status {self.status} {adj} {self.location}\n' r += f'Fuel: {self.fuel_current}/{self.fuel_capacity}\n' r += f'Speed: {self.speed}\n' r += f'Cargo: {self.cargo_units}/{self.cargo_capacity}\n' for res, u in self.cargo.items(): r += f' {res}: {u}\n' if self.is_travelling(): r += f'Arrival: {arrival} seconds\n' if self.is_cooldown(): r += f'Cooldown: {cooldown} seconds \n' return r