|
@@ -4,7 +4,9 @@ from twisted.internet import defer
|
|
|
from colorama import Fore, Back, Style
|
|
|
from twisted.python import log
|
|
|
|
|
|
+from itertools import cycle
|
|
|
import pendulum
|
|
|
+from pprint import pformat
|
|
|
|
|
|
|
|
|
def merge(color_string):
|
|
@@ -52,6 +54,7 @@ class PlayerInput(object):
|
|
|
|
|
|
keywords:
|
|
|
abort_blank : Abort if they give us blank text.
|
|
|
+ name : Stores the input in self.keep dict.
|
|
|
|
|
|
"""
|
|
|
log.msg("PlayerInput({0}, {1}, {2}".format(user_prompt, limit, kw))
|
|
@@ -74,7 +77,8 @@ class PlayerInput(object):
|
|
|
self.game.to_player = False
|
|
|
|
|
|
# Display prompt
|
|
|
- self.queue_game.put(self.r + self.nl + self.c + user_prompt + " " + self.cp)
|
|
|
+ # self.queue_game.put(self.r + self.nl + self.c + user_prompt + " " + self.cp)
|
|
|
+ self.queue_game.put(self.r + self.c + user_prompt + self.r + " " + self.cp)
|
|
|
# Set "Background of prompt"
|
|
|
self.queue_game.put(" " * limit + "\b" * limit)
|
|
|
|
|
@@ -107,6 +111,7 @@ class PlayerInput(object):
|
|
|
line = self.input
|
|
|
self.input = ""
|
|
|
assert not self.deferred is None
|
|
|
+ self.game.to_player = self.to_player
|
|
|
|
|
|
# If they gave us the keyword name, save the value as that name
|
|
|
if "name" in self.kw:
|
|
@@ -144,10 +149,157 @@ class PlayerInput(object):
|
|
|
def output(self, line):
|
|
|
""" A default display of what they just input. """
|
|
|
log.msg("PlayerInput.output({0})".format(line))
|
|
|
- self.game.queue_game.put(self.r + self.nl + "[{0}]".format(line) + self.nl)
|
|
|
+ self.game.queue_game.put(self.r + "[{0}]".format(line) + self.nl)
|
|
|
return line
|
|
|
|
|
|
|
|
|
+PORT_CLASSES = {
|
|
|
+ 1: "BBS",
|
|
|
+ 2: "BSB",
|
|
|
+ 3: "SBB",
|
|
|
+ 4: "SSB",
|
|
|
+ 5: "SBS",
|
|
|
+ 6: "BSS",
|
|
|
+ 7: "SSS",
|
|
|
+ 8: "BBB",
|
|
|
+}
|
|
|
+CLASSES_PORT = {v: k for k, v in PORT_CLASSES.items()}
|
|
|
+import re
|
|
|
+
|
|
|
+
|
|
|
+class CIMPortReport(object):
|
|
|
+ def __init__(self, game):
|
|
|
+ self.game = game
|
|
|
+ self.queue_game = game.queue_game
|
|
|
+ self.queue_player = game.queue_player
|
|
|
+ self.observer = game.observer
|
|
|
+ # Yes, at this point we would activate
|
|
|
+ self.prompt = game.buffer
|
|
|
+ self.save = self.observer.save()
|
|
|
+
|
|
|
+ # I actually don't want the player input, but I'll grab it anyway.
|
|
|
+ self.observer.connect("player", self.player)
|
|
|
+
|
|
|
+ self.observer.connect("prompt", self.game_prompt)
|
|
|
+ self.observer.connect("game-line", self.game_line)
|
|
|
+
|
|
|
+ # If we want it, it's here.
|
|
|
+ self.defer = None
|
|
|
+ self.to_player = self.game.to_player
|
|
|
+ log.msg("to_player (stored)", self.to_player)
|
|
|
+
|
|
|
+ # Hide what's happening from the player
|
|
|
+ self.game.to_player = False
|
|
|
+
|
|
|
+ self.queue_player.put("^") # Activate CIM
|
|
|
+ self.state = 1
|
|
|
+ self.portdata = {}
|
|
|
+ self.portcycle = cycle(["/", "-", "\\", "|"])
|
|
|
+
|
|
|
+ def game_prompt(self, prompt):
|
|
|
+ if prompt == ": ":
|
|
|
+ if self.state == 1:
|
|
|
+ # Ok, then we're ready to request the port report
|
|
|
+ self.portcycle = cycle(["/", "-", "\\", "|"])
|
|
|
+ self.queue_player.put("R")
|
|
|
+ self.state = 2
|
|
|
+ if self.state == 2:
|
|
|
+ self.queue_player.put("Q")
|
|
|
+ self.state = 3
|
|
|
+ if re.match(r"Command \[TL=.* \(\?=Help\)\? :", prompt):
|
|
|
+ if self.state == 3:
|
|
|
+ # Ok, time to exit
|
|
|
+ # exit from this...
|
|
|
+ self.game.to_player = self.to_player
|
|
|
+ self.observer.load(self.save)
|
|
|
+ self.save = None
|
|
|
+
|
|
|
+ self.queue_game.put("\b \b\r\n")
|
|
|
+
|
|
|
+ if not self.defer is None:
|
|
|
+ self.defer.callback(self.portdata)
|
|
|
+ self.defer = None
|
|
|
+
|
|
|
+ def game_line(self, line):
|
|
|
+ if line == "" or line == ": ":
|
|
|
+ return
|
|
|
+ if line == ": ENDINTERROG":
|
|
|
+ return
|
|
|
+
|
|
|
+ # This should be the CIM Report Data -- parse it
|
|
|
+ if self.portcycle:
|
|
|
+ if len(self.portdata) % 10 == 0:
|
|
|
+ self.queue_game.put("\b" + next(self.portcycle))
|
|
|
+
|
|
|
+ work = line.replace("%", "")
|
|
|
+
|
|
|
+ parts = re.split(r"(?<=\d)\s", work)
|
|
|
+
|
|
|
+ if len(parts) == 8:
|
|
|
+ port = int(parts[0].strip())
|
|
|
+ data = dict()
|
|
|
+
|
|
|
+ def portBS(info):
|
|
|
+ if info[0] == "-":
|
|
|
+ bs = "B"
|
|
|
+ else:
|
|
|
+ bs = "S"
|
|
|
+ return (bs, int(info[1:].strip()))
|
|
|
+
|
|
|
+ data["fuel"] = dict()
|
|
|
+ data["fuel"]["sale"], data["fuel"]["units"] = portBS(parts[1])
|
|
|
+ data["fuel"]["pct"] = int(parts[2].strip())
|
|
|
+ data["org"] = dict()
|
|
|
+ data["org"]["sale"], data["org"]["units"] = portBS(parts[3])
|
|
|
+ data["org"]["pct"] = int(parts[4].strip())
|
|
|
+ data["equ"] = dict()
|
|
|
+ data["equ"]["sale"], data["equ"]["units"] = portBS(parts[5])
|
|
|
+ data["equ"]["pct"] = int(parts[6].strip())
|
|
|
+
|
|
|
+ # Store what this port is buying/selling
|
|
|
+ data["port"] = (
|
|
|
+ data["fuel"]["sale"] + data["org"]["sale"] + data["equ"]["sale"]
|
|
|
+ )
|
|
|
+
|
|
|
+ # Convert BBS/SBB to Class number 1-8
|
|
|
+ data["class"] = CLASSES_PORT[data["port"]]
|
|
|
+ self.portdata[port] = data
|
|
|
+ else:
|
|
|
+ log.msg("CIMPortReport:", line, "???")
|
|
|
+
|
|
|
+ def __del__(self):
|
|
|
+ log.msg("CIMPortReport {0} RIP".format(self))
|
|
|
+
|
|
|
+ def whenDone(self):
|
|
|
+ self.defer = defer.Deferred()
|
|
|
+ # Call this to chain something after we exit.
|
|
|
+ return self.defer
|
|
|
+
|
|
|
+ def player(self, chunk):
|
|
|
+ """ Data from player (in bytes). """
|
|
|
+ chunk = chunk.decode("utf-8", "ignore")
|
|
|
+ key = chunk.upper()
|
|
|
+ log.msg("CIMPortReport.player({0}) : I AM stopping...".format(key))
|
|
|
+
|
|
|
+ # Stop the keepalive if we are activating something else
|
|
|
+ # or leaving...
|
|
|
+ # self.keepalive.stop()
|
|
|
+
|
|
|
+ self.queue_game.put("\b \b\r\n")
|
|
|
+
|
|
|
+ if not self.defer is None:
|
|
|
+ # We have something, so:
|
|
|
+ self.game.to_player = self.to_player
|
|
|
+ self.observer.load(self.save)
|
|
|
+ self.save = None
|
|
|
+ self.defer.errback(Exception("User Abort"))
|
|
|
+ self.defer = None
|
|
|
+ else:
|
|
|
+ # Still "exit" out.
|
|
|
+ self.game.to_player = self.to_player
|
|
|
+ self.observer.load(self.save)
|
|
|
+
|
|
|
+
|
|
|
class ProxyMenu(object):
|
|
|
def __init__(self, game):
|
|
|
self.nl = "\n\r"
|
|
@@ -155,7 +307,7 @@ class ProxyMenu(object):
|
|
|
self.r = Style.RESET_ALL
|
|
|
self.c1 = merge(Style.BRIGHT + Fore.BLUE)
|
|
|
self.c2 = merge(Style.NORMAL + Fore.CYAN)
|
|
|
-
|
|
|
+ self.portdata = None
|
|
|
self.game = game
|
|
|
self.queue_game = game.queue_game
|
|
|
self.observer = game.observer
|
|
@@ -202,6 +354,11 @@ class ProxyMenu(object):
|
|
|
log.msg("ProxyMenu.awake()")
|
|
|
self.game.queue_player.put(" ")
|
|
|
|
|
|
+ def port_report(self, portdata):
|
|
|
+ self.portdata = portdata
|
|
|
+ self.queue_game.put("Loaded {0} records.".format(len(portdata)) + self.nl)
|
|
|
+ self.welcome_back()
|
|
|
+
|
|
|
def player(self, chunk):
|
|
|
""" Data from player (in bytes). """
|
|
|
chunk = chunk.decode("utf-8", "ignore")
|
|
@@ -219,20 +376,31 @@ class ProxyMenu(object):
|
|
|
self.queue_game.put(
|
|
|
self.nl + self.c1 + "Current time " + now.to_datetime_string() + self.nl
|
|
|
)
|
|
|
+ elif key == "P":
|
|
|
+ self.queue_game.put(self.c + key + self.r + self.nl)
|
|
|
+ # Activate CIM Port Report
|
|
|
+ report = CIMPortReport(self.game)
|
|
|
+ d = report.whenDone()
|
|
|
+ d.addCallback(self.port_report)
|
|
|
+ d.addErrback(self.welcome_back)
|
|
|
+ return
|
|
|
+ elif key == "D":
|
|
|
+ self.queue_game.put(self.c + key + self.r + self.nl)
|
|
|
+ self.queue_game.put(pformat(self.portdata).replace("\n", "\n\r") + self.nl)
|
|
|
elif key == "Q":
|
|
|
self.queue_game.put(self.c + key + self.r + self.nl)
|
|
|
|
|
|
# This is an example of chaining PlayerInput prompt calls.
|
|
|
|
|
|
ask = PlayerInput(self.game)
|
|
|
- d = ask.prompt("What is your quest?", 20, name="quest", abort_blank=True)
|
|
|
+ d = ask.prompt("What is your quest?", 40, name="quest", abort_blank=True)
|
|
|
|
|
|
# Display the user's input
|
|
|
d.addCallback(ask.output)
|
|
|
|
|
|
d.addCallback(
|
|
|
lambda ignore: ask.prompt(
|
|
|
- "What is your favorite color?", 5, name="color"
|
|
|
+ "What is your favorite color?", 10, name="color"
|
|
|
)
|
|
|
)
|
|
|
d.addCallback(ask.output)
|
|
@@ -240,7 +408,7 @@ class ProxyMenu(object):
|
|
|
d.addCallback(
|
|
|
lambda ignore: ask.prompt(
|
|
|
"What is the meaning of the squirrel?",
|
|
|
- 40,
|
|
|
+ 12,
|
|
|
name="squirrel",
|
|
|
digits=True,
|
|
|
)
|
|
@@ -249,6 +417,7 @@ class ProxyMenu(object):
|
|
|
|
|
|
def show_values(show):
|
|
|
log.msg(show)
|
|
|
+ self.queue_game.put(pformat(show).replace("\n", "\n\r") + self.nl)
|
|
|
|
|
|
d.addCallback(lambda ignore: show_values(ask.keep))
|
|
|
d.addCallback(self.welcome_back)
|