28 Commits

Author SHA1 Message Date
Richard Bronkhorst
9d124179bf Update base.py 2023-06-26 20:50:29 +02:00
Richard Bronkhorst
9b9a149e3f Update base.py 2023-06-26 20:19:13 +02:00
Richard Bronkhorst
9e6583ac24 Update haul.py 2023-06-26 14:55:25 +02:00
Richard Bronkhorst
6c98eec738 Update commander.py 2023-06-26 13:40:11 +02:00
Richard Bronkhorst
11031599cf Update base.py 2023-06-26 05:48:19 +02:00
Richard Bronkhorst
7eea63ac82 Update mine.py 2023-06-25 22:39:33 +02:00
Richard Bronkhorst
dc862088cd Update mine.py 2023-06-25 22:37:33 +02:00
Richard Bronkhorst
35bc586b72 Update api.py 2023-06-25 20:21:49 +02:00
Richard Bronkhorst
2a5680c16d Update api.py 2023-06-25 19:32:35 +02:00
Richard Bronkhorst
4d51ad53c0 Update analyzer.py, central_command.py and five other files 2023-06-25 17:35:06 +02:00
Richard Bronkhorst
5fbce54285 Update analyzer.py and commander.py 2023-06-23 13:49:09 +02:00
Richard Bronkhorst
27bd054e8b Update analyzer.py and commander.py 2023-06-23 13:32:08 +02:00
Richard Bronkhorst
38a2ee7870 Update central_command.py, command_line.py and seven other files 2023-06-22 19:57:07 +02:00
Richard Bronkhorst
7c3eaa825f Update commander.py and mission.py 2023-06-22 14:56:51 +02:00
Richard Bronkhorst
ddd693a66e Update commander.py 2023-06-22 09:22:34 +02:00
Richard Bronkhorst
b43568f476 Update commander.py 2023-06-22 08:49:43 +02:00
Richard Bronkhorst
ff4643d7ac Update commander.py 2023-06-22 08:46:47 +02:00
Richard Bronkhorst
0e3f939b9a Update commander.py 2023-06-22 07:34:45 +02:00
Richard Bronkhorst
2d792dffae Update mission.py 2023-06-21 09:54:07 +02:00
Richard Bronkhorst
4043c5585e Update commander.py 2023-06-21 09:37:14 +02:00
Richard Bronkhorst
b19e3ed2b2 Update analyzer.py and commander.py 2023-06-21 09:32:31 +02:00
Richard Bronkhorst
b7d3347fac Update commander.py 2023-06-20 23:14:17 +02:00
Richard Bronkhorst
42e370fde5 Update commander.py and mission.py 2023-06-20 23:12:57 +02:00
Richard Bronkhorst
b202b80541 Update mission.py 2023-06-20 22:38:29 +02:00
Richard Bronkhorst
b023718450 Update mission.py 2023-06-20 22:30:21 +02:00
Richard Bronkhorst
fbda97df61 Update analyzer.py 2023-06-20 22:18:20 +02:00
Richard Bronkhorst
707f142e7a Update analyzer.py, api.py and four other files 2023-06-20 21:46:05 +02:00
Richard Bronkhorst
35ea9e2e04 Update commander.py 2023-06-19 10:36:30 +02:00
14 changed files with 430 additions and 165 deletions

View File

