123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420 |
- from twisted.internet import reactor
- from twisted.internet import task
- from twisted.internet import defer
- from colorama import Fore, Back, Style
- from twisted.python import log
- """ This entire object, will likely be replaced with something
- smaller, simpler, and much more reliable.
- """
- class MCP(object):
- def __init__(self, game):
- self.game = game
- self.queue_game = None
- # we don't have this .. yet!
- self.prompt = None
- self.observer = None
- self.keepalive = None
- # Port Data
- self.portdata = None
- self.portcycle = None
- def finishSetup(self):
- # if self.queue_game is None:
- self.queue_game = self.game.queue_game
- # if self.observer is None:
- self.observer = self.game.observer
- self.observer.connect("hotkey", self.activate)
- self.observer.connect("notyet", self.notyet)
- self.observer.connect("close", self.close)
- def close(self, _):
- if self.keepalive:
- if self.keepalive.running:
- self.keepalive.stop()
- def notyet(self, _):
- """ No, not yet! """
- nl = "\n\r"
- r = Style.RESET_ALL
- log.msg("NNY!")
- prompt = self.game.buffer
- self.queue_game.put(
- r
- + nl
- + Style.BRIGHT
- + "Proxy:"
- + Style.RESET_ALL
- + " I can't activate at this time."
- + nl
- )
- self.queue_game.put(prompt)
- def stayAwake(self):
- """ Send a space to the game to keep it alive/don't timeout. """
- log.msg("Gameserver, stay awake.")
- self.game.queue_player.put(" ")
- def startAwake(self):
- """ Start the task that keeps the game server alive.
- There is currently a bug in there somewhere, which causes it to
- duplicate:
- 2019-11-25 21:19:03-0500 [-] Gameserver, stay awake.
- 2019-11-25 21:19:14-0500 [-] Gameserver, stay awake.
- 2019-11-25 21:19:24-0500 [-] Gameserver, stay awake.
- 2019-11-25 21:19:27-0500 [-] Gameserver, stay awake.
- 2019-11-25 21:19:31-0500 [-] Gameserver, stay awake.
- 2019-11-25 21:19:33-0500 [-] Gameserver, stay awake.
- 2019-11-25 21:19:44-0500 [-] Gameserver, stay awake.
- 2019-11-25 21:19:54-0500 [-] Gameserver, stay awake.
- 2019-11-25 21:19:57-0500 [-] Gameserver, stay awake.
- 2019-11-25 21:20:01-0500 [-] Gameserver, stay awake.
- 2019-11-25 21:20:03-0500 [-] Gameserver, stay awake.
- ^ These aren't 30 seconds apart.
- These are being sent, even when the MCP is not active!
- """
- self.keepalive = task.LoopingCall(self.stayAwake)
- self.keepalive.start(30)
- def activate(self, _):
- log.msg("MCP menu called.")
- # We want the raw one, not the ANSI cleaned getPrompt.
- prompt = self.game.buffer
- if not self.prompt is None:
- # silly, we're already active
- log.msg("I think we're already active. Ignoring request.")
- return
- # Or will the caller setup/restore the prompt?
- self.prompt = prompt
- # queue_game = to player
- self.displayMenu()
- self.observer.connect("player", self.fromPlayer)
- # TODO: Add background "keepalive" event so the game doesn't time out on us.
- self.startAwake()
- # self.keepalive = task.LoopingCall(self.stayAwake)
- # self.keepalive.start(30)
- def displayMenu(self):
- nl = "\n\r"
- c = merge(Style.BRIGHT + Fore.YELLOW + Back.BLUE)
- r = Style.RESET_ALL
- c1 = merge(Style.BRIGHT + Fore.BLUE)
- c2 = merge(Style.NORMAL + Fore.BLUE)
- self.queue_game.put(nl + c + "TradeWars Proxy active." + r + nl)
- self.queue_game.put(" " + c1 + "D" + c2 + " - " + c1 + "Diagnostics" + nl)
- self.queue_game.put(
- " " + c1 + "T" + c2 + " - " + c1 + "Display current Time" + nl
- )
- self.queue_game.put(" " + c1 + "P" + c2 + " - " + c1 + "Port CIM Report" + nl)
- self.queue_game.put(" " + c1 + "S" + c2 + " - " + c1 + "Scripts" + nl)
- self.queue_game.put(" " + c1 + "X" + c2 + " - " + c1 + "eXit" + nl)
- self.queue_game.put(" " + c + "-=>" + r + " ")
- def fromPlayer(self, chunk):
- """ Data from player (in bytes). """
- chunk = chunk.decode("utf-8", "ignore")
- nl = "\n\r"
- c = merge(Style.BRIGHT + Fore.YELLOW + Back.BLUE)
- r = Style.RESET_ALL
- c1 = merge(Style.BRIGHT + Fore.BLUE)
- c2 = merge(Style.NORMAL + Fore.BLUE)
- key = chunk.upper()
- if key == "T":
- self.queue_game.put(c + key + r + nl)
- now = pendulum.now()
- log.msg("Time")
- self.queue_game.put(
- nl + c1 + "It is currently " + now.to_datetime_string() + "." + nl
- )
- self.displayMenu()
- elif key == "P":
- log.msg("Port")
- self.queue_game.put(c + key + r + nl)
- self.portReport()
- # self.queue_game.put(nl + c + "NO, NOT YET!" + r + nl)
- # self.displayMenu()
- elif key == "S":
- log.msg("Scripts")
- self.queue_game.put(c + key + r + nl)
- self.scripts()
- elif key == "D":
- self.queue_game.put(nl + "Diagnostics" + nl + "portdata:" + nl)
- line = pformat(self.portdata).replace("\n", "\n\r")
- self.queue_game.put(line + nl)
- self.displayMenu()
- elif key == "X":
- log.msg('"Quit, return to "normal". (Whatever that means!)')
- self.queue_game.put(c + key + r + nl)
- self.observer.disconnect("player", self.fromPlayer)
- self.queue_game.put(nl + c1 + "Returning to game" + c2 + "..." + r + nl)
- self.queue_game.put(self.prompt)
- self.prompt = None
- self.keepalive.stop()
- self.keepalive = None
- self.game.to_player = True
- else:
- if key.isprintable():
- self.queue_game.put(r + nl)
- self.queue_game.put("Excuse me? I don't understand '" + key + "'." + nl)
- self.displayMenu()
- def portReport(self):
- """ Activate CIM and request Port Report """
- self.game.to_player = False
- self.portdata = None
- self.observer.connect("prompt", self.portPrompt)
- self.observer.connect("game-line", self.portParse)
- self.game.queue_player.put("^")
- def portPrompt(self, prompt):
- if prompt == ": ":
- log.msg("CIM Prompt")
- if self.portdata is None:
- log.msg("R - Port Report")
- self.portdata = dict()
- self.game.queue_player.put("R")
- self.portcycle = cycle(["/", "-", "\\", "|"])
- self.queue_game.put(" ")
- else:
- log.msg("Q - Quit")
- self.game.queue_player.put("Q")
- self.portcycle = None
- def portBS(self, info):
- if info[0] == "-":
- bs = "B"
- else:
- bs = "S"
- return (bs, int(info[1:].strip()))
- def portParse(self, line):
- if line == "":
- return
- if line == ": ":
- return
- log.msg("parse line:", line)
- if line.startswith("Command [TL="):
- return
- if line == ": ENDINTERROG":
- log.msg("CIM Done")
- log.msg(pformat(self.portdata))
- self.queue_game.put("\b \b" + "\n\r")
- self.observer.disconnect("prompt", self.portPrompt)
- self.observer.disconnect("game-line", self.portParse)
- self.game.to_player = True
- # self.keepalive.start(30)
- self.startAwake()
- self.displayMenu()
- return
- # Give some sort of feedback to the user.
- if self.portcycle:
- if len(self.portdata) % 10 == 0:
- self.queue_game.put("\b" + next(self.portcycle))
- # Ok, we need to parse this line
- # 436 2870 100% - 1520 100% - 2820 100%
- # 2 1950 100% - 1050 100% 2780 100%
- # 5 2800 100% - 2330 100% - 1230 100%
- # 8 2890 100% 1530 100% - 2310 100%
- # 9 - 2160 100% 2730 100% - 2120 100%
- # 324 - 2800 100% 2650 100% - 2490 100%
- # 492 990 100% 900 100% 1660 100%
- # 890 1920 100% - 2140 100% 1480 100%
- # 1229 - 2870 100% - 1266 90% 728 68%
- # 1643 - 3000 100% - 3000 100% - 3000 100%
- # 1683 - 1021 97% 1460 100% - 2620 100%
- # 1898 - 1600 100% - 1940 100% - 1860 100%
- # 2186 1220 100% - 900 100% - 1840 100%
- # 2194 2030 100% - 1460 100% - 1080 100%
- # 2577 2810 100% - 1550 100% - 2350 100%
- # 2629 2570 100% - 2270 100% - 1430 100%
- # 3659 - 1720 100% 1240 100% - 2760 100%
- # 3978 - 920 100% 2560 100% - 2590 100%
- # 4302 348 25% - 2530 100% - 316 23%
- # 4516 - 1231 60% - 1839 75% 7 0%
- work = line.replace("%", "")
- parts = re.split(r"(?<=\d)\s", work)
- if len(parts) == 8:
- port = int(parts[0].strip())
- data = dict()
- data["fuel"] = dict()
- data["fuel"]["sale"], data["fuel"]["units"] = self.portBS(parts[1])
- data["fuel"]["pct"] = int(parts[2].strip())
- data["org"] = dict()
- data["org"]["sale"], data["org"]["units"] = self.portBS(parts[3])
- data["org"]["pct"] = int(parts[4].strip())
- data["equ"] = dict()
- data["equ"]["sale"], data["equ"]["units"] = self.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:
- self.queue_game.put("?")
- log.msg("Line in question is: [{0}].".format(line))
- log.msg(repr(parts))
- def scripts(self):
- self.script = dict()
- self.observer.disconnect("player", self.fromPlayer)
- self.observer.connect("player", self.scriptFromPlayer)
- self.observer.connect("game-line", self.scriptLine)
- nl = "\n\r"
- c = merge(Style.BRIGHT + Fore.WHITE + Back.BLUE)
- r = Style.RESET_ALL
- c1 = merge(Style.BRIGHT + Fore.CYAN)
- c2 = merge(Style.NORMAL + Fore.CYAN)
- self.queue_game.put(nl + c + "TradeWars Proxy Script(s)" + r + nl)
- self.queue_game.put(" " + c1 + "P" + c2 + " - " + c1 + "Port Trading Pair" + nl)
- self.queue_game.put(" " + c + "-=>" + r + " ")
- def unscript(self):
- self.observer.connect("player", self.fromPlayer)
- self.observer.disconnect("player", self.scriptFromPlayer)
- self.observer.disconnect("game-line", self.scriptLine)
- self.displayMenu()
- def scriptLine(self, line):
- pass
- def scriptFromPlayer(self, chunk):
- """ Data from player (in bytes). """
- chunk = chunk.decode("utf-8", "ignore")
- nl = "\n\r"
- c = merge(Style.BRIGHT + Fore.WHITE + Back.BLUE)
- r = Style.RESET_ALL
- key = chunk.upper()
- if key == "Q":
- self.queue_game.put(c + key + r + nl)
- self.observer.connect("player", self.fromPlayer)
- self.observer.disconnect("player", self.scriptFromPlayer)
- self.observer.disconnect("game-line", self.scriptLine)
- self.observer.connect("game-line", self.portParse)
- self.displayMenu()
- elif key == "P":
- self.queue_game.put(c + key + r + nl)
- d = self.playerInput("Enter sector to trade to: ", 6)
- d.addCallback(self.save_sector)
- def save_sector(self, sector):
- log.msg("save_sector {0}".format(sector))
- if sector.strip() == "":
- self.queue_game.put("Script Aborted.")
- self.unscript()
- return
- s = int(sector.strip())
- self.script["sector"] = s
- d = self.playerInput("Enter times to execute script: ", 6)
- d.addCallback(self.save_loop)
- def save_loop(self, loop):
- log.msg("save_loop {0}".format(loop))
- if loop.strip() == "":
- self.queue_game.put("Script Aborted.")
- self.unscript()
- return
- l = int(loop.strip())
- self.script["loop"] = l
- d = self.playerInput("Enter markup/markdown percentage: ", 3)
- d.addCallback(self.save_mark)
- def save_mark(self, mark):
- log.msg("save_mark {0}".format(mark))
- if mark.strip() == "":
- self.script["mark"] = 5
- else:
- self.script["mark"] = int(mark.strip())
- # Ok, we have the values we need to run the Port trade script
- self.queue_game.put(pformat(self.script).replace("\n", "\n\r"))
- self.unscript()
- def playerInput(self, prompt, limit):
- """ Given a prompt and limit, this handles user input.
- This displays the prompt, and sets up the proper
- observers, while preserving the "current" ones.
- This returns a deferred, so you can chain the results
- of this.
- """
- log.msg("playerInput({0}, {1}".format(prompt, limit))
- nl = "\n\r"
- c = merge(Style.BRIGHT + Fore.WHITE + Back.BLUE)
- r = Style.RESET_ALL
- self.queue_game.put(r + nl + c + prompt)
- # This should set the background and show the size of the entry area.
- self.queue_game.put(" " * limit + "\b" * limit)
- d = defer.Deferred()
- self.player_input = d
- self.input_limit = limit
- self.input_input = ""
- self.save = self.observer.save()
- self.observer.connect("player", self.niceInput)
- # input_funcs = { 'player': [self.niceInput] }
- # self.observer.set_funcs(input_funcs)
- return d
- def niceInput(self, chunk):
- """ Data from player (in bytes). """
- chunk = chunk.decode("utf-8", "ignore")
- # log.msg("niceInput:", repr(chunk))
- r = Style.RESET_ALL
- for c in chunk:
- if c == "\b":
- # Backspace
- if len(self.input_input) > 0:
- self.queue_game.put("\b \b")
- self.input_input = self.input_input[0:-1]
- else:
- # Can't
- self.queue_game.put("\a")
- if c == "\r":
- # Ok, completed!
- self.queue_game.put(r + "\n\r")
- self.observer.load(self.save)
- self.save = None
- line = self.input_input
- log.msg("finishing niceInput {0}".format(line))
- # self.queue_game.put("[{0}]\n\r".format(line))
- self.input_input = ""
- # Ok, maybe this isn't the way to do this ...
- # self.player_input.callback(line)
- reactor.callLater(0, self.player_input.callback, line)
- self.player_input = None
- if c.isprintable():
- if len(self.input_input) + 1 <= self.input_limit:
- self.input_input += c
- self.queue_game.put(c)
- else:
- # Limit reached
- self.queue_game.put("\a")
|