| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919 | 
							- #!/usr/bin/env python3
 
- import sys
 
- import re
 
- from twisted.internet import defer
 
- from twisted.internet import protocol
 
- from twisted.internet import reactor
 
- from twisted.internet import task
 
- from twisted.python import log
 
- from twisted.python.logfile import DailyLogFile
 
- import pendulum
 
- from subprocess import check_output
 
- from colorama import Fore, Back, Style
 
- from itertools import cycle
 
- from deprecated import deprecated
 
- from pprint import pformat
 
- # This isn't the best configuration, but it's simple
 
- # and works.  Mostly.
 
- try:
 
-     from config_dev import *
 
- except ModuleNotFoundError:
 
-     from config import *
 
- # Extract the version information from git.
 
- # The match gives us only tags starting with v[0-9]*  Using anything else trips up on double digits.
 
- version = check_output(
 
-     [
 
-         "git",
 
-         "describe",
 
-         "--abbrev=8",
 
-         "--long",
 
-         "--tags",
 
-         "--dirty",
 
-         "--always",
 
-         "--match",
 
-         "v[0-9]*",
 
-     ],
 
-     universal_newlines=True,
 
- ).strip()
 
- def merge(color_string):
 
-     """ Given a string of colorama ANSI, merge them if you can. """
 
-     return color_string.replace("m\x1b[", ";")
 
- # https://en.wikipedia.org/wiki/ANSI_escape_code
 
- # Cleans all ANSI
 
- cleaner = re.compile(r"\x1b\[[0-9;]*[A-Zmh]")
 
- # Looks for ANSI (that should be considered to be a newline)
 
- # This needs to see what is send when something enters / leaves
 
- # the player's current sector.  (That doesn't work/isn't
 
- # detected.  NNY!)  It is "\x1b[K" Erase in Line!
 
- makeNL = re.compile(r"\x1b\[[0-9;]*[JK]")
 
- def treatAsNL(line):
 
-     """ Replace any ANSI codes that would be better understood as newlines. """
 
-     global makeNL
 
-     return makeNL.sub("\n", line)
 
- def cleanANSI(line):
 
-     """ Remove all ANSI codes. """
 
-     global cleaner
 
-     return cleaner.sub("", line)
 
-     # return re.sub(r'\x1b\[([0-9,A-Z]{1,2}(;[0-9]{1,2})?(;[0-9]{3})?)?[m|K]?', '', 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() }
 
- from observer import Observer
 
- class PlayerInput(object):
 
-     def __init__(self, game):
 
-         # I think game gives us access to everything we need
 
-         self.game = game
 
-         self.observer = self.game.observer
 
-         self.save = None
 
-         self.defer = None
 
-         self.game_queue = game.game_queue
 
-         # default colors, and useful consts
 
-         self.c = merge(Style.BRIGHT + Fore.WHITE + Back.BLUE)
 
-         self.r = Style.RESET_ALL
 
-         self.nl = "\n\r"
 
-         self.bsb = "\b \b"
 
-         self.keepalive = None
 
-     def color(self, c):
 
-         self.c = c
 
-     def awake(self):
 
-         log.msg("PlayerInput.awake()")
 
-         self.game.queue_player.put(" ")
 
-     def prompt(self, prompt, limit, default=''):
 
-         log.msg("PlayerInput({0}, {1}, {2}".format(prompt, limit, default))
 
-         self.prompt = prompt
 
-         self.limit = limit
 
-         self.default = default
 
-         self.input = ''
 
-         assert(self.save is None)
 
-         assert(self.keepalive is None)
 
-         # Note: This clears out the server "keep alive"
 
-         self.save = self.observer.save()
 
-         self.observer.connect('player', self.input)
 
-         self.keepalive = task.LoopingCall(self.awake)
 
-         self.keepalive.start(30)
 
-         # We need to "hide" the game output.
 
-         # Otherwise it WITH mess up the user input display.
 
-         self.to_player = self.game.to_player
 
-         self.game.to_player = False
 
-         # Display prompt
 
-         self.queue_game.put(self.r + self.nl + self.c + prompt)
 
-         # Set "Background of prompt"
 
-         self.queue_game.put( " " * limit + "\b" * limit)
 
-         assert(self.defer is None)
 
-         d = defer.Deferred()
 
-         self.defer = d
 
-         return d
 
-     def input(self, chunk):
 
-         """ Data from player (in bytes) """
 
-         chunk = chunk.decode('utf-8', 'ignore')
 
-         for ch in chunk:
 
-             if ch == "\b":
 
-                 if len(self.input) > 0:
 
-                     self.queue_game.put(self.bsb)
 
-                     self.input = self.input[0:-1]
 
-                 else:
 
-                     self.queue_game.put("\a")
 
-             if ch == "'\r":
 