@@ -1,6 +1,7 @@
from nullptr.models.marketplace import Marketplace from nullptr.models.marketplace import Marketplace
from nullptr.models.jumpgate import Jumpgate from nullptr.models.jumpgate import Jumpgate
from nullptr.models.system import System from nullptr.models.system import System
from nullptr.models.waypoint import Waypoint
from dataclasses import dataclass from dataclasses import dataclass
@dataclass @dataclass
@@ -29,15 +30,43 @@ class Analyzer:
def find_markets(self, resource, sellbuy): def find_markets(self, resource, sellbuy):
for m in self.store.all(Marketplace): for m in self.store.all(Marketplace):
resources = m.imports if sellbuy == 'sell' else m.exports if 'sell' in sellbuy and resource in m.imports:
if resource in resources: yield ('sell', m)
yield m
elif 'buy' in sellbuy and resource in m.exports:
yield ('buy', m)
elif 'exchange' in sellbuy and resource in m.exchange:
yield ('exchange', m)
def find_closest_markets(self, resource, sellbuy, location):
if type(location) == str:
location = self.store.get(Waypoint, location)
mkts = self.find_markets(resource, sellbuy)
candidates = []
origin = self.store.get(System, location.system())
for typ, m in mkts:
system = self.store.get(System, m.system())
d = origin.distance(system)
candidates.append((typ, m, d))
possibles = sorted(candidates, key=lambda m: m[2])
possibles = possibles[:10]
results = []
for typ,m,d in possibles:
system = self.store.get(System, m.system())
p = self.find_path(origin, system)
if p is None: continue
results.append((typ,m,d,len(p)))
return results
def solve_tsp(self, waypoints):
# todo actually try to solve it
return waypoints
def get_jumpgate(self, system): def get_jumpgate(self, system):
gates = self.store.all_members(system, Jumpgate) gates = self.store.all_members(system, Jumpgate)
return next(gates, None) return next(gates, None)
def find_path(self, orig, to, depth=100, seen=None): def find_path(self, orig, to, depth=100, seen=None):
if depth < 1: return None if depth < 1: return None
if seen is None: if seen is None:

View File

@@ -31,7 +31,7 @@ class Api:
def request(self, method, path, data=None, need_token=True, params={}): def request(self, method, path, data=None, need_token=True, params={}):
try: try:
return self.request_once(method, path, data, need_token, params) return self.request_once(method, path, data, need_token, params)
except ApiLimitError: except (ApiLimitError, requests.exceptions.Timeout):
print('oops, hit the limit. take a break') print('oops, hit the limit. take a break')
sleep(10) sleep(10)
return self.request_once(method, path, data, need_token, params) return self.request_once(method, path, data, need_token, params)
@@ -221,8 +221,10 @@ class Api:
return ship return ship
def jump(self, ship, system): def jump(self, ship, system):
if type(system) == System:
system = system.symbol
data = { data = {
"systemSymbol": system.symbol "systemSymbol": system
} }
data = self.request('post', f'my/ships/{ship}/jump', data) data = self.request('post', f'my/ships/{ship}/jump', data)
if 'nav' in data: if 'nav' in data:

View File

@@ -1,10 +1,13 @@
from nullptr.store import Store from nullptr.store import Store
from nullptr.models.ship import Ship from nullptr.models.ship import Ship
from nullptr.mission import * from nullptr.missions import create_mission, get_mission_class
from random import choice from random import choice
from time import sleep from time import sleep
from threading import Thread from threading import Thread
class CentralCommandError(Exception):
pass
class CentralCommand: class CentralCommand:
def __init__(self, store, api): def __init__(self, store, api):
self.missions = {} self.missions = {}
@@ -86,6 +89,21 @@ class CentralCommand:
m = self.missions[s] m = self.missions[s]
m.next_step = max(s.cooldown, s.arrival) m.next_step = max(s.cooldown, s.arrival)
def init_mission(self, s, mtyp):
if mtyp == 'none':
s.mission_state = {}
s.mission_status = None
s.mission = None
return
try:
mclass = get_mission_class(mtyp)
except ValueError:
raise CentralCommandError('no such mission')
s.mission = mtyp
s.mission_status = 'init'
s.mission_state = {k: v.default for k,v in mclass.params().items()}
self.start_mission(s)
def start_mission(self, s): def start_mission(self, s):
mtype = s.mission mtype = s.mission
m = create_mission(mtype, s, self.store, self.api) m = create_mission(mtype, s, self.store, self.api)

View File

@@ -41,7 +41,7 @@ class CommandLine:
print(f'command not found; {c}') print(f'command not found; {c}')
def handle_error(self, cmd, args, e): def handle_error(self, cmd, args, e):
logging.error(e, exc_info=type(e).__name__ not in ['ApiError','CommandError']) logging.error(e, exc_info=type(e).__name__ not in ['ApiError','CommandError', 'CentralCommandError'])
def handle_empty(self): def handle_empty(self):
pass pass
@@ -90,5 +90,8 @@ class CommandLine:
except EOFError: except EOFError:
self.handle_eof() self.handle_eof()
break break
self.handle_cmd(c) try:
self.handle_cmd(c)
except Exception as e:
logging.error(e, exc_info=True)

View File