-                 self.queue_game.put(self.r + self.nl)
 
-                 assert(not self.save is None)
 
-                 self.observer.load(self.save)
 
-                 self.save = None
 
-                 self.keepalive.stop()
 
-                 self.keepalive = None
 
-                 line = self.input
 
-                 self.input = ''
 
-                 assert(not self.defer is None)
 
-                 reactor.callLater(0, self.defer.callback, line)
 
-                 self.defer = None
 
-             if ch.isprintable():
 
-                 if len(self.input) + 1 <= self.limit:
 
-                     self.input += c
 
-                     self.queue_game.put(ch)
 
-                 else:
 
-                     self.queue_game.put("\a")
 
-     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)
 
-         return line
 
- class ProxyMenu(object):
 
-     def __init__(self, game):
 
-         self.nl = "\n\r"
 
-         self.c = merge(Style.BRIGHT + Fore.YELLOW + Back.BLUE)
 
-         self.r = Style.RESET_ALL
 
-         self.c1 = merge(Style.BRIGHT + Fore.BLUE)
 
-         self.c2 = merge(Style.NORMAL + Fore.BLUE)
 
-         self.game = game
 
-         self.queue_game = game.queue_game
 
-         self.observer = game.observer
 
-         # Yes, at this point we would activate
 
-         self.prompt = game.buffer
 
-         self.save = self.observer.save()
 
-         self.observer.connect("player", self.player)
 
-         # If we want it, it's here.
 
-         self.defer = None
 
-         self.keepalive = task.LoopingCall(self.awake)
 
-         self.keepalive.start(30)
 
-         self.menu()
 
-     def __del__(self):
 
-         log.msg("ProxyMenu {0} RIP".format(self))
 
-     def whenDone(self):
 
-         self.defer = defer.Deferred()
 
-         # Call this to chain something after we exit.
 
-         return self.defer
 
-     def menu(self):
 
-         self.queue_game.put(self.nl + self.c + "TradeWars Proxy active." + self.r + self.nl)
 
-         self.queue_game.put(" " + self.c1 + "D" + self.c2 + " - " + self.c1 + "Diagnostics" + self.nl)        
 
-         self.queue_game.put(
 
-             " " + self.c1 + "T" + self.c2 + " - " + self.c1 + "Display current Time" + self.nl
 
-         )
 
-         self.queue_game.put(" " + self.c1 + "P" + self.c2 + " - " + self.c1 + "Port CIM Report" + self.nl)
 
-         self.queue_game.put(" " + self.c1 + "S" + self.c2 + " - " + self.c1 + "Scripts" + self.nl)
 
-         self.queue_game.put(" " + self.c1 + "X" + self.c2 + " - " + self.c1 + "eXit" + self.nl)
 
-         self.queue_game.put("   " + self.c + "-=>" + self.r + " ")
 
-     def awake(self):
 
-         log.msg("ProxyMenu.awake()")
 
-         self.game.queue_player.put(" ")
 
-     def player(self, chunk):
 
-         """ Data from player (in bytes). """
 
-         chunk = chunk.decode("utf-8", 'ignore')
 
-         key = chunk.upper()
 
-         log.msg("ProxyMenu.player({0})".format(key))
 
-         # Weird / long running task / something odd happening here?
 
-         self.keepalive.stop()
 
-         if key == "T":
 
-             self.queue_game.put(self.c + key + self.r + self.nl)
 
-             # perform T option
 
-             now = pendulum.now()
 
-             self.queue_game.put(self.nl + self.c1 + "Current time " + now.to_datetime_string() + self.nl)
 
-         elif key == 'X':
 
-             self.queue_game.put(self.c + key + self.r + self.nl)
 
-             self.observer.load(self.save)
 
-             self.save = None
 
-             # It isn't running (NOW), so don't try to stop it.
 
-             # self.keepalive.stop()
 
-             self.keepalive = None
 
-             self.queue_game.put(self.prompt)
 
-             self.prompt = None
 
-             if self.defer:
 
-                 self.defer.callback()
 
-                 self.defer = None
 
-             return
 
-         self.keepalive.start(30, True)
 
-         self.menu()
 
- 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")
 
- class Game(protocol.Protocol):
 
-     def __init__(self):
 
-         self.buffer = ""
 
-         self.game = None
 
-         self.usergame = (None, None)
 
-         self.to_player = True
 
-         self.mcp = MCP(self)
 
-     def connectionMade(self):
 
-         log.msg("Connected to Game Server")
 
-         self.queue_player = self.factory.queue_player
 
-         self.queue_game = self.factory.queue_game
 
-         self.observer = self.factory.observer
 
-         self.factory.game = self
 
-         self.setPlayerReceived()
 
-         self.observer.connect("user-game", self.show_game)
 
-         self.mcp.finishSetup()
 
-     def show_game(self, game):
 
-         self.usergame = game
 
-         log.msg("## User-Game:", game)
 
-     def setPlayerReceived(self):
 
-         """ Get deferred from client queue, callback clientDataReceived. """
 
-         self.queue_player.get().addCallback(self.playerDataReceived)
 
-     def playerDataReceived(self, chunk):
 
-         if chunk is False:
 
-             self.queue_player = None
 
-             log.msg("Player: disconnected, close connection to game")
 
-             # I don't believe I need this if I'm using protocol.Factory
 
-             self.factory.continueTrying = False
 
-             self.transport.loseConnection()
 
-         else:
 
-             # Pass received data to the server
 
-             if type(chunk) == str:
 
-                 self.transport.write(chunk.encode())
 
-             else:
 
-                 self.transport.write(chunk)
 
-             self.setPlayerReceived()
 
-     def lineReceived(self, line):
 
-         """ line received from the game. """
 
-         if LOG_LINES:
 
-             log.msg(">> [{0}]".format(line))
 
-         if "TWGS v2.20b" in line and "www.eisonline.com" in line:
 
-             self.queue_game.put(
 
-                 "TWGS Proxy build "
 
-                 + version
 
-                 + " is active. \x1b[1;34m~\x1b[0m to activate.\n\r\n\r",
 
-             )
 
-         if "TradeWars Game Server" in line and "Copyright (C) EIS" in line:
 
-             # We are not in a game
 
-             if not self.game is None:
 
-                 # We were in a game.
 
-                 self.game = None
 
-                 self.observer.emit("user-game", (self.factory.player.user, self.game))
 
-         if "Selection (? for menu): " in line:
 
-             game = line[-1]
 
-             if game >= "A" and game < "Q":
 
-                 self.game = game
 
-                 log.msg("Game: {0}".format(self.game))
 
-                 self.observer.emit("user-game", (self.factory.player.user, self.game))
 
-         self.observer.emit("game-line", line)
 
-     def getPrompt(self):
 
-         """ Return the current prompt, stripped of ANSI. """
 
-         return cleanANSI(self.buffer)
 
-     def dataReceived(self, chunk):
 
-         """ Data received from the Game. 
 
-         
 
-         Remove backspaces.
 
-         Treat some ANSI codes as NewLine.        
 
-         Remove ANSI.
 
-         Break into lines.
 
-         Trim out carriage returns.
 
-         Call lineReceived().
 
-         
 
-         "Optionally" pass data to player.
 
-         FUTURE: trigger on prompt. [cleanANSI(buffer)]
 
-         """
 
-         # Sequence error:
 
-         # If I don't put the chunk(I received) to the player.
 
-         # anything I display -- lineReceive() put() ... would
 
-         # be out of order.  (I'd be responding -- before it
 
-         # was displayed to the user.)
 
-         if self.to_player:
 
-             self.queue_game.put(chunk)
 
-         self.buffer += chunk.decode("utf-8", "ignore")
 
-         # Process any backspaces
 
-         while "\b" in self.buffer:
 
-             part = self.buffer.partition("\b")
 
-             self.buffer = part[0][:-1] + part[2]
 
-         # Treat some ANSI codes as a newline
 
-         self.buffer = treatAsNL(self.buffer)
 
-         # Break into lines
 
-         while "\n" in self.buffer:
 
-             part = self.buffer.partition("\n")
 
-             line = part[0].replace("\r", "")
 
-             # Clean ANSI codes from line
 
-             line = cleanANSI(line)
 
-             self.lineReceived(line)
 
-             self.buffer = part[2]
 
-         self.observer.emit("prompt", self.getPrompt())
 
-     def connectionLost(self, why):
 
-         log.msg("Game connectionLost because: %s" % why)
 
-         self.observer.emit('close', why)
 
-         self.queue_game.put(False)
 
-         self.transport.loseConnection()
 
- class GlueFactory(protocol.ClientFactory):
 
-     # class GlueFactory(protocol.Factory):
 
-     maxDelay = 10
 
-     protocol = Game
 
-     def __init__(self, player):
 
-         self.player = player
 
-         self.queue_player = player.queue_player
 
-         self.queue_game = player.queue_game
 
-         self.observer = player.observer
 
-         self.game = None
 
-     def closeIt(self):
 
-         log.msg("closeIt")
 
-         self.queue_game.put(False)
 
-     def getUser(self, user):
 
-         log.msg("getUser( %s )" % user)
 
-         self.twgs.logUser(user)
 
-     # This was needed when I replaced ClientFactory with Factory.
 
-     # def clientConnectionLost(self, connector, why):
 
-     #     log.msg("clientconnectionlost: %s" % why)
 
-     #     self.queue_client.put(False)
 
-     def clientConnectionFailed(self, connector, why):
 
-         log.msg("connection to game failed: %s" % why)
 
-         self.queue_game.put(b"Sorry!  I'm Unable to connect to the game server.\r\n")
 
-         # syncterm gets cranky/locks up if we close this here.
 
-         # (Because it is still sending rlogin information?)
 
-         reactor.callLater(2, self.closeIt)
 
- class Player(protocol.Protocol):
 
-     def __init__(self):
 
-         self.buffer = ""
 
-         self.user = None
 
-         self.observer = Observer()
 
-         self.game = None
 
-         self.glue = None
 
-     def connectionMade(self):
 
-         """ connected, setup queues. 
 
-         
 
-         queue_player is data from player.
 
-         queue_game is data to player. (possibly from game)
 
-         """
 
-         self.queue_player = defer.DeferredQueue()
 
-         self.queue_game = defer.DeferredQueue()
 
-         self.setGameReceived()
 
-         # Connect GlueFactory to this Player object.
 
-         factory = GlueFactory(self)
 
-         self.glue = factory
 
-         # Make connection to the game server
 
-         reactor.connectTCP(HOST, PORT, factory, 5)
 
-     def setGameReceived(self):
 
-         """ Get deferred from client queue, callback clientDataReceived. """
 
-         self.queue_game.get().addCallback(self.gameDataReceived)
 
-     def gameDataReceived(self, chunk):
 
-         """ Data received from the game. """
 
-         # If we have received game data, it has to be connected.
 
-         if self.game is None:
 
-             self.game = self.glue.game
 
-         if chunk is False:
 
-             self.transport.loseConnection()
 
-         else:
 
-             if type(chunk) == bytes:
 
-                 self.transport.write(chunk)
 
-             elif type(chunk) == str:
 
-                 self.transport.write(chunk.encode())
 
-             else:
 
-                 log.err("gameDataReceived: type (%s) given!", type(chunk))
 
-                 self.transport.write(chunk)
 
-             self.setGameReceived()
 
-     def dataReceived(self, chunk):
 
-         if self.user is None:
 
-             self.buffer += chunk.decode("utf-8", "ignore")
 
-             parts = self.buffer.split("\x00")
 
-             if len(parts) >= 5:
 
-                 # rlogin we have the username
 
-                 self.user = parts[1]
 
-                 log.msg("User: {0}".format(self.user))
 
-                 zpos = self.buffer.rindex("\x00")
 
-                 self.buffer = self.buffer[zpos + 1 :]
 
-                 # but I don't need the buffer anymore, so:
 
-                 self.buffer = ""
 
-                 # Pass user value on to whatever needs it.
 
-                 self.observer.emit("user", self.user)
 
-                 # Unfortunately, the ones interested in this don't exist yet.
 
-         if not self.observer.emit("player", chunk):
 
-             # Was not dispatched.  Send to game.
 
-             self.queue_player.put(chunk)
 
-         
 
-         else:
 
-             # There's an observer.  Don't continue.
 
-             return
 
-         if chunk == b"~":
 
-             if self.game:
 
-                 prompt = self.game.getPrompt()
 
-                 if re.match(r"Command \[TL=.* \(\?=Help\)\? :", prompt):
 
-                     self.observer.emit("hotkey", prompt)
 
-                 else:
 
-                     self.observer.emit("notyet", prompt)
 
-             # Selection (? for menu):   (the game server menu)
 
-             # Enter your choice:  (game menu)
 
-             # Command [TL=00:00:00]:[1800] (?=Help)? :  <- YES!
 
-             # Computer command [TL=00:00:00]:[613] (?=Help)?
 
-         if chunk == b"|":
 
-             # how can I tell if this is active or not?
 
-             # I no longer see a 'player' observer.  GOOD!
 
-             # log.msg(pformat(self.observer.dispatch))
 
-             # prompt = self.game.getPrompt()
 
-             # if re.match(r"Command \[TL=.* \(\?=Help\)\? :", prompt):
 
-             menu = ProxyMenu(self.game)
 
-     def connectionLost(self, why):
 
-         log.msg("lost connection %s" % why)
 
-         self.observer.emit('close', why)        
 
-         self.queue_player.put(False)
 
-     def connectionFailed(self, why):
 
-         log.msg("connectionFailed: %s" % why)
 
- if __name__ == "__main__":
 
-     if LOGFILE:
 
-         log.startLogging(DailyLogFile("proxy.log", "."))
 
-     else:
 
-         log.startLogging(sys.stdout)
 
-     log.msg("This is version: %s" % version)
 
-     factory = protocol.Factory()
 
-     factory.protocol = Player
 
-     reactor.listenTCP(LISTEN_PORT, factory, interface=LISTEN_ON)
 
-     reactor.run()
 
 
  |