@@ -82,13 +82,6 @@ class Commander(CommandLine):
def do_auto(self): def do_auto(self):
self.centcom.run_interactive() self.centcom.run_interactive()
def set_mission(self, arg=''):
if arg == 'none':
arg = None
self.ship.mission = arg
self.ship.mission_status = 'init'
self.centcom.start_mission(self.ship)
def print_mission(self): def print_mission(self):
print(f'mission: {self.ship.mission} ({self.ship.mission_status})') print(f'mission: {self.ship.mission} ({self.ship.mission_status})')
pprint(self.ship.mission_state) pprint(self.ship.mission_state)
@@ -96,12 +89,15 @@ class Commander(CommandLine):
def do_mission(self, arg=''): def do_mission(self, arg=''):
if not self.has_ship(): return if not self.has_ship(): return
if arg: if arg:
self.set_mission(arg) self.centcom.init_mission(self.ship, arg)
self.print_mission() self.print_mission()
def do_mset(self, args): def do_mreset(self):
if not self.has_ship(): return
self.ship.mission_state = {}
def do_mset(self, nm, val):
if not self.has_ship(): return if not self.has_ship(): return
nm, val = args.split(' ')
self.centcom.set_mission_param(self.ship, nm, val) self.centcom.set_mission_param(self.ship, nm, val)
def active_contract(self): def active_contract(self):
@@ -118,20 +114,64 @@ class Commander(CommandLine):
raise CommandError('no delivery') raise CommandError('no delivery')
resource = delivery['trade_symbol'] resource = delivery['trade_symbol']
destination = delivery['destination'] destination = delivery['destination']
self.set_mission('mine') self.centcom.init_mission(self.ship, 'mine')
self.centcom.set_mission_param(self.ship, 'site', site) self.centcom.set_mission_param(self.ship, 'site', site)
self.centcom.set_mission_param(self.ship, 'resource', resource) self.centcom.set_mission_param(self.ship, 'resource', resource)
self.centcom.set_mission_param(self.ship, 'destination', destination) self.centcom.set_mission_param(self.ship, 'dest', destination)
self.centcom.set_mission_param(self.ship, 'contract', contract.symbol) self.centcom.set_mission_param(self.ship, 'contract', contract.symbol)
self.print_mission() self.print_mission()
def do_chaul(self):
if not self.has_ship(): return
contract = self.active_contract()
delivery = contract.unfinished_delivery()
if delivery is None:
raise CommandError('no delivery')
resource = delivery['trade_symbol']
destination = delivery['destination']
m = self.analyzer.find_closest_markets(resource, 'buy', destination)
if len(m) == 0:
m = self.analyzer.find_closest_markets(resource, 'exchange', destination)
if len(m) == 0:
print('no market found')
return
_, m, _, _ = m[0]
site = self.store.get(Waypoint, m.symbol)
self.centcom.init_mission(self.ship, 'haul')
self.centcom.set_mission_param(self.ship, 'site', site.symbol)
self.centcom.set_mission_param(self.ship, 'resource', resource)
self.centcom.set_mission_param(self.ship, 'dest', destination)
self.centcom.set_mission_param(self.ship, 'contract', contract.symbol)
self.print_mission()
def do_cprobe(self):
if not self.has_ship(): return
contract = self.active_contract()
delivery = contract.unfinished_delivery()
if delivery is None:
raise CommandError('no delivery')
resource = delivery['trade_symbol']
destination = delivery['destination']
m = self.analyzer.find_closest_markets(resource, 'buy,exchange', destination)
if len(m) is None:
print('no market found')
return
markets = [ mkt[1] for mkt in m]
markets = self.analyzer.solve_tsp(markets)
hops = ','.join([m.symbol for m in markets])
self.centcom.init_mission(self.ship, 'probe')
self.centcom.set_mission_param(self.ship, 'hops', hops)
self.print_mission()
def do_travel(self, dest):
dest = self.resolve('Waypoint', dest)
self.centcom.init_mission(self.ship, 'travel')
self.centcom.set_mission_param(self.ship, 'dest', dest.symbol)
self.print_mission()
def do_register(self, faction): def do_register(self, faction):
self.api.register(faction.upper()) self.api.register(faction.upper())
site = self.ship.location_str pprint(self.api.agent)
contract = self.active_contract()
self.do_mission('mine')
self.centcom.set_mission_param(self.ship, 'site', site)
self.centcom.set_mission_param(self.ship, 'contract', contract)
def do_universe(self, page=1): def do_universe(self, page=1):
self.atlas_builder.run(page) self.atlas_builder.run(page)
@@ -184,16 +224,16 @@ class Commander(CommandLine):
r = self.api.jumps(waypoint) r = self.api.jumps(waypoint)
pprint(r) pprint(r)
def do_query(self): def do_query(self, resource):
location = self.ask_obj(System, 'Where are you? ') if not self.has_ship(): return
resource = input('what resource?').upper() location = self.ship.location()
sellbuy = self.ask_multichoice(['sell','buy'], 'do you want to sell or buy?') resource = resource.upper()
print('Found markets:') print('Found markets:')
for m in self.analyzer.find_markets(resource, sellbuy): for typ, m, d, plen in self.analyzer.find_closest_markets(resource, 'buy,exchange',location):
system = self.store.get(System, m.system()) price = '?'
p = self.analyzer.find_path(location, system) if resource in m.prices:
if p is None: continue price = m.prices[resource]['buy']
print(m, f'{len(p)-1} hops') print(m, typ[0], f'{plen-1:3} hops {price}')
def do_path(self): def do_path(self):
orig = self.ask_obj(System, 'from: ') orig = self.ask_obj(System, 'from: ')
@@ -228,6 +268,10 @@ class Commander(CommandLine):
self.api.deliver(self.ship, resource, contract) self.api.deliver(self.ship, resource, contract)
pprint(contract) pprint(contract)
def do_fulfill(self):
contract = self.active_contract()
self.api.fulfill(contract)
def do_ship(self, arg=''): def do_ship(self, arg=''):
if arg != '': if arg != '':
symbol = f'{self.agent.symbol}-{arg}' symbol = f'{self.agent.symbol}-{arg}'
@@ -309,7 +353,9 @@ class Commander(CommandLine):
def do_shipyard(self): def do_shipyard(self):
if not self.has_ship(): return if not self.has_ship(): return
location = self.ship.location() location = self.ship.location()
pprint(self.api.shipyard(location)) data = self.api.shipyard(location)
for s in must_get(data, 'ships'):
print(s['type'], s['purchasePrice'])
def do_jump(self, system_str): def do_jump(self, system_str):
if not self.has_ship(): return if not self.has_ship(): return

View File

@@ -0,0 +1,23 @@
from nullptr.missions.survey import SurveyMission
from nullptr.missions.mine import MiningMission
from nullptr.missions.haul import HaulMission
from nullptr.missions.travel import TravelMission
from nullptr.missions.probe import ProbeMission
def get_mission_class( mtype):
types = {
'survey': SurveyMission,
'mine': MiningMission,
'haul': HaulMission,
'travel': TravelMission,
'probe': ProbeMission
}
if mtype not in types:
raise ValueError(f'invalid mission type {mtype}')
return types[mtype]
def create_mission(mtype, ship, store, api):
typ = get_mission_class(mtype)
m = typ(ship, store, api)
return m

View File

@@ -2,9 +2,12 @@ from nullptr.store import Store
from nullptr.models.base import Base from nullptr.models.base import Base
from nullptr.models.waypoint import Waypoint from nullptr.models.waypoint import Waypoint
from nullptr.models.contract import Contract from nullptr.models.contract import Contract
from nullptr.models.system import System
from nullptr.models.survey import Survey from nullptr.models.survey import Survey
from nullptr.models.ship import Ship from nullptr.models.ship import Ship
from nullptr.analyzer import Analyzer
from time import time from time import time
from functools import partial
import logging import logging
from nullptr.util import * from nullptr.util import *
@@ -22,6 +25,8 @@ class MissionParam:
return str(val) return str(val)
elif self.cls == int: elif self.cls == int:
return int(val) return int(val)
elif self.cls == list:
return [i.strip() for i in val.split(',')]
elif issubclass(self.cls, Base): elif issubclass(self.cls, Base):
data = store.get(self.cls, val) data = store.get(self.cls, val)
if data is None: if data is None:
@@ -42,6 +47,7 @@ class Mission:
self.store = store self.store = store
self.api = api self.api = api
self.next_step = 0 self.next_step = 0
self.analyzer = Analyzer(self.store)
def sts(self, nm, v): def sts(self, nm, v):
if issubclass(type(v), Base): if issubclass(type(v), Base):
@@ -121,85 +127,7 @@ class Mission:
self.status(next_step[result]) self.status(next_step[result])
print(f'{self.ship} {status} -> {self.status()}') print(f'{self.ship} {status} -> {self.status()}')
class BaseMission(Mission):
class MiningMission(Mission):
@classmethod
def params(cls):
return {
'site': MissionParam(Waypoint, True),
'resource': MissionParam(str, True),
'destination': MissionParam(Waypoint, True),
'delivery': MissionParam(str, True, 'deliver'),
'contract': MissionParam(Contract, False)
}
def start_state(self):
return 'go_site'
def steps(self):
return {
'extract': (self.step_extract, {
'done': 'dock',
'more': 'extract'
}),
'dock': (self.step_dock, 'sell'),
'sell': (self.step_sell, {
'more': 'sell',
'done': 'orbit',
}),
'orbit': (self.step_orbit, 'jettison'),
'jettison': (self.step_dispose, {
'more': 'jettison',
'done': 'extract',
'full': 'go_dest'
}),
'go_dest': (self.step_go_dest, 'dock_dest'),
'dock_dest': (self.step_dock, 'unload'),
'unload': (self.step_unload, {
'done': 'refuel',
'more': 'unload'
}),
'refuel': (self.step_refuel, 'orbit_dest'),
'orbit_dest': (self.step_orbit, 'go_site'),
'go_site': (self.step_go_site, 'extract')
}
def get_survey(self):
resource = self.st('resource')
site = self.rst(Waypoint,'site')
# todo optimize
for s in self.store.all(Survey):
if resource in s.deposits and site.symbol == s.waypoint():
return s
return None
def step_extract(self):
survey = self.get_survey()
print('using survey:', str(survey))
result = self.api.extract(self.ship, survey)
symbol = sg(result,'extraction.yield.symbol')
units = sg(result,'extraction.yield.units')
print('extracted:', units, symbol)
self.next_step = self.ship.cooldown
if self.ship.cargo_units < self.ship.cargo_capacity:
return 'more'
else:
return 'done'
def step_sell(self, except_resource=True):
target = self.st('resource')
market = self.store.get('Marketplace', self.ship.location_str)
sellables = market.sellable_items(self.ship.cargo.keys())
if target in sellables and except_resource:
sellables.remove(target)
if len(sellables) == 0:
return 'done'
self.api.sell(self.ship, sellables[0])
if len(sellables) == 1:
return 'done'
else:
return 'more'
def step_go_dest(self): def step_go_dest(self):
destination = self.rst(Waypoint, 'destination') destination = self.rst(Waypoint, 'destination')
if self.ship.location() == destination: if self.ship.location() == destination:
@@ -207,8 +135,12 @@ class MiningMission(Mission):
self.api.navigate(self.ship, destination) self.api.navigate(self.ship, destination)
self.next_step = self.ship.arrival self.next_step = self.ship.arrival
def step_dock(self): def step_go_site(self):
self.api.dock(self.ship) site = self.rst(Waypoint,'site')
if self.ship.location() == site:
return
self.api.navigate(self.ship, site)
self.next_step = self.ship.arrival
def step_unload(self): def step_unload(self):
contract = self.rst(Contract, 'contract') contract = self.rst(Contract, 'contract')
@@ -224,54 +156,95 @@ class MiningMission(Mission):
else: else:
return 'more' return 'more'
def step_refuel(self): def step_sell(self, except_resource=True):
self.api.refuel(self.ship) target = self.st('resource')
market = self.store.get('Marketplace', self.ship.location_str)
def step_dispose(self): sellables = market.sellable_items(self.ship.cargo.keys())
contract = self.rst(Contract, 'contract') if target in sellables and except_resource:
typs = self.ship.nondeliverable_cargo(contract) sellables.remove(target)
if len(typs) > 0: if len(sellables) == 0:
self.api.jettison(self.ship, typs[0])
if len(typs) > 1:
return 'more'
elif self.ship.cargo_units > self.ship.cargo_capacity - 3:
return 'full'
else:
return 'done' return 'done'
self.api.sell(self.ship, sellables[0])
if len(sellables) == 1:
return 'done'
else:
return 'more'
def step_load(self):
cargo_space = self.ship.cargo_capacity - self.ship.cargo_units
resource = self.st('resource')
self.api.buy(self.ship, resource, cargo_space)
def step_travel(self):
traject = self.st('traject')
if traject is None or traject == []:
return 'done'
dest = self.store.get(Waypoint, traject[-1])
loc = self.ship.location()
print(dest, loc)
if dest == loc:
self.sts('traject', None)
return 'done'
hop = traject.pop(0)
if len(hop.split('-')) == 3:
self.api.navigate(self.ship, hop)
self.next_step = self.ship.arrival
else:
self.api.jump(self.ship, hop)
self.next_step = self.ship.cooldown
if traject == []:
traject= None
self.sts('traject', traject)
return 'more'
def step_calculate_traject(self, dest):
if type(dest) == str:
dest = self.store.get(Waypoint, dest)
loc = self.ship.location()
loc_sys = self.store.get(System, loc.system())
loc_jg = self.analyzer.get_jumpgate(loc_sys)
dest_sys = self.store.get(System, dest.system())
dest_jg = self.analyzer.get_jumpgate(dest_sys)
if dest_sys == loc_sys:
result = [dest.symbol]
self.sts('traject', result)
return
path = self.analyzer.find_path(loc_sys, dest_sys)
result = []
if loc.symbol != loc_jg.symbol:
result.append(loc_jg.symbol)
result += [s.symbol for s in path[1:]]
if dest_jg.symbol != dest.symbol:
result.append(dest.symbol)
self.sts('traject', result)
print(result)
return result
def step_dock(self):
self.api.dock(self.ship)
def step_refuel(self):
if self.ship.fuel_capacity == 0:
return
if self.ship.fuel_current / self.ship.fuel_capacity < 0.5:
try:
self.api.refuel(self.ship)
except Exception as e:
pass
def step_orbit(self): def step_orbit(self):
self.api.orbit(self.ship) self.api.orbit(self.ship)
def step_go_site(self): def travel_steps(self, nm, destination, next_step):
site = self.rst(Waypoint,'site') destination = self.st(destination)
if self.ship.location() == site: calc = partial(self.step_calculate_traject, destination)
return
self.api.navigate(self.ship, site)
self.next_step = self.ship.arrival
class SurveyMission(Mission):
def start_state(self):
return 'survey'
def steps(self):
return { return {
'survey': (self.step_survey, 'survey') f'travel-{nm}': (self.step_orbit, f'calc-trav-{nm}'),
f'calc-trav-{nm}': (calc, f'go-{nm}'),
f'go-{nm}': (self.step_travel, {
'done': f'dock-{nm}',
'more': f'go-{nm}'
}),
f'dock-{nm}': (self.step_dock, f'refuel-{nm}'),
f'refuel-{nm}': (self.step_refuel, next_step)
} }
def step_survey(self):
result = self.api.survey(self.ship)
#pprint(result, 2)
self.next_step = self.ship.cooldown
def create_mission(mtype, ship, store, api):
types = {
'survey': SurveyMission,
'mine': MiningMission
}
if mtype not in types:
logging.warning(f'invalid mission type {mtype}')
return
m = types[mtype](ship, store, api)
return m

25
nullptr/missions/haul.py Normal file
View File

@@ -0,0 +1,25 @@
from nullptr.missions.base import BaseMission, MissionParam
from nullptr.models.waypoint import Waypoint
from nullptr.models.survey import Survey
from nullptr.models.contract import Contract
class HaulMission(BaseMission):
def start_state(self):
return 'travel-to'
@classmethod
def params(cls):
return {
'site': MissionParam(Waypoint, True),
'resource': MissionParam(str, True),
'dest': MissionParam(Waypoint, True),
'delivery': MissionParam(str, True, 'deliver'),
'contract': MissionParam(Contract, False)
}
def steps(self):
return {
**self.travel_steps('to', 'site', 'load'),
'load': (self.step_load, 'travel-back'),
**self.travel_steps('back', 'dest', 'unload'),
'unload': (self.step_unload, 'travel-to'),
}

80
nullptr/missions/mine.py Normal file
View File

@@ -0,0 +1,80 @@
from nullptr.missions.base import BaseMission, MissionParam
from nullptr.models.waypoint import Waypoint
from nullptr.models.survey import Survey
from nullptr.models.contract import Contract
from nullptr.util import *
class MiningMission(BaseMission):
@classmethod
def params(cls):
return {
'site': MissionParam(Waypoint, True),
'resource': MissionParam(str, True),
'dest': MissionParam(Waypoint, True),
'delivery': MissionParam(str, True, 'deliver'),
'contract': MissionParam(Contract, False)
}
def start_state(self):
return 'travel-to'
def steps(self):
return {
**self.travel_steps('to', 'site', 'orbit1'),
'orbit1': (self.step_orbit, 'extract'),
'extract': (self.step_extract, {
'done': 'dock',
'more': 'extract'
}),
'dock': (self.step_dock, 'sell'),
'sell': (self.step_sell, {
'more': 'sell',
'done': 'orbit2',
}),
'orbit2': (self.step_orbit, 'jettison'),
'jettison': (self.step_dispose, {
'more': 'jettison',
'done': 'extract',
'full': 'travel-back'
}),
**self.travel_steps('back', 'dest', 'unload'),
'unload': (self.step_unload, {
'done': 'travel-to',
'more': 'unload'
}),
}
def get_survey(self):
resource = self.st('resource')
site = self.rst(Waypoint,'site')
# todo optimize
for s in self.store.all(Survey):
if resource in s.deposits and site.symbol == s.waypoint():
return s
return None
def step_extract(self):
survey = self.get_survey()
print('using survey:', str(survey))
result = self.api.extract(self.ship, survey)
symbol = sg(result,'extraction.yield.symbol')
units = sg(result,'extraction.yield.units')
print('extracted:', units, symbol)
self.next_step = self.ship.cooldown
if self.ship.cargo_units < self.ship.cargo_capacity:
return 'more'
else:
return 'done'
def step_dispose(self):
contract = self.rst(Contract, 'contract')
typs = self.ship.nondeliverable_cargo(contract)
if len(typs) > 0:
self.api.jettison(self.ship, typs[0])
if len(typs) > 1:
return 'more'
elif self.ship.cargo_units > self.ship.cargo_capacity - 3:
return 'full'
else:
return 'done'

33
nullptr/missions/probe.py Normal file
View File

@@ -0,0 +1,33 @@
from nullptr.missions.base import BaseMission, MissionParam
from nullptr.models.waypoint import Waypoint
class ProbeMission(BaseMission):
def start_state(self):
return 'next-hop'
@classmethod
def params(cls):
return {
'hops': MissionParam(list, True),
'next-hop': MissionParam(int, True, 0)
}
def steps(self):
return {
'next-hop': (self.step_next_hop, 'travel-to'),
**self.travel_steps('to', 'site', 'market'),
'market': (self.step_market, 'next-hop'),
}
def step_market(self):
loc = self.ship.location()
self.api.marketplace(loc)
def step_next_hop(self):
hops = self.st('hops')
next_hop = self.st('next-hop')
hop = hops[next_hop]
self.sts('site', hop)
self.sts('next-hop', (next_hop+1) % len(hops))

View File

@@ -0,0 +1,15 @@
from nullptr.missions.base import BaseMission, MissionParam
class SurveyMission(BaseMission):
def start_state(self):
return 'survey'
def steps(self):
return {
'survey': (self.step_survey, 'survey')
}
def step_survey(self):
result = self.api.survey(self.ship)
#pprint(result, 2)
self.next_step = self.ship.cooldown

View File

@@ -0,0 +1,16 @@
from nullptr.missions.base import BaseMission, MissionParam
from nullptr.models.waypoint import Waypoint
class TravelMission(BaseMission):
def start_state(self):
return 'travel-to'
@classmethod
def params(cls):
return {
'dest': MissionParam(Waypoint, True)
}
def steps(self):
return self.travel_steps('to', 'dest', 'done')

View File

@@ -7,10 +7,11 @@ class Base:
store: object store: object
def __init__(self, symbol, store): def __init__(self, symbol, store):
self.disable_dirty = False self.disable_dirty = True
self.store = store self.store = store
self.symbol = symbol self.symbol = symbol
self.define() self.define()
self.disable_dirty = False
def define(self): def define(self):
pass pass

View File

@@ -124,6 +124,7 @@ class Store:
if system not in self.system_members: if system not in self.system_members:
return return
print('typ', typ)
for m in self.system_members[system]: for m in self.system_members[system]:
if typ is None or type(m) == typ: if typ is None or type(m) == typ:
yield m yield m