Tests for deep space probes.
[super-star-trek.git] / sst.py
diff --git a/sst.py b/sst.py
old mode 100644 (file)
new mode 100755 (executable)
index 5bc4bac..e2bf5c3
--- a/sst.py
+++ b/sst.py
@@ -13,11 +13,12 @@ on how to modify (and how not to modify!) this code.
 """
 import os, sys, math, curses, time, readline, cPickle, random, copy, gettext, getpass
 
 """
 import os, sys, math, curses, time, readline, cPickle, random, copy, gettext, getpass
 
-version="2.0"
+version = "2.1"
 
 docpath        = (".", "../doc", "/usr/share/doc/sst")
 
 
 docpath        = (".", "../doc", "/usr/share/doc/sst")
 
-def _(str): return gettext.gettext(str)
+def _(st):
+    return gettext.gettext(st)
 
 GALSIZE        = 8             # Galaxy size in quadrants
 NINHAB         = (GALSIZE * GALSIZE / 2)       # Number of inhabited worlds
 
 GALSIZE        = 8             # Galaxy size in quadrants
 NINHAB         = (GALSIZE * GALSIZE / 2)       # Number of inhabited worlds
@@ -52,17 +53,20 @@ LIGHTMAGENTA = 13
 YELLOW       = 14
 WHITE        = 15
 
 YELLOW       = 14
 WHITE        = 15
 
-class TrekError:
+class TrekError(Exception):
     pass
 
     pass
 
-class coord:
+class JumpOut(Exception):
+    pass 
+
+class Coord:
     def __init__(self, x=None, y=None):
         self.i = x
         self.j = y
     def valid_quadrant(self):
     def __init__(self, x=None, y=None):
         self.i = x
         self.j = y
     def valid_quadrant(self):
-        return self.i>=0 and self.i<GALSIZE and self.j>=0 and self.j<GALSIZE
+        return self.i >= 0 and self.i < GALSIZE and self.j >= 0 and self.j < GALSIZE
     def valid_sector(self):
     def valid_sector(self):
-       return self.i>=0 and self.i<QUADSIZE and self.j>=0 and self.j<QUADSIZE
+       return self.i >= 0 and self.i < QUADSIZE and self.j >= 0 and self.j < QUADSIZE
     def invalidate(self):
         self.i = self.j = None
     def is_valid(self):
     def invalidate(self):
         self.i = self.j = None
     def is_valid(self):
@@ -72,28 +76,29 @@ class coord:
     def __ne__(self, other):
         return other == None or self.i != other.i or self.j != other.j
     def __add__(self, other):
     def __ne__(self, other):
         return other == None or self.i != other.i or self.j != other.j
     def __add__(self, other):
-        return coord(self.i+other.i, self.j+other.j)
+        return Coord(self.i+other.i, self.j+other.j)
     def __sub__(self, other):
     def __sub__(self, other):
-        return coord(self.i-other.i, self.j-other.j)
+        return Coord(self.i-other.i, self.j-other.j)
     def __mul__(self, other):
     def __mul__(self, other):
-        return coord(self.i*other, self.j*other)
+        return Coord(self.i*other, self.j*other)
     def __rmul__(self, other):
     def __rmul__(self, other):
-        return coord(self.i*other, self.j*other)
+        return Coord(self.i*other, self.j*other)
     def __div__(self, other):
     def __div__(self, other):
-        return coord(self.i/other, self.j/other)
+        return Coord(self.i/other, self.j/other)
     def __mod__(self, other):
     def __mod__(self, other):
-        return coord(self.i % other, self.j % other)
+        return Coord(self.i % other, self.j % other)
     def __rdiv__(self, other):
     def __rdiv__(self, other):
-        return coord(self.i/other, self.j/other)
+        return Coord(self.i/other, self.j/other)
     def roundtogrid(self):
     def roundtogrid(self):
-        return coord(int(round(self.i)), int(round(self.j)))
+        return Coord(int(round(self.i)), int(round(self.j)))
     def distance(self, other=None):
     def distance(self, other=None):
-        if not other: other = coord(0, 0)
+        if not other:
+            other = Coord(0, 0)
         return math.sqrt((self.i - other.i)**2 + (self.j - other.j)**2)
     def bearing(self):
         return 1.90985*math.atan2(self.j, self.i)
     def sgn(self):
         return math.sqrt((self.i - other.i)**2 + (self.j - other.j)**2)
     def bearing(self):
         return 1.90985*math.atan2(self.j, self.i)
     def sgn(self):
-        s = coord()
+        s = Coord()
         if self.i == 0:
             s.i = 0
         else:
         if self.i == 0:
             s.i = 0
         else:
@@ -109,7 +114,7 @@ class coord:
     def sector(self):
         return self.roundtogrid() % QUADSIZE
     def scatter(self):
     def sector(self):
         return self.roundtogrid() % QUADSIZE
     def scatter(self):
-        s = coord()
+        s = Coord()
         s.i = self.i + randrange(-1, 2)
         s.j = self.j + randrange(-1, 2)
         return s
         s.i = self.i + randrange(-1, 2)
         s.j = self.j + randrange(-1, 2)
         return s
@@ -119,18 +124,28 @@ class coord:
         return "%s - %s" % (self.i+1, self.j+1)
     __repr__ = __str__
 
         return "%s - %s" % (self.i+1, self.j+1)
     __repr__ = __str__
 
-class planet:
+class Thingy(Coord):
+    "Do not anger the Space Thingy!"
+    def __init__(self):
+        Coord.__init__(self)
+        self.angered = False
+    def angry(self):
+        self.angered = True
+    def at(self, q):
+        return (q.i, q.j) == (self.i, self.j)
+
+class Planet:
     def __init__(self):
         self.name = None       # string-valued if inhabited
     def __init__(self):
         self.name = None       # string-valued if inhabited
-        self.quadrant = coord()        # quadrant located
+        self.quadrant = Coord()        # quadrant located
         self.pclass = None     # could be ""M", "N", "O", or "destroyed"
         self.crystals = "absent"# could be "mined", "present", "absent"
         self.known = "unknown" # could be "unknown", "known", "shuttle_down"
         self.pclass = None     # could be ""M", "N", "O", or "destroyed"
         self.crystals = "absent"# could be "mined", "present", "absent"
         self.known = "unknown" # could be "unknown", "known", "shuttle_down"
-        self.inhabited = False # is it inhabites?
+        self.inhabited = False # is it inhabited?
     def __str__(self):
         return self.name
 
     def __str__(self):
         return self.name
 
-class quadrant:
+class Quadrant:
     def __init__(self):
         self.stars = 0
         self.planet = None
     def __init__(self):
         self.stars = 0
         self.planet = None
@@ -141,11 +156,13 @@ class quadrant:
        self.charted = False
         self.status = "secure" # Could be "secure", "distressed", "enslaved"
 
        self.charted = False
         self.status = "secure" # Could be "secure", "distressed", "enslaved"
 
-class page:
+class Page:
     def __init__(self):
        self.stars = None
     def __init__(self):
        self.stars = None
-       self.starbase = None
+       self.starbase = False
        self.klingons = None
        self.klingons = None
+    def __repr__(self):
+        return "<%s,%s,%s>" % (self.klingons, self.starbase, self.stars)
 
 def fill2d(size, fillfun):
     "Fill an empty list in 2D."
 
 def fill2d(size, fillfun):
     "Fill an empty list in 2D."
@@ -156,7 +173,7 @@ def fill2d(size, fillfun):
             lst[i].append(fillfun(i, j))
     return lst
 
             lst[i].append(fillfun(i, j))
     return lst
 
-class snapshot:
+class Snapshot:
     def __init__(self):
         self.snap = False      # snapshot taken
         self.crew = 0          # crew complement
     def __init__(self):
         self.snap = False      # snapshot taken
         self.crew = 0          # crew complement
@@ -173,13 +190,13 @@ class snapshot:
        self.remtime = 0        # remaining time
         self.baseq = []        # Base quadrant coordinates
         self.kcmdr = []        # Commander quadrant coordinates
        self.remtime = 0        # remaining time
         self.baseq = []        # Base quadrant coordinates
         self.kcmdr = []        # Commander quadrant coordinates
-       self.kscmdr = coord()   # Supercommander quadrant coordinates
+       self.kscmdr = Coord()   # Supercommander quadrant coordinates
         # the galaxy
         # the galaxy
-        self.galaxy = fill2d(GALSIZE, lambda i, j: quadrant())
+        self.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
         # the starchart
         # the starchart
-       self.chart = fill2d(GALSIZE, lambda i, j: page())
+       self.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
 
 
-class event:
+class Event:
     def __init__(self):
         self.date = None       # A real number
         self.quadrant = None   # A coord structure
     def __init__(self):
         self.date = None       # A real number
         self.quadrant = None   # A coord structure
@@ -205,23 +222,23 @@ OPTION_ALMY       = 0x02000000    # user chose Almy variant
 OPTION_COLOR    = 0x04000000   # enable color display (experimental, ESR, 2010)
 
 # Define devices 
 OPTION_COLOR    = 0x04000000   # enable color display (experimental, ESR, 2010)
 
 # Define devices 
-DSRSENS        = 0
-DLRSENS        = 1
-DPHASER        = 2
-DPHOTON        = 3
-DLIFSUP        = 4
-DWARPEN        = 5
-DIMPULS        = 6
-DSHIELD        = 7
-DRADIO = 0
-DSHUTTL = 9
-DCOMPTR = 10
-DNAVSYS        = 11
-DTRANSP = 12
-DSHCTRL        = 13
-DDRAY  = 14
-DDSP   = 15
-NDEVICES= 16   # Number of devices
+DSRSENS         = 0
+DLRSENS         = 1
+DPHASER         = 2
+DPHOTON         = 3
+DLIFSUP         = 4
+DWARPEN         = 5
+DIMPULS         = 6
+DSHIELD         = 7
+DRADIO  = 0
+DSHUTTL  = 9
+DCOMPTR  = 10
+DNAVSYS         = 11
+DTRANSP  = 12
+DSHCTRL         = 13
+DDRAY   = 14
+DDSP    = 15
+NDEVICES = 16  # Number of devices
 
 SKILL_NONE     = 0
 SKILL_NOVICE   = 1
 
 SKILL_NONE     = 0
 SKILL_NOVICE   = 1
@@ -230,8 +247,10 @@ SKILL_GOOD = 3
 SKILL_EXPERT   = 4
 SKILL_EMERITUS = 5
 
 SKILL_EXPERT   = 4
 SKILL_EMERITUS = 5
 
-def damaged(dev):      return (game.damage[dev] != 0.0)
-def communicating():   return not damaged(DRADIO) or game.condition=="docked"
+def damaged(dev):
+    return (game.damage[dev] != 0.0)
+def communicating():
+    return not damaged(DRADIO) or game.condition=="docked"
 
 # Define future events 
 FSPY   = 0     # Spy event happens always (no future[] entry)
 
 # Define future events 
 FSPY   = 0     # Spy event happens always (no future[] entry)
@@ -251,12 +270,15 @@ NEVENTS   = 12
 
 # Abstract out the event handling -- underlying data structures will change
 # when we implement stateful events 
 
 # Abstract out the event handling -- underlying data structures will change
 # when we implement stateful events 
-def findevent(evtype): return game.future[evtype]
+def findevent(evtype):
+    return game.future[evtype]
 
 
-class enemy:
-    def __init__(self, type=None, loc=None, power=None):
-        self.type = type
-        self.location = coord()
+class Enemy:
+    def __init__(self, etype=None, loc=None, power=None):
+        self.type = etype
+        self.location = Coord()
+        self.kdist = None
+        self.kavgd = None
         if loc:
             self.move(loc)
         self.power = power     # enemy energy level
         if loc:
             self.move(loc)
         self.power = power     # enemy energy level
@@ -274,24 +296,26 @@ class enemy:
             game.quad[self.location.i][self.location.j] = self.type
             self.kdist = self.kavgd = (game.sector - loc).distance()
         else:
             game.quad[self.location.i][self.location.j] = self.type
             self.kdist = self.kavgd = (game.sector - loc).distance()
         else:
-            self.location = coord()
+            self.location = Coord()
             self.kdist = self.kavgd = None
             game.enemies.remove(self)
         return motion
     def __repr__(self):
         return "<%s,%s.%f>" % (self.type, self.location, self.power)   # For debugging
 
             self.kdist = self.kavgd = None
             game.enemies.remove(self)
         return motion
     def __repr__(self):
         return "<%s,%s.%f>" % (self.type, self.location, self.power)   # For debugging
 
-class gamestate:
+class Gamestate:
     def __init__(self):
         self.options = None    # Game options
     def __init__(self):
         self.options = None    # Game options
-        self.state = snapshot()        # A snapshot structure
-        self.snapsht = snapshot()      # Last snapshot taken for time-travel purposes
+        self.state = Snapshot()        # A snapshot structure
+        self.snapsht = Snapshot()      # Last snapshot taken for time-travel purposes
         self.quad = None       # contents of our quadrant
         self.damage = [0.0] * NDEVICES # damage encountered
         self.quad = None       # contents of our quadrant
         self.damage = [0.0] * NDEVICES # damage encountered
-        self.future = []               # future events
-        for i in range(NEVENTS):
-            self.future.append(event())
-        self.passwd  = None;           # Self Destruct password
+        self.future = []       # future events
+        i = NEVENTS
+        while i > 0:
+            i -= 1
+            self.future.append(Event())
+        self.passwd  = None    # Self Destruct password
         self.enemies = []
         self.quadrant = None   # where we are in the large
         self.sector = None     # where we are in the small
         self.enemies = []
         self.quadrant = None   # where we are in the large
         self.sector = None     # where we are in the small
@@ -358,6 +382,10 @@ class gamestate:
         self.cryprob = 0.0     # probability that crystal will work
         self.probe = None      # object holding probe course info
         self.height = 0.0      # height of orbit around planet
         self.cryprob = 0.0     # probability that crystal will work
         self.probe = None      # object holding probe course info
         self.height = 0.0      # height of orbit around planet
+        self.score = 0.0       # overall score
+        self.perdate = 0.0     # rate of kills
+        self.idebug = False    # Debugging instrumentation enabled?
+        self.statekscmdr = None # No SuperCommander coordinates yet.
     def recompute(self):
         # Stas thinks this should be (C expression): 
         # game.state.remkl + len(game.state.kcmdr) > 0 ?
     def recompute(self):
         # Stas thinks this should be (C expression): 
         # game.state.remkl + len(game.state.kcmdr) > 0 ?
@@ -365,7 +393,7 @@ class gamestate:
         # He says the existing expression is prone to divide-by-zero errors
         # after killing the last klingon when score is shown -- perhaps also
         # if the only remaining klingon is SCOM.
         # He says the existing expression is prone to divide-by-zero errors
         # after killing the last klingon when score is shown -- perhaps also
         # if the only remaining klingon is SCOM.
-        game.state.remtime = game.state.remres/(game.state.remkl + 4*len(game.state.kcmdr))
+        self.state.remtime = self.state.remres/(self.state.remkl + 4*len(self.state.kcmdr))
 
 FWON = 0
 FDEPLETE = 1
 
 FWON = 0
 FDEPLETE = 1
@@ -414,30 +442,25 @@ def welcoming(iq):
 
 def tryexit(enemy, look, irun):
     "A bad guy attempts to bug out."
 
 def tryexit(enemy, look, irun):
     "A bad guy attempts to bug out."
-    iq = coord()
+    iq = Coord()
     iq.i = game.quadrant.i+(look.i+(QUADSIZE-1))/QUADSIZE - 1
     iq.j = game.quadrant.j+(look.j+(QUADSIZE-1))/QUADSIZE - 1
     if not welcoming(iq):
     iq.i = game.quadrant.i+(look.i+(QUADSIZE-1))/QUADSIZE - 1
     iq.j = game.quadrant.j+(look.j+(QUADSIZE-1))/QUADSIZE - 1
     if not welcoming(iq):
-       return False;
+       return False
     if enemy.type == 'R':
     if enemy.type == 'R':
-       return False; # Romulans cannot escape! 
+       return False # Romulans cannot escape! 
     if not irun:
        # avoid intruding on another commander's territory 
        if enemy.type == 'C':
             if iq in game.state.kcmdr:
     if not irun:
        # avoid intruding on another commander's territory 
        if enemy.type == 'C':
             if iq in game.state.kcmdr:
-                return False
+                return []
            # refuse to leave if currently attacking starbase 
            if game.battle == game.quadrant:
            # refuse to leave if currently attacking starbase 
            if game.battle == game.quadrant:
-               return False
+               return []
        # don't leave if over 1000 units of energy 
        if enemy.power > 1000.0:
        # don't leave if over 1000 units of energy 
        if enemy.power > 1000.0:
-           return False
-    # emit escape message and move out of quadrant.
-    # we know this if either short or long range sensors are working
-    if not damaged(DSRSENS) or not damaged(DLRSENS) or \
-       game.condition == "docked":
-       prout(crmena(True, enemy.type, "sector", enemy.location) + \
-              (_(" escapes to Quadrant %s (and regains strength).") % q))
+           return []
+    oldloc = copy.copy(enemy.location)
     # handle local matters related to escape
     enemy.move(None)
     game.klhere -= 1
     # handle local matters related to escape
     enemy.move(None)
     game.klhere -= 1
@@ -446,19 +469,20 @@ def tryexit(enemy, look, irun):
     # Handle global matters related to escape 
     game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
     game.state.galaxy[iq.i][iq.j].klingons += 1
     # Handle global matters related to escape 
     game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
     game.state.galaxy[iq.i][iq.j].klingons += 1
-    if enemy.type=='S':
+    if enemy.type == 'S':
        game.iscate = False
        game.ientesc = False
        game.isatb = 0
        schedule(FSCMOVE, 0.2777)
        unschedule(FSCDBAS)
        game.iscate = False
        game.ientesc = False
        game.isatb = 0
        schedule(FSCMOVE, 0.2777)
        unschedule(FSCDBAS)
-       game.state.kscmdr=iq
+       game.state.kscmdr = iq
     else:
        for cmdr in game.state.kcmdr:
            if cmdr == game.quadrant:
     else:
        for cmdr in game.state.kcmdr:
            if cmdr == game.quadrant:
-               game.state.kcmdr[n] = iq
+               game.state.kcmdr.append(iq)
                break
                break
-    return True; # success 
+    # report move out of quadrant.
+    return [(True, enemy, oldloc, ibq)]
 
 # The bad-guy movement algorithm:
 # 
 
 # The bad-guy movement algorithm:
 # 
@@ -500,17 +524,18 @@ def tryexit(enemy, look, irun):
 
 def movebaddy(enemy):
     "Tactical movement for the bad guys."
 
 def movebaddy(enemy):
     "Tactical movement for the bad guys."
-    next = coord(); look = coord()
+    goto = Coord()
+    look = Coord()
     irun = False
     # This should probably be just (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant) 
     if game.skill >= SKILL_EXPERT:
        nbaddys = (((game.quadrant in game.state.kcmdr)*2 + (game.state.kscmdr==game.quadrant)*2+game.klhere*1.23+game.irhere*1.5)/2.0)
     else:
        nbaddys = (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
     irun = False
     # This should probably be just (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant) 
     if game.skill >= SKILL_EXPERT:
        nbaddys = (((game.quadrant in game.state.kcmdr)*2 + (game.state.kscmdr==game.quadrant)*2+game.klhere*1.23+game.irhere*1.5)/2.0)
     else:
        nbaddys = (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
-    dist1 = enemy.kdist
-    mdist = int(dist1 + 0.5); # Nearest integer distance 
+    old_dist = enemy.kdist
+    mdist = int(old_dist + 0.5) # Nearest integer distance 
     # If SC, check with spy to see if should hi-tail it 
     # If SC, check with spy to see if should hi-tail it 
-    if enemy.type=='S' and \
+    if enemy.type == 'S' and \
        (enemy.power <= 500.0 or (game.condition=="docked" and not damaged(DPHOTON))):
        irun = True
        motion = -QUADSIZE
        (enemy.power <= 500.0 or (game.condition=="docked" and not damaged(DPHOTON))):
        irun = True
        motion = -QUADSIZE
@@ -518,7 +543,7 @@ def movebaddy(enemy):
        # decide whether to advance, retreat, or hold position 
        forces = enemy.power+100.0*len(game.enemies)+400*(nbaddys-1)
        if not game.shldup:
        # decide whether to advance, retreat, or hold position 
        forces = enemy.power+100.0*len(game.enemies)+400*(nbaddys-1)
        if not game.shldup:
-           forces += 1000; # Good for enemy if shield is down! 
+           forces += 1000 # Good for enemy if shield is down! 
        if not damaged(DPHASER) or not damaged(DPHOTON):
             if damaged(DPHASER): # phasers damaged 
                forces += 300.0
        if not damaged(DPHASER) or not damaged(DPHOTON):
             if damaged(DPHASER): # phasers damaged 
                forces += 300.0
@@ -536,14 +561,14 @@ def movebaddy(enemy):
            motion = ((forces + randreal(200))/150.0) - 5.0
        else:
             if forces > 1000.0: # Very strong -- move in for kill 
            motion = ((forces + randreal(200))/150.0) - 5.0
        else:
             if forces > 1000.0: # Very strong -- move in for kill 
-               motion = (1.0 - randreal())**2 * dist1 + 1.0
-           if game.condition=="docked" and (game.options & OPTION_BASE): # protected by base -- back off ! 
+               motion = (1.0 - randreal())**2 * old_dist + 1.0
+           if game.condition == "docked" and (game.options & OPTION_BASE): # protected by base -- back off ! 
                motion -= game.skill*(2.0-randreal()**2)
                motion -= game.skill*(2.0-randreal()**2)
-       if idebug:
+       if game.idebug:
            proutn("=== MOTION = %d, FORCES = %1.2f, " % (motion, forces))
        # don't move if no motion 
            proutn("=== MOTION = %d, FORCES = %1.2f, " % (motion, forces))
        # don't move if no motion 
-       if motion==0:
-           return
+       if motion == 0:
+           return []
        # Limit motion according to skill 
        if abs(motion) > game.skill:
             if motion < 0:
        # Limit motion according to skill 
        if abs(motion) > game.skill:
             if motion < 0:
@@ -553,12 +578,12 @@ def movebaddy(enemy):
     # calculate preferred number of steps 
     nsteps = abs(int(motion))
     if motion > 0 and nsteps > mdist:
     # calculate preferred number of steps 
     nsteps = abs(int(motion))
     if motion > 0 and nsteps > mdist:
-       nsteps = mdist; # don't overshoot 
+       nsteps = mdist # don't overshoot 
     if nsteps > QUADSIZE:
     if nsteps > QUADSIZE:
-       nsteps = QUADSIZE; # This shouldn't be necessary 
+       nsteps = QUADSIZE # This shouldn't be necessary 
     if nsteps < 1:
     if nsteps < 1:
-       nsteps = 1; # This shouldn't be necessary 
-    if idebug:
+       nsteps = 1 # This shouldn't be necessary 
+    if game.idebug:
        proutn("NSTEPS = %d:" % nsteps)
     # Compute preferred values of delta X and Y 
     m = game.sector - enemy.location
        proutn("NSTEPS = %d:" % nsteps)
     # Compute preferred values of delta X and Y 
     m = game.sector - enemy.location
@@ -567,13 +592,13 @@ def movebaddy(enemy):
     if 2.0 * abs(m.j) < abs(game.sector.i-enemy.location.i):
        m.j = 0
     m = (motion * m).sgn()
     if 2.0 * abs(m.j) < abs(game.sector.i-enemy.location.i):
        m.j = 0
     m = (motion * m).sgn()
-    next = enemy.location
+    goto = enemy.location
     # main move loop 
     for ll in range(nsteps):
     # main move loop 
     for ll in range(nsteps):
-       if idebug:
+       if game.idebug:
            proutn(" %d" % (ll+1))
        # Check if preferred position available 
            proutn(" %d" % (ll+1))
        # Check if preferred position available 
-       look = next + m
+       look = goto + m
         if m.i < 0:
             krawli = 1
         else:
         if m.i < 0:
             krawli = 1
         else:
@@ -583,70 +608,65 @@ def movebaddy(enemy):
         else:
             krawlj = -1
        success = False
         else:
             krawlj = -1
        success = False
-       attempts = 0; # Settle mysterious hang problem 
+       attempts = 0 # Settle mysterious hang problem 
        while attempts < 20 and not success:
             attempts += 1
            if look.i < 0 or look.i >= QUADSIZE:
        while attempts < 20 and not success:
             attempts += 1
            if look.i < 0 or look.i >= QUADSIZE:
-               if motion < 0 and tryexit(enemy, look, irun):
-                   return
+                if motion < 0:
+                   return tryexit(enemy, look, irun)
                if krawli == m.i or m.j == 0:
                    break
                if krawli == m.i or m.j == 0:
                    break
-               look.i = next.i + krawli
+               look.i = goto.i + krawli
                krawli = -krawli
            elif look.j < 0 or look.j >= QUADSIZE:
                krawli = -krawli
            elif look.j < 0 or look.j >= QUADSIZE:
-               if motion < 0 and tryexit(enemy, look, irun):
-                   return
+               if motion < 0:
+                   return tryexit(enemy, look, irun)
                if krawlj == m.j or m.i == 0:
                    break
                if krawlj == m.j or m.i == 0:
                    break
-               look.j = next.j + krawlj
+               look.j = goto.j + krawlj
                krawlj = -krawlj
            elif (game.options & OPTION_RAMMING) and game.quad[look.i][look.j] != '.':
                # See if enemy should ram ship 
                if game.quad[look.i][look.j] == game.ship and \
                    (enemy.type == 'C' or enemy.type == 'S'):
                    collision(rammed=True, enemy=enemy)
                krawlj = -krawlj
            elif (game.options & OPTION_RAMMING) and game.quad[look.i][look.j] != '.':
                # See if enemy should ram ship 
                if game.quad[look.i][look.j] == game.ship and \
                    (enemy.type == 'C' or enemy.type == 'S'):
                    collision(rammed=True, enemy=enemy)
-                   return
+                   return []
                if krawli != m.i and m.j != 0:
                if krawli != m.i and m.j != 0:
-                   look.i = next.i + krawli
+                   look.i = goto.i + krawli
                    krawli = -krawli
                elif krawlj != m.j and m.i != 0:
                    krawli = -krawli
                elif krawlj != m.j and m.i != 0:
-                   look.j = next.j + krawlj
+                   look.j = goto.j + krawlj
                    krawlj = -krawlj
                else:
                    krawlj = -krawlj
                else:
-                   break; # we have failed 
+                   break # we have failed 
            else:
                success = True
        if success:
            else:
                success = True
        if success:
-           next = look
-           if idebug:
-               proutn(`next`)
+           goto = look
+           if game.idebug:
+               proutn(repr(goto))
        else:
        else:
-           break; # done early 
-    if idebug:
+           break # done early 
+    if game.idebug:
        skip(1)
        skip(1)
-    if enemy.move(next):
-       if not damaged(DSRSENS) or game.condition == "docked":
-           proutn(_("*** %s from Sector %s") % (cramen(enemy.type), enemy.location))
-           if enemy.kdist < dist1:
-               proutn(_(" advances to "))
-           else:
-               proutn(_(" retreats to "))
-           prout("Sector %s." % next)
+    # Enemy moved, but is still in sector
+    return [(False, enemy, old_dist, goto)]
 
 def moveklings():
     "Sequence Klingon tactical movement."
 
 def moveklings():
     "Sequence Klingon tactical movement."
-    if idebug:
+    if game.idebug:
        prout("== MOVCOM")
     # Figure out which Klingon is the commander (or Supercommander)
     # and do move
        prout("== MOVCOM")
     # Figure out which Klingon is the commander (or Supercommander)
     # and do move
+    tacmoves = []
     if game.quadrant in game.state.kcmdr:
         for enemy in game.enemies:
            if enemy.type == 'C':
     if game.quadrant in game.state.kcmdr:
         for enemy in game.enemies:
            if enemy.type == 'C':
-               movebaddy(enemy)
-    if game.state.kscmdr==game.quadrant:
+               tacmoves += movebaddy(enemy)
+    if game.state.kscmdr == game.quadrant:
         for enemy in game.enemies:
            if enemy.type == 'S':
         for enemy in game.enemies:
            if enemy.type == 'S':
-               movebaddy(enemy)
+               tacmoves += movebaddy(enemy)
                break
     # If skill level is high, move other Klingons and Romulans too!
     # Move these last so they can base their actions on what the
                break
     # If skill level is high, move other Klingons and Romulans too!
     # Move these last so they can base their actions on what the
@@ -654,8 +674,8 @@ def moveklings():
     if game.skill >= SKILL_EXPERT and (game.options & OPTION_MVBADDY):
         for enemy in game.enemies:
             if enemy.type in ('K', 'R'):
     if game.skill >= SKILL_EXPERT and (game.options & OPTION_MVBADDY):
         for enemy in game.enemies:
             if enemy.type in ('K', 'R'):
-               movebaddy(enemy)
-    game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
+               tacmoves += movebaddy(enemy)
+    return tacmoves
 
 def movescom(iq, avoid):
     "Commander movement helper." 
 
 def movescom(iq, avoid):
     "Commander movement helper." 
@@ -668,20 +688,19 @@ def movescom(iq, avoid):
     game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons -= 1
     game.state.kscmdr = iq
     game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons += 1
     game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons -= 1
     game.state.kscmdr = iq
     game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons += 1
-    if game.state.kscmdr==game.quadrant:
+    if game.state.kscmdr == game.quadrant:
        # SC has scooted, remove him from current quadrant 
        # SC has scooted, remove him from current quadrant 
-       game.iscate=False
-       game.isatb=0
+       game.iscate = False
+       game.isatb = 0
        game.ientesc = False
        unschedule(FSCDBAS)
        for enemy in game.enemies:
            if enemy.type == 'S':
        game.ientesc = False
        unschedule(FSCDBAS)
        for enemy in game.enemies:
            if enemy.type == 'S':
-               break
-       enemy.move(None)
+               enemy.move(None)
        game.klhere -= 1
        if game.condition != "docked":
            newcnd()
        game.klhere -= 1
        if game.condition != "docked":
            newcnd()
-        game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
+        sortenemies()
     # check for a helpful planet 
     for i in range(game.inplan):
        if game.state.planets[i].quadrant == game.state.kscmdr and \
     # check for a helpful planet 
     for i in range(game.inplan):
        if game.state.planets[i].quadrant == game.state.kscmdr and \
@@ -695,13 +714,16 @@ def movescom(iq, avoid):
                proutn(_("   a planet in Quadrant %s has been destroyed") % game.state.kscmdr)
                prout(_("   by the Super-commander.\""))
            break
                proutn(_("   a planet in Quadrant %s has been destroyed") % game.state.kscmdr)
                prout(_("   by the Super-commander.\""))
            break
-    return True; # looks good! 
+    return True # looks good! 
                        
 def supercommander():
     "Move the Super Commander." 
                        
 def supercommander():
     "Move the Super Commander." 
-    iq = coord(); sc = coord(); ibq = coord(); idelta = coord()
+    iq = Coord()
+    sc = Coord()
+    ibq = Coord()
+    idelta = Coord()
     basetbl = []
     basetbl = []
-    if idebug:
+    if game.idebug:
        prout("== SUPERCOMMANDER")
     # Decide on being active or passive 
     avoid = ((game.incom - len(game.state.kcmdr) + game.inkling - game.state.remkl)/(game.state.date+0.01-game.indate) < 0.1*game.skill*(game.skill+1.0) or \
        prout("== SUPERCOMMANDER")
     # Decide on being active or passive 
     avoid = ((game.incom - len(game.state.kcmdr) + game.inkling - game.state.remkl)/(game.state.date+0.01-game.indate) < 0.1*game.skill*(game.skill+1.0) or \
@@ -720,16 +742,16 @@ def supercommander():
            unschedule(FSCMOVE)
            return
        sc = game.state.kscmdr
            unschedule(FSCMOVE)
            return
        sc = game.state.kscmdr
-        for base in game.state.baseq:
+        for (i, base) in enumerate(game.state.baseq):
            basetbl.append((i, (base - sc).distance()))
        if game.state.baseq > 1:
            basetbl.append((i, (base - sc).distance()))
        if game.state.baseq > 1:
-            basetbl.sort(lambda x, y: cmp(x[1]. y[1]))
+            basetbl.sort(lambda x, y: cmp(x[1], y[1]))
        # look for nearest base without a commander, no Enterprise, and
         # without too many Klingons, and not already under attack. 
        ifindit = iwhichb = 0
        for (i2, base) in enumerate(game.state.baseq):
        # look for nearest base without a commander, no Enterprise, and
         # without too many Klingons, and not already under attack. 
        ifindit = iwhichb = 0
        for (i2, base) in enumerate(game.state.baseq):
-           i = basetbl[i2][0]; # bug in original had it not finding nearest
-           if base==game.quadrant or base==game.battle or not welcoming(base):
+           i = basetbl[i2][0]  # bug in original had it not finding nearest
+           if base == game.quadrant or base == game.battle or not welcoming(base):
                continue
            # if there is a commander, and no other base is appropriate,
            # we will take the one with the commander
                continue
            # if there is a commander, and no other base is appropriate,
            # we will take the one with the commander
@@ -742,7 +764,7 @@ def supercommander():
                ifindit = 1
                iwhichb = i
                break
                ifindit = 1
                iwhichb = i
                break
-       if ifindit==0:
+       if ifindit == 0:
            return # Nothing suitable -- wait until next time
        ibq = game.state.baseq[iwhichb]
        # decide how to move toward base 
            return # Nothing suitable -- wait until next time
        ibq = game.state.baseq[iwhichb]
        # decide how to move toward base 
@@ -755,7 +777,7 @@ def supercommander():
     iq = game.state.kscmdr + idelta
     if not movescom(iq, avoid):
        # failed -- try some other maneuvers 
     iq = game.state.kscmdr + idelta
     if not movescom(iq, avoid):
        # failed -- try some other maneuvers 
-       if idelta.i==0 or idelta.j==0:
+       if idelta.i == 0 or idelta.j == 0:
            # attempt angle move 
            if idelta.i != 0:
                iq.j = game.state.kscmdr.j + 1
            # attempt angle move 
            if idelta.i != 0:
                iq.j = game.state.kscmdr.j + 1
@@ -800,13 +822,13 @@ def supercommander():
                if not game.resting:
                    return
                prout(_("Mr. Spock-  \"Captain, shall we cancel the rest period?\""))
                if not game.resting:
                    return
                prout(_("Mr. Spock-  \"Captain, shall we cancel the rest period?\""))
-               if ja() == False:
+               if not ja():
                    return
                game.resting = False
                    return
                game.resting = False
-               game.optime = 0.0; # actually finished 
+               game.optime = 0.0 # actually finished 
                return
     # Check for intelligence report 
                return
     # Check for intelligence report 
-    if not idebug and \
+    if not game.idebug and \
        (withprob(0.8) or \
         (not communicating()) or \
         not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].charted):
        (withprob(0.8) or \
         (not communicating()) or \
         not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].charted):
@@ -820,47 +842,51 @@ def movetholian():
     "Move the Tholian."
     if not game.tholian or game.justin:
        return
     "Move the Tholian."
     if not game.tholian or game.justin:
        return
-    id = coord()
+    tid = Coord()
     if game.tholian.location.i == 0 and game.tholian.location.j == 0:
     if game.tholian.location.i == 0 and game.tholian.location.j == 0:
-       id.i = 0; id.j = QUADSIZE-1
+       tid.i = 0
+        tid.j = QUADSIZE-1
     elif game.tholian.location.i == 0 and game.tholian.location.j == QUADSIZE-1:
     elif game.tholian.location.i == 0 and game.tholian.location.j == QUADSIZE-1:
-       id.i = QUADSIZE-1; id.j = QUADSIZE-1
+       tid.i = QUADSIZE-1
+        tid.j = QUADSIZE-1
     elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == QUADSIZE-1:
     elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == QUADSIZE-1:
-       id.i = QUADSIZE-1; id.j = 0
+       tid.i = QUADSIZE-1
+        tid.j = 0
     elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == 0:
     elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == 0:
-       id.i = 0; id.j = 0
+       tid.i = 0
+        tid.j = 0
     else:
        # something is wrong! 
        game.tholian.move(None)
         prout("***Internal error: Tholian in a bad spot.")
        return
     # do nothing if we are blocked 
     else:
        # something is wrong! 
        game.tholian.move(None)
         prout("***Internal error: Tholian in a bad spot.")
        return
     # do nothing if we are blocked 
-    if game.quad[id.i][id.j] not in ('.', '#'):
+    if game.quad[tid.i][tid.j] not in ('.', '#'):
        return
     here = copy.copy(game.tholian.location)
        return
     here = copy.copy(game.tholian.location)
-    delta = (id - game.tholian.location).sgn()
+    delta = (tid - game.tholian.location).sgn()
     # move in x axis 
     # move in x axis 
-    while here.i != id.i:
+    while here.i != tid.i:
         here.i += delta.i
         here.i += delta.i
-        if game.quad[here.i][here.j]=='.':
+        if game.quad[here.i][here.j] == '.':
             game.tholian.move(here)
     # move in y axis 
             game.tholian.move(here)
     # move in y axis 
-    while here.j != id.j:
+    while here.j != tid.j:
         here.j += delta.j
         here.j += delta.j
-        if game.quad[here.i][here.j]=='.':
+        if game.quad[here.i][here.j] == '.':
             game.tholian.move(here)
     # check to see if all holes plugged 
     for i in range(QUADSIZE):
             game.tholian.move(here)
     # check to see if all holes plugged 
     for i in range(QUADSIZE):
-       if game.quad[0][i]!='#' and game.quad[0][i]!='T':
+       if game.quad[0][i] != '#' and game.quad[0][i] != 'T':
            return
            return
-       if game.quad[QUADSIZE-1][i]!='#' and game.quad[QUADSIZE-1][i]!='T':
+       if game.quad[QUADSIZE-1][i] != '#' and game.quad[QUADSIZE-1][i] != 'T':
            return
            return
-       if game.quad[i][0]!='#' and game.quad[i][0]!='T':
+       if game.quad[i][0] != '#' and game.quad[i][0] != 'T':
            return
            return
-       if game.quad[i][QUADSIZE-1]!='#' and game.quad[i][QUADSIZE-1]!='T':
+       if game.quad[i][QUADSIZE-1] != '#' and game.quad[i][QUADSIZE-1] != 'T':
            return
     # All plugged up -- Tholian splits 
            return
     # All plugged up -- Tholian splits 
-    game.quad[game.tholian.location.i][game.tholian.location.j]='#'
+    game.quad[game.tholian.location.i][game.tholian.location.j] = '#'
     dropin(' ')
     prout(crmena(True, 'T', "sector", game.tholian) + _(" completes web."))
     game.tholian.move(None)
     dropin(' ')
     prout(crmena(True, 'T', "sector", game.tholian) + _(" completes web."))
     game.tholian.move(None)
@@ -887,27 +913,27 @@ def doshield(shraise):
                    action = "SHUP"
                elif scanner.sees("down"):
                    action = "SHDN"
                    action = "SHUP"
                elif scanner.sees("down"):
                    action = "SHDN"
-       if action=="NONE":
+       if action == "NONE":
            proutn(_("Do you wish to change shield energy? "))
            proutn(_("Do you wish to change shield energy? "))
-           if ja() == True:
+           if ja():
                action = "NRG"
            elif damaged(DSHIELD):
                prout(_("Shields damaged and down."))
                return
            elif game.shldup:
                proutn(_("Shields are up. Do you want them down? "))
                action = "NRG"
            elif damaged(DSHIELD):
                prout(_("Shields damaged and down."))
                return
            elif game.shldup:
                proutn(_("Shields are up. Do you want them down? "))
-               if ja() == True:
+               if ja():
                    action = "SHDN"
                else:
                    scanner.chew()
                    return
            else:
                proutn(_("Shields are down. Do you want them up? "))
                    action = "SHDN"
                else:
                    scanner.chew()
                    return
            else:
                proutn(_("Shields are down. Do you want them up? "))
-               if ja() == True:
+               if ja():
                    action = "SHUP"
                else:
                    scanner.chew()
                    action = "SHUP"
                else:
                    scanner.chew()
-                   return    
+                   return
     if action == "SHUP": # raise shields 
        if game.shldup:
            prout(_("Shields already up."))
     if action == "SHUP": # raise shields 
        if game.shldup:
            prout(_("Shields already up."))
@@ -922,14 +948,14 @@ def doshield(shraise):
            prout(_("Shields raising uses up last of energy."))
            finish(FNRG)
            return
            prout(_("Shields raising uses up last of energy."))
            finish(FNRG)
            return
-       game.ididit=True
+       game.ididit = True
        return
     elif action == "SHDN":
        if not game.shldup:
            prout(_("Shields already down."))
            return
        return
     elif action == "SHDN":
        if not game.shldup:
            prout(_("Shields already down."))
            return
-       game.shldup=False
-       game.shldchg=True
+       game.shldup = False
+       game.shldchg = True
        prout(_("Shields lowered."))
        game.ididit = True
        return
        prout(_("Shields lowered."))
        game.ididit = True
        return
@@ -996,15 +1022,15 @@ def randdevice():
     )
     assert(sum(weights) == 1000)
     idx = randrange(1000)
     )
     assert(sum(weights) == 1000)
     idx = randrange(1000)
-    sum = 0
+    wsum = 0
     for (i, w) in enumerate(weights):
     for (i, w) in enumerate(weights):
-       sum += w
-       if idx < sum:
+       wsum += w
+       if idx < wsum:
            return i
            return i
-    return None;       # we should never get here
+    return None        # we should never get here
 
 def collision(rammed, enemy):
 
 def collision(rammed, enemy):
-    "Collision handling fot rammong events."
+    "Collision handling for rammong events."
     prouts(_("***RED ALERT!  RED ALERT!"))
     skip(1)
     prout(_("***COLLISION IMMINENT."))
     prouts(_("***RED ALERT!  RED ALERT!"))
     skip(1)
     prout(_("***COLLISION IMMINENT."))
@@ -1021,16 +1047,17 @@ def collision(rammed, enemy):
        proutn(_(" (original position)"))
     skip(1)
     deadkl(enemy.location, enemy.type, game.sector)
        proutn(_(" (original position)"))
     skip(1)
     deadkl(enemy.location, enemy.type, game.sector)
-    proutn("***" + crmship() + " heavily damaged.")
+    proutn("***" + crmshp() + " heavily damaged.")
     icas = randrange(10, 30)
     icas = randrange(10, 30)
-    prout(_("***Sickbay reports %d casualties"), icas)
+    prout(_("***Sickbay reports %d casualties") % icas)
     game.casual += icas
     game.state.crew -= icas
     # In the pre-SST2K version, all devices got equiprobably damaged,
     # which was silly.  Instead, pick up to half the devices at
     # random according to our weighting table,
     ncrits = randrange(NDEVICES/2)
     game.casual += icas
     game.state.crew -= icas
     # In the pre-SST2K version, all devices got equiprobably damaged,
     # which was silly.  Instead, pick up to half the devices at
     # random according to our weighting table,
     ncrits = randrange(NDEVICES/2)
-    for m in range(ncrits):
+    while ncrits > 0:
+        ncrits -= 1
        dev = randdevice()
        if game.damage[dev] < 0:
            continue
        dev = randdevice()
        if game.damage[dev] < 0:
            continue
@@ -1048,57 +1075,59 @@ def collision(rammed, enemy):
 
 def torpedo(origin, bearing, dispersion, number, nburst):
     "Let a photon torpedo fly" 
 
 def torpedo(origin, bearing, dispersion, number, nburst):
     "Let a photon torpedo fly" 
-    if not damaged(DSRSENS) or game.condition=="docked":
+    if not damaged(DSRSENS) or game.condition == "docked":
        setwnd(srscan_window)
     else: 
        setwnd(message_window)
     ac = bearing + 0.25*dispersion     # dispersion is a random variable
     bullseye = (15.0 - bearing)*0.5235988
     track = course(bearing=ac, distance=QUADSIZE, origin=cartesian(origin)) 
        setwnd(srscan_window)
     else: 
        setwnd(message_window)
     ac = bearing + 0.25*dispersion     # dispersion is a random variable
     bullseye = (15.0 - bearing)*0.5235988
     track = course(bearing=ac, distance=QUADSIZE, origin=cartesian(origin)) 
-    bumpto = coord(0, 0)
+    bumpto = Coord(0, 0)
     # Loop to move a single torpedo 
     setwnd(message_window)
     for step in range(1, QUADSIZE*2):
     # Loop to move a single torpedo 
     setwnd(message_window)
     for step in range(1, QUADSIZE*2):
-        if not track.next(): break
+        if not track.next():
+            break
         w = track.sector()
        if not w.valid_sector():
            break
         w = track.sector()
        if not w.valid_sector():
            break
-       iquad=game.quad[w.i][w.j]
-       tracktorpedo(origin, w, step, number, nburst, iquad)
-       if iquad=='.':
+       iquad = game.quad[w.i][w.j]
+       tracktorpedo(w, step, number, nburst, iquad)
+       if iquad == '.':
            continue
        # hit something 
            continue
        # hit something 
-       if not damaged(DSRSENS) or game.condition == "docked":
-           skip(1);    # start new line after text track 
+        setwnd(message_window)
+        if not damaged(DSRSENS) or game.condition == "docked":
+           skip(1)     # start new line after text track 
        if iquad in ('E', 'F'): # Hit our ship 
            skip(1)
            prout(_("Torpedo hits %s.") % crmshp())
            hit = 700.0 + randreal(100) - \
                1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
        if iquad in ('E', 'F'): # Hit our ship 
            skip(1)
            prout(_("Torpedo hits %s.") % crmshp())
            hit = 700.0 + randreal(100) - \
                1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
-           newcnd(); # we're blown out of dock 
-           if game.landed or game.condition=="docked":
+           newcnd() # we're blown out of dock 
+           if game.landed or game.condition == "docked":
                return hit # Cheat if on a planet 
             # In the C/FORTRAN version, dispersion was 2.5 radians, which
             # is 143 degrees, which is almost exactly 4.8 clockface units
                return hit # Cheat if on a planet 
             # In the C/FORTRAN version, dispersion was 2.5 radians, which
             # is 143 degrees, which is almost exactly 4.8 clockface units
-            displacement = course(track.bearing+randreal(-2.4,2.4), distance=2**0.5)
+            displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
             displacement.next()
             bumpto = displacement.sector()
            if not bumpto.valid_sector():
                return hit
             displacement.next()
             bumpto = displacement.sector()
            if not bumpto.valid_sector():
                return hit
-           if game.quad[bumpto.i][bumpto.j]==' ':
+           if game.quad[bumpto.i][bumpto.j] == ' ':
                finish(FHOLE)
                return hit
                finish(FHOLE)
                return hit
-           if game.quad[bumpto.i][bumpto.j]!='.':
+           if game.quad[bumpto.i][bumpto.j] != '.':
                # can't move into object 
                return hit
            game.sector = bumpto
            proutn(crmshp())
                # can't move into object 
                return hit
            game.sector = bumpto
            proutn(crmshp())
-            game.quad[w.i][w.j]='.'
-            game.quad[bumpto.i][bumpto.j]=iquad
+            game.quad[w.i][w.j] = '.'
+            game.quad[bumpto.i][bumpto.j] = iquad
             prout(_(" displaced by blast to Sector %s ") % bumpto)
             for enemy in game.enemies:
                 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
             prout(_(" displaced by blast to Sector %s ") % bumpto)
             for enemy in game.enemies:
                 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
-            game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
+            sortenemies()
             return None
        elif iquad in ('C', 'S', 'R', 'K'): # Hit a regular enemy 
            # find the enemy 
             return None
        elif iquad in ('C', 'S', 'R', 'K'): # Hit a regular enemy 
            # find the enemy 
@@ -1108,49 +1137,52 @@ def torpedo(origin, bearing, dispersion, number, nburst):
                return None
             for enemy in game.enemies:
                if w == enemy.location:
                return None
             for enemy in game.enemies:
                if w == enemy.location:
-                   break
-           kp = math.fabs(enemy.power)
-           h1 = 700.0 + randrange(100) - \
-               1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
-           h1 = math.fabs(h1)
-           if kp < h1:
-               h1 = kp
-            if enemy.power < 0:
-                enemy.power -= -h1
-            else:
-                enemy.power -= h1
-           if enemy.power == 0:
-               deadkl(w, iquad, w)
-               return None
-           proutn(crmena(True, iquad, "sector", w))
-            displacement = course(track.bearing+randreal(-2.4,2.4), distance=2**0.5)
-            displacement.next()
-            bumpto = displacement.sector()
-            if not bumpto.valid_sector():
-               prout(_(" damaged but not destroyed."))
-               return
-           if game.quad[bumpto.i][bumpto.j] == ' ':
-               prout(_(" buffeted into black hole."))
-               deadkl(w, iquad, bumpto)
-           if game.quad[bumpto.i][bumpto.j] != '.':
-               prout(_(" damaged but not destroyed."))
+                    kp = math.fabs(enemy.power)
+                    h1 = 700.0 + randrange(100) - \
+                        1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
+                    h1 = math.fabs(h1)
+                    if kp < h1:
+                        h1 = kp
+                    if enemy.power < 0:
+                        enemy.power -= -h1
+                    else:
+                        enemy.power -= h1
+                    if enemy.power == 0:
+                        deadkl(w, iquad, w)
+                        return None
+                    proutn(crmena(True, iquad, "sector", w))
+                    displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
+                    displacement.next()
+                    bumpto = displacement.sector()
+                    if not bumpto.valid_sector():
+                        prout(_(" damaged but not destroyed."))
+                        return
+                    if game.quad[bumpto.i][bumpto.j] == ' ':
+                        prout(_(" buffeted into black hole."))
+                        deadkl(w, iquad, bumpto)
+                    if game.quad[bumpto.i][bumpto.j] != '.':
+                        prout(_(" damaged but not destroyed."))
+                    else:
+                        prout(_(" damaged-- displaced by blast to Sector %s ")%bumpto)
+                        enemy.location = bumpto
+                        game.quad[w.i][w.j] = '.'
+                        game.quad[bumpto.i][bumpto.j] = iquad
+                        for enemy in game.enemies:
+                            enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
+                        sortenemies()
+                    break
             else:
             else:
-                prout(_(" damaged-- displaced by blast to Sector %s ")%bumpto)
-                enemy.location = bumpto
-                game.quad[w.i][w.j]='.'
-                game.quad[bumpto.i][bumpto.j]=iquad
-                for enemy in game.enemies:
-                    enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
-                game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
+                prout("Internal error, no enemy where expected!")
+                raise SystemExit, 1
             return None
        elif iquad == 'B': # Hit a base 
            skip(1)
            prout(_("***STARBASE DESTROYED.."))
             game.state.baseq = filter(lambda x: x != game.quadrant, game.state.baseq)
             return None
        elif iquad == 'B': # Hit a base 
            skip(1)
            prout(_("***STARBASE DESTROYED.."))
             game.state.baseq = filter(lambda x: x != game.quadrant, game.state.baseq)
-           game.quad[w.i][w.j]='.'
+           game.quad[w.i][w.j] = '.'
            game.base.invalidate()
            game.base.invalidate()
-           game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase -= 1
-           game.state.chart[game.quadrant.i][game.quadrant.j].starbase -= 1
+           game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
+           game.state.chart[game.quadrant.i][game.quadrant.j].starbase = False
            game.state.basekl += 1
            newcnd()
            return None
            game.state.basekl += 1
            newcnd()
            return None
@@ -1200,8 +1232,7 @@ def torpedo(origin, bearing, dispersion, number, nburst):
                # Stas Sergeev added the possibility that
                # you can shove the Thingy and piss it off.
                # It then becomes an enemy and may fire at you.
                # Stas Sergeev added the possibility that
                # you can shove the Thingy and piss it off.
                # It then becomes an enemy and may fire at you.
-               thing.angry = True
-               shoved = True
+               thing.angry()
            return None
        elif iquad == ' ': # Black hole 
            skip(1)
            return None
        elif iquad == ' ': # Black hole 
            skip(1)
@@ -1213,7 +1244,7 @@ def torpedo(origin, bearing, dispersion, number, nburst):
            return None
        elif iquad == 'T':  # Hit a Tholian 
            h1 = 700.0 + randrange(100) - \
            return None
        elif iquad == 'T':  # Hit a Tholian 
            h1 = 700.0 + randrange(100) - \
-               1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-angle))
+               1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
            h1 = math.fabs(h1)
            if h1 >= 600:
                game.quad[w.i][w.j] = '.'
            h1 = math.fabs(h1)
            if h1 >= 600:
                game.quad[w.i][w.j] = '.'
@@ -1238,8 +1269,9 @@ def torpedo(origin, bearing, dispersion, number, nburst):
            return None
        break
     skip(1)
            return None
        break
     skip(1)
+    setwnd(message_window)
     prout(_("Torpedo missed."))
     prout(_("Torpedo missed."))
-    return None;
+    return None
 
 def fry(hit):
     "Critical-hit resolution." 
 
 def fry(hit):
     "Critical-hit resolution." 
@@ -1249,15 +1281,16 @@ def fry(hit):
     proutn(_("***CRITICAL HIT--"))
     # Select devices and cause damage
     cdam = []
     proutn(_("***CRITICAL HIT--"))
     # Select devices and cause damage
     cdam = []
-    for loop1 in range(ncrit):
+    while ncrit > 0:
         while True:
            j = randdevice()
            # Cheat to prevent shuttle damage unless on ship 
         while True:
            j = randdevice()
            # Cheat to prevent shuttle damage unless on ship 
-            if not (game.damage[j]<0.0 or (j==DSHUTTL and game.iscraft != "onship")):
+            if not (game.damage[j]<0.0 or (j == DSHUTTL and game.iscraft != "onship")):
                 break
        cdam.append(j)
        extradm = (hit*game.damfac)/(ncrit*randreal(75, 100))
        game.damage[j] += extradm
                 break
        cdam.append(j)
        extradm = (hit*game.damfac)/(ncrit*randreal(75, 100))
        game.damage[j] += extradm
+        ncrit -= 1
     skipcount = 0
     for (i, j) in enumerate(cdam):
        proutn(device[j])
     skipcount = 0
     for (i, j) in enumerate(cdam):
        proutn(device[j])
@@ -1269,7 +1302,7 @@ def fry(hit):
     prout(_(" damaged."))
     if damaged(DSHIELD) and game.shldup:
        prout(_("***Shields knocked down."))
     prout(_(" damaged."))
     if damaged(DSHIELD) and game.shldup:
        prout(_("***Shields knocked down."))
-       game.shldup=False
+       game.shldup = False
 
 def attack(torps_ok):
     # bad guy attacks us 
 
 def attack(torps_ok):
     # bad guy attacks us 
@@ -1277,10 +1310,13 @@ def attack(torps_ok):
     # game could be over at this point, check
     if game.alldone:
        return
     # game could be over at this point, check
     if game.alldone:
        return
-    attempt = False; ihurt = False;
-    hitmax=0.0; hittot=0.0; chgfac=1.0
+    attempt = False
+    ihurt = False
+    hitmax = 0.0
+    hittot = 0.0
+    chgfac = 1.0
     where = "neither"
     where = "neither"
-    if idebug:
+    if game.idebug:
        prout("=== ATTACK!")
     # Tholian gets to move before attacking 
     if game.tholian:
        prout("=== ATTACK!")
     # Tholian gets to move before attacking 
     if game.tholian:
@@ -1290,10 +1326,27 @@ def attack(torps_ok):
        game.neutz = False
        return
     # commanders get a chance to tac-move towards you 
        game.neutz = False
        return
     # commanders get a chance to tac-move towards you 
-    if (((game.quadrant in game.state.kcmdr or game.state.kscmdr==game.quadrant) and not game.justin) or game.skill == SKILL_EMERITUS) and torps_ok:
-       moveklings()
+    if (((game.quadrant in game.state.kcmdr or game.state.kscmdr == game.quadrant) and not game.justin) or game.skill == SKILL_EMERITUS) and torps_ok:
+        for (bugout, enemy, old, goto) in  moveklings():
+            if bugout:
+                # we know about this if either short or long range
+                # sensors are working
+                if damaged(DSRSENS) and damaged(DLRSENS) \
+                       and game.condition != "docked":
+                    prout(crmena(True, enemy.type, "sector", old) + \
+                          (_(" escapes to Quadrant %s (and regains strength).") % goto))
+            else: # Enemy still in-sector
+                if enemy.move(goto):
+                    if not damaged(DSRSENS) or game.condition == "docked":
+                        proutn(_("*** %s from Sector %s") % (cramen(enemy.type), enemy.location))
+                        if enemy.kdist < old:
+                            proutn(_(" advances to "))
+                        else:
+                            proutn(_(" retreats to "))
+                        prout("Sector %s." % goto)
+        sortenemies()
     # if no enemies remain after movement, we're done 
     # if no enemies remain after movement, we're done 
-    if len(game.enemies)==0 or (len(game.enemies)==1 and thing == game.quadrant and not thing.angry):
+    if len(game.enemies) == 0 or (len(game.enemies) == 1 and thing.at(game.quadrant) and not thing.angered):
        return
     # set up partial hits if attack happens during shield status change 
     pfac = 1.0/game.inshld
        return
     # set up partial hits if attack happens during shield status change 
     pfac = 1.0/game.inshld
@@ -1305,33 +1358,33 @@ def attack(torps_ok):
        where = "sector"
     for enemy in game.enemies:
        if enemy.power < 0:
        where = "sector"
     for enemy in game.enemies:
        if enemy.power < 0:
-           continue;   # too weak to attack 
+           continue    # too weak to attack 
        # compute hit strength and diminish shield power 
        r = randreal()
        # Increase chance of photon torpedos if docked or enemy energy is low 
        if game.condition == "docked":
            r *= 0.25
        if enemy.power < 500:
        # compute hit strength and diminish shield power 
        r = randreal()
        # Increase chance of photon torpedos if docked or enemy energy is low 
        if game.condition == "docked":
            r *= 0.25
        if enemy.power < 500:
-           r *= 0.25; 
-       if enemy.type=='T' or (enemy.type=='?' and not thing.angry):
+           r *= 0.25 
+       if enemy.type == 'T' or (enemy.type == '?' and not thing.angered):
            continue
        # different enemies have different probabilities of throwing a torp 
        usephasers = not torps_ok or \
            (enemy.type == 'K' and r > 0.0005) or \
            continue
        # different enemies have different probabilities of throwing a torp 
        usephasers = not torps_ok or \
            (enemy.type == 'K' and r > 0.0005) or \
-           (enemy.type=='C' and r > 0.015) or \
-           (enemy.type=='R' and r > 0.3) or \
-           (enemy.type=='S' and r > 0.07) or \
-           (enemy.type=='?' and r > 0.05)
+           (enemy.type == 'C' and r > 0.015) or \
+           (enemy.type == 'R' and r > 0.3) or \
+           (enemy.type == 'S' and r > 0.07) or \
+           (enemy.type == '?' and r > 0.05)
        if usephasers:      # Enemy uses phasers 
            if game.condition == "docked":
        if usephasers:      # Enemy uses phasers 
            if game.condition == "docked":
-               continue; # Don't waste the effort! 
-           attempt = True; # Attempt to attack 
+               continue # Don't waste the effort! 
+           attempt = True # Attempt to attack 
            dustfac = randreal(0.8, 0.85)
            dustfac = randreal(0.8, 0.85)
-           hit = enemy.power*math.pow(dustfac,enemy.kavgd)
+           hit = enemy.power*math.pow(dustfac, enemy.kavgd)
            enemy.power *= 0.75
        else: # Enemy uses photon torpedo 
            # We should be able to make the bearing() method work here
            enemy.power *= 0.75
        else: # Enemy uses photon torpedo 
            # We should be able to make the bearing() method work here
-           course = 1.90985*math.atan2(game.sector.j-enemy.location.j, enemy.location.i-game.sector.i)
+           pcourse = 1.90985*math.atan2(game.sector.j-enemy.location.j, enemy.location.i-game.sector.i)
            hit = 0
            proutn(_("***TORPEDO INCOMING"))
            if not damaged(DSRSENS):
            hit = 0
            proutn(_("***TORPEDO INCOMING"))
            if not damaged(DSRSENS):
@@ -1340,19 +1393,19 @@ def attack(torps_ok):
            prout("  ")
            dispersion = (randreal()+randreal())*0.5 - 0.5
            dispersion += 0.002*enemy.power*dispersion
            prout("  ")
            dispersion = (randreal()+randreal())*0.5 - 0.5
            dispersion += 0.002*enemy.power*dispersion
-           hit = torpedo(enemy.location, course, dispersion, number=1, nburst=1)
-           if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
-               finish(FWON); # Klingons did themselves in! 
+           hit = torpedo(enemy.location, pcourse, dispersion, number=1, nburst=1)
+           if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
+               finish(FWON) # Klingons did themselves in! 
            if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.alldone:
                return # Supernova or finished 
            if hit == None:
                continue
        # incoming phaser or torpedo, shields may dissipate it 
            if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.alldone:
                return # Supernova or finished 
            if hit == None:
                continue
        # incoming phaser or torpedo, shields may dissipate it 
-       if game.shldup or game.shldchg or game.condition=="docked":
+       if game.shldup or game.shldchg or game.condition == "docked":
            # shields will take hits 
            propor = pfac * game.shield
            # shields will take hits 
            propor = pfac * game.shield
-            if game.condition =="docked":
-                propr *= 2.1
+            if game.condition == "docked":
+                propor *= 2.1
            if propor < 0.1:
                propor = 0.1
            hitsh = propor*chgfac*hit+1.0
            if propor < 0.1:
                propor = 0.1
            hitsh = propor*chgfac*hit+1.0
@@ -1414,23 +1467,23 @@ def attack(torps_ok):
     # After attack, reset average distance to enemies 
     for enemy in game.enemies:
        enemy.kavgd = enemy.kdist
     # After attack, reset average distance to enemies 
     for enemy in game.enemies:
        enemy.kavgd = enemy.kdist
-    game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
+    sortenemies()
     return
                
     return
                
-def deadkl(w, type, mv):
+def deadkl(w, etype, mv):
     "Kill a Klingon, Tholian, Romulan, or Thingy." 
     # Added mv to allow enemy to "move" before dying 
     "Kill a Klingon, Tholian, Romulan, or Thingy." 
     # Added mv to allow enemy to "move" before dying 
-    proutn(crmena(True, type, "sector", mv))
+    proutn(crmena(True, etype, "sector", mv))
     # Decide what kind of enemy it is and update appropriately 
     # Decide what kind of enemy it is and update appropriately 
-    if type == 'R':
+    if etype == 'R':
         # Chalk up a Romulan 
         game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans -= 1
         game.irhere -= 1
         game.state.nromrem -= 1
         # Chalk up a Romulan 
         game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans -= 1
         game.irhere -= 1
         game.state.nromrem -= 1
-    elif type == 'T':
+    elif etype == 'T':
         # Killed a Tholian 
         game.tholian = None
         # Killed a Tholian 
         game.tholian = None
-    elif type == '?':
+    elif etype == '?':
         # Killed a Thingy
         global thing
         thing = None
         # Killed a Thingy
         global thing
         thing = None
@@ -1456,7 +1509,7 @@ def deadkl(w, type, mv):
             unschedule(FSCDBAS)
     # For each kind of enemy, finish message to player 
     prout(_(" destroyed."))
             unschedule(FSCDBAS)
     # For each kind of enemy, finish message to player 
     prout(_(" destroyed."))
-    if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
+    if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
        return
     game.recompute()
     # Remove enemy ship from arrays describing local conditions
        return
     game.recompute()
     # Remove enemy ship from arrays describing local conditions
@@ -1471,11 +1524,11 @@ def targetcheck(w):
     if not w.valid_sector():
        huh()
        return None
     if not w.valid_sector():
        huh()
        return None
-    delta = coord()
-    # FIXME: C code this was translated from is wacky -- why the sign reversal?
-    delta.j = (w.j - game.sector.j);
-    delta.i = (game.sector.i - w.i);
-    if delta == coord(0, 0):
+    delta = Coord()
+    # C code this was translated from is wacky -- why the sign reversal?
+    delta.j = (w.j - game.sector.j)
+    delta.i = (game.sector.i - w.i)
+    if delta == Coord(0, 0):
        skip(1)
        prout(_("Spock-  \"Bridge to sickbay.  Dr. McCoy,"))
        prout(_("  I recommend an immediate review of"))
        skip(1)
        prout(_("Spock-  \"Bridge to sickbay.  Dr. McCoy,"))
        prout(_("  I recommend an immediate review of"))
@@ -1486,7 +1539,7 @@ def targetcheck(w):
 
 def torps():
     "Launch photon torpedo salvo."
 
 def torps():
     "Launch photon torpedo salvo."
-    course = []
+    tcourse = []
     game.ididit = False
     if damaged(DPHOTON):
        prout(_("Photon tubes damaged."))
     game.ididit = False
     if damaged(DPHOTON):
        prout(_("Photon tubes damaged."))
@@ -1524,21 +1577,21 @@ def torps():
     target = []
     for i in range(n):
        key = scanner.next()
     target = []
     for i in range(n):
        key = scanner.next()
-       if i==0 and key == "IHEOL":
-           break;      # no coordinate waiting, we will try prompting 
-       if i==1 and key == "IHEOL":
+       if i == 0 and key == "IHEOL":
+           break       # no coordinate waiting, we will try prompting 
+       if i == 1 and key == "IHEOL":
            # direct all torpedoes at one target 
            while i < n:
                target.append(target[0])
            # direct all torpedoes at one target 
            while i < n:
                target.append(target[0])
-               course.append(course[0])
+               tcourse.append(tcourse[0])
                i += 1
            break
         scanner.push(scanner.token)
         target.append(scanner.getcoord())
         if target[-1] == None:
             return
                i += 1
            break
         scanner.push(scanner.token)
         target.append(scanner.getcoord())
         if target[-1] == None:
             return
-        course.append(targetcheck(target[-1]))
-        if course[-1] == None:
+        tcourse.append(targetcheck(target[-1]))
+        if tcourse[-1] == None:
            return
     scanner.chew()
     if len(target) == 0:
            return
     scanner.chew()
     if len(target) == 0:
@@ -1549,8 +1602,8 @@ def torps():
             target.append(scanner.getcoord())
             if target[-1] == None:
                 return
             target.append(scanner.getcoord())
             if target[-1] == None:
                 return
-            course.append(targetcheck(target[-1]))
-            if course[-1] == None:
+            tcourse.append(targetcheck(target[-1]))
+            if tcourse[-1] == None:
                 return
     game.ididit = True
     # Loop for moving <n> torpedoes 
                 return
     game.ididit = True
     # Loop for moving <n> torpedoes 
@@ -1574,11 +1627,11 @@ def torps():
            break
        if game.shldup or game.condition == "docked":
            dispersion *= 1.0 + 0.0001*game.shield
            break
        if game.shldup or game.condition == "docked":
            dispersion *= 1.0 + 0.0001*game.shield
-       torpedo(game.sector, course[i], dispersion, number=i, nburst=n)
+       torpedo(game.sector, tcourse[i], dispersion, number=i, nburst=n)
        if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
            return
        if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
            return
-    if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
-       finish(FWON);
+    if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)<=0:
+       finish(FWON)
 
 def overheat(rpow):
     "Check for phasers overheating."
 
 def overheat(rpow):
     "Check for phasers overheating."
@@ -1622,18 +1675,18 @@ def checkshctrl(rpow):
     prout(_("Phaser energy dispersed by shields."))
     prout(_("Enemy unaffected."))
     overheat(rpow)
     prout(_("Phaser energy dispersed by shields."))
     prout(_("Enemy unaffected."))
     overheat(rpow)
-    return True;
+    return True
 
 def hittem(hits):
     "Register a phaser hit on Klingons and Romulans."
 
 def hittem(hits):
     "Register a phaser hit on Klingons and Romulans."
-    nenhr2 = len(game.enemies); kk=0
-    w = coord()
+    w = Coord()
     skip(1)
     skip(1)
-    for (k, wham) in enumerate(hits):
-       if wham==0:
+    kk = 0
+    for wham in hits:
+       if wham == 0:
            continue
        dustfac = randreal(0.9, 1.0)
            continue
        dustfac = randreal(0.9, 1.0)
-       hit = wham*math.pow(dustfac,game.enemies[kk].kdist)
+       hit = wham*math.pow(dustfac, game.enemies[kk].kdist)
        kpini = game.enemies[kk].power
        kp = math.fabs(kpini)
        if PHASEFAC*hit < kp:
        kpini = game.enemies[kk].power
        kp = math.fabs(kpini)
        if PHASEFAC*hit < kp:
@@ -1651,20 +1704,20 @@ def hittem(hits):
        else:
            proutn(_("Very small hit on "))
        ienm = game.quad[w.i][w.j]
        else:
            proutn(_("Very small hit on "))
        ienm = game.quad[w.i][w.j]
-       if ienm=='?':
-           thing.angry = True
+       if ienm == '?':
+           thing.angry()
        proutn(crmena(False, ienm, "sector", w))
        skip(1)
        if kpow == 0:
            deadkl(w, ienm, w)
            if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
        proutn(crmena(False, ienm, "sector", w))
        skip(1)
        if kpow == 0:
            deadkl(w, ienm, w)
            if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
-               finish(FWON);           
+               finish(FWON)            
            if game.alldone:
                return
            kk -= 1     # don't do the increment
             continue
        else: # decide whether or not to emasculate klingon 
            if game.alldone:
                return
            kk -= 1     # don't do the increment
             continue
        else: # decide whether or not to emasculate klingon 
-           if kpow>0 and withprob(0.9) and kpow <= randreal(0.4, 0.8)*kpini:
+           if kpow > 0 and withprob(0.9) and kpow <= randreal(0.4, 0.8)*kpini:
                prout(_("***Mr. Spock-  \"Captain, the vessel at Sector %s")%w)
                prout(_("   has just lost its firepower.\""))
                game.enemies[kk].power = -kpow
                prout(_("***Mr. Spock-  \"Captain, the vessel at Sector %s")%w)
                prout(_("   has just lost its firepower.\""))
                game.enemies[kk].power = -kpow
@@ -1674,10 +1727,16 @@ def hittem(hits):
 def phasers():
     "Fire phasers at bad guys."
     hits = []
 def phasers():
     "Fire phasers at bad guys."
     hits = []
-    kz = 0; k = 1; irec=0 # Cheating inhibitor 
-    ifast = False; no = False; itarg = True; msgflag = True; rpow=0
+    kz = 0
+    k = 1
+    irec = 0 # Cheating inhibitor 
+    ifast = False
+    no = False
+    itarg = True
+    msgflag = True
+    rpow = 0
     automode = "NOTSET"
     automode = "NOTSET"
-    key=0
+    key = 0
     skip(1)
     # SR sensors and Computer are needed for automode 
     if damaged(DSRSENS) or damaged(DCOMPTR):
     skip(1)
     # SR sensors and Computer are needed for automode 
     if damaged(DSRSENS) or damaged(DCOMPTR):
@@ -1703,15 +1762,15 @@ def phasers():
        ifast = True
     # Original code so convoluted, I re-did it all
     # (That was Tom Almy talking about the C code, I think -- ESR)
        ifast = True
     # Original code so convoluted, I re-did it all
     # (That was Tom Almy talking about the C code, I think -- ESR)
-    while automode=="NOTSET":
-       key=scanner.next()
+    while automode == "NOTSET":
+       key = scanner.next()
        if key == "IHALPHA":
            if scanner.sees("manual"):
                if len(game.enemies)==0:
                    prout(_("There is no enemy present to select."))
                    scanner.chew()
                    key = "IHEOL"
        if key == "IHALPHA":
            if scanner.sees("manual"):
                if len(game.enemies)==0:
                    prout(_("There is no enemy present to select."))
                    scanner.chew()
                    key = "IHEOL"
-                   automode="AUTOMATIC"
+                   automode = "AUTOMATIC"
                else:
                    automode = "MANUAL"
                    key = scanner.next()
                else:
                    automode = "MANUAL"
                    key = scanner.next()
@@ -1755,18 +1814,18 @@ def phasers():
            key = scanner.next()
        if key != "IHREAL" and len(game.enemies) != 0:
            prout(_("Phasers locked on target. Energy available: %.2f")%avail)
            key = scanner.next()
        if key != "IHREAL" and len(game.enemies) != 0:
            prout(_("Phasers locked on target. Energy available: %.2f")%avail)
-       irec=0
+       irec = 0
         while True:
            scanner.chew()
            if not kz:
                for i in range(len(game.enemies)):
         while True:
            scanner.chew()
            if not kz:
                for i in range(len(game.enemies)):
-                   irec += math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90,game.enemies[i].kdist))*randreal(1.01, 1.06) + 1.0
-           kz=1
+                   irec += math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))*randreal(1.01, 1.06) + 1.0
+           kz = 1
            proutn(_("%d units required. ") % irec)
            scanner.chew()
            proutn(_("Units to fire= "))
            key = scanner.next()
            proutn(_("%d units required. ") % irec)
            scanner.chew()
            proutn(_("Units to fire= "))
            key = scanner.next()
-           if key!="IHREAL":
+           if key != "IHREAL":
                return
            rpow = scanner.real
            if rpow > avail:
                return
            rpow = scanner.real
            if rpow > avail:
@@ -1775,15 +1834,15 @@ def phasers():
                key = "IHEOL"
             if not rpow > avail:
                 break
                key = "IHEOL"
             if not rpow > avail:
                 break
-       if rpow<=0:
+       if rpow <= 0:
            # chicken out 
            scanner.chew()
            return
            # chicken out 
            scanner.chew()
            return
-        key=scanner.next()
+        key = scanner.next()
        if key == "IHALPHA" and scanner.sees("no"):
            no = True
        if ifast:
        if key == "IHALPHA" and scanner.sees("no"):
            no = True
        if ifast:
-           game.energy -= 200; # Go and do it! 
+           game.energy -= 200 # Go and do it! 
            if checkshctrl(rpow):
                return
        scanner.chew()
            if checkshctrl(rpow):
                return
        scanner.chew()
@@ -1796,7 +1855,7 @@ def phasers():
                hits.append(0.0)
                if powrem <= 0:
                    continue
                hits.append(0.0)
                if powrem <= 0:
                    continue
-               hits[i] = math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90,game.enemies[i].kdist))
+               hits[i] = math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))
                over = randreal(1.01, 1.06) * hits[i]
                temp = powrem
                powrem -= hits[i] + over
                over = randreal(1.01, 1.06) * hits[i]
                temp = powrem
                powrem -= hits[i] + over
@@ -1845,13 +1904,13 @@ def phasers():
                prout(cramen(ienm) + _(" can't be located without short range scan."))
                scanner.chew()
                key = "IHEOL"
                prout(cramen(ienm) + _(" can't be located without short range scan."))
                scanner.chew()
                key = "IHEOL"
-               hits[k] = 0; # prevent overflow -- thanks to Alexei Voitenko 
+               hits[k] = 0 # prevent overflow -- thanks to Alexei Voitenko 
                k += 1
                continue
            if key == "IHEOL":
                scanner.chew()
                if itarg and k > kz:
                k += 1
                continue
            if key == "IHEOL":
                scanner.chew()
                if itarg and k > kz:
-                   irec=(abs(game.enemies[k].power)/(PHASEFAC*math.pow(0.9,game.enemies[k].kdist))) *  randreal(1.01, 1.06) + 1.0
+                   irec = (abs(game.enemies[k].power)/(PHASEFAC*math.pow(0.9, game.enemies[k].kdist))) *       randreal(1.01, 1.06) + 1.0
                kz = k
                proutn("(")
                if not damaged(DCOMPTR):
                kz = k
                proutn("(")
                if not damaged(DCOMPTR):
@@ -1869,7 +1928,7 @@ def phasers():
                huh()
                return
            if key == "IHEOL":
                huh()
                return
            if key == "IHEOL":
-               if k==1: # Let me say I'm baffled by this 
+               if k == 1: # Let me say I'm baffled by this 
                    msgflag = True
                continue
            if scanner.real < 0:
                    msgflag = True
                continue
            if scanner.real < 0:
@@ -1883,7 +1942,7 @@ def phasers():
                prout(_("Available energy exceeded -- try again."))
                scanner.chew()
                return
                prout(_("Available energy exceeded -- try again."))
                scanner.chew()
                return
-           key = scanner.next(); # scan for next value 
+           key = scanner.next() # scan for next value 
            k += 1
        if rpow == 0.0:
            # zero energy -- abort 
            k += 1
        if rpow == 0.0:
            # zero energy -- abort 
@@ -1914,7 +1973,7 @@ def phasers():
                prout(_("Shields raised."))
        else:
            game.shldup = False
                prout(_("Shields raised."))
        else:
            game.shldup = False
-    overheat(rpow);
+    overheat(rpow)
 
 # Code from events,c begins here.
 
 
 # Code from events,c begins here.
 
@@ -1950,7 +2009,7 @@ def cancelrest():
     if game.resting:
        skip(1)
        proutn(_("Mr. Spock-  \"Captain, shall we cancel the rest period?\""))
     if game.resting:
        skip(1)
        proutn(_("Mr. Spock-  \"Captain, shall we cancel the rest period?\""))
-       if ja() == True:
+       if ja():
            game.resting = False
            game.optime = 0.0
            return True
            game.resting = False
            game.optime = 0.0
            return True
@@ -1958,11 +2017,15 @@ def cancelrest():
 
 def events():
     "Run through the event queue looking for things to do."
 
 def events():
     "Run through the event queue looking for things to do."
-    i=0
-    fintim = game.state.date + game.optime; yank=0
-    ictbeam = False; istract = False
-    w = coord(); hold = coord()
-    ev = event(); ev2 = event()
+    i = 0
+    fintim = game.state.date + game.optime
+    yank = 0
+    ictbeam = False
+    istract = False
+    w = Coord()
+    hold = Coord()
+    ev = Event()
+    ev2 = Event()
 
     def tractorbeam(yank):
         "Tractor-beaming cases merge here." 
 
     def tractorbeam(yank):
         "Tractor-beaming cases merge here." 
@@ -2004,8 +2067,8 @@ def events():
             else:
                 prout(_("(Shields not currently useable.)"))
         newqad()
             else:
                 prout(_("(Shields not currently useable.)"))
         newqad()
-        # Adjust finish time to time of tractor beaming 
-        fintim = game.state.date+game.optime
+        # Adjust finish time to time of tractor beaming? 
+        fintim = game.state.date+game.optime
         attack(torps_ok=False)
         if not game.state.kcmdr:
             unschedule(FTBEAM)
         attack(torps_ok=False)
         if not game.state.kcmdr:
             unschedule(FTBEAM)
@@ -2043,7 +2106,7 @@ def events():
             game.isatb = 0
         else:
             game.battle.invalidate()
             game.isatb = 0
         else:
             game.battle.invalidate()
-    if idebug:
+    if game.idebug:
        prout("=== EVENTS from %.2f to %.2f:" % (game.state.date, fintim))
        for i in range(1, NEVENTS):
            if   i == FSNOVA:  proutn("=== Supernova       ")
        prout("=== EVENTS from %.2f to %.2f:" % (game.state.date, fintim))
        for i in range(1, NEVENTS):
            if   i == FSNOVA:  proutn("=== Supernova       ")
@@ -2072,7 +2135,7 @@ def events():
        for l in range(1, NEVENTS):
            if game.future[l].date < datemin:
                evcode = l
        for l in range(1, NEVENTS):
            if game.future[l].date < datemin:
                evcode = l
-               if idebug:
+               if game.idebug:
                    prout("== Event %d fires" % evcode)
                datemin = game.future[l].date
        xtime = datemin-game.state.date
                    prout("== Event %d fires" % evcode)
                datemin = game.future[l].date
        xtime = datemin-game.state.date
@@ -2080,11 +2143,11 @@ def events():
        # Decrement Federation resources and recompute remaining time 
        game.state.remres -= (game.state.remkl+4*len(game.state.kcmdr))*xtime
         game.recompute()
        # Decrement Federation resources and recompute remaining time 
        game.state.remres -= (game.state.remkl+4*len(game.state.kcmdr))*xtime
         game.recompute()
-       if game.state.remtime <=0:
+       if game.state.remtime <= 0:
            finish(FDEPLETE)
            return
        # Any crew left alive? 
            finish(FDEPLETE)
            return
        # Any crew left alive? 
-       if game.state.crew <=0:
+       if game.state.crew <= 0:
            finish(FCREW)
            return
        # Is life support adequate? 
            finish(FCREW)
            return
        # Is life support adequate? 
@@ -2128,7 +2191,7 @@ def events():
        elif evcode == FSPY: # Check with spy to see if SC should tractor beam 
            if game.state.nscrem == 0 or \
                ictbeam or istract or \
        elif evcode == FSPY: # Check with spy to see if SC should tractor beam 
            if game.state.nscrem == 0 or \
                ictbeam or istract or \
-                game.condition=="docked" or game.isatb==1 or game.iscate:
+                game.condition == "docked" or game.isatb == 1 or game.iscate:
                return
            if game.ientesc or \
                (game.energy<2000 and game.torps<4 and game.shield < 1250) or \
                return
            if game.ientesc or \
                (game.energy<2000 and game.torps<4 and game.shield < 1250) or \
@@ -2166,15 +2229,15 @@ def events():
                 continue
             try:
                 for ibq in game.state.baseq:
                 continue
             try:
                 for ibq in game.state.baseq:
-                   for cmdr in game.state.kcmdr: 
-                       if ibq == cmdr and ibq != game.quadrant and ibq != game.state.kscmdr:
-                           raise ibq
+                    for cmdr in game.state.kcmdr: 
+                        if ibq == cmdr and ibq != game.quadrant and ibq != game.state.kscmdr:
+                            raise JumpOut
                 else:
                     # no match found -- try later 
                     schedule(FBATTAK, expran(0.3*game.intime))
                     unschedule(FCDBAS)
                     continue
                 else:
                     # no match found -- try later 
                     schedule(FBATTAK, expran(0.3*game.intime))
                     unschedule(FCDBAS)
                     continue
-            except coord:
+            except JumpOut:
                 pass
            # commander + starbase combination found -- launch attack 
            game.battle = ibq
                 pass
            # commander + starbase combination found -- launch attack 
            game.battle = ibq
@@ -2202,7 +2265,7 @@ def events():
            game.battle = game.state.kscmdr
            destroybase()
        elif evcode == FCDBAS: # Commander succeeds in destroying base 
            game.battle = game.state.kscmdr
            destroybase()
        elif evcode == FCDBAS: # Commander succeeds in destroying base 
-           if evcode==FCDBAS:
+           if evcode == FCDBAS:
                unschedule(FCDBAS)
                 if not game.state.baseq() \
                        or not game.state.galaxy[game.battle.i][game.battle.j].starbase:
                unschedule(FCDBAS)
                 if not game.state.baseq() \
                        or not game.state.galaxy[game.battle.i][game.battle.j].starbase:
@@ -2270,7 +2333,7 @@ def events():
                     break
             else:
                # can't seem to find one; ignore this call 
                     break
             else:
                # can't seem to find one; ignore this call 
-               if idebug:
+               if game.idebug:
                    prout("=== Couldn't find location for distress event.")
                continue
            # got one!!  Schedule its enslavement 
                    prout("=== Couldn't find location for distress event.")
                continue
            # got one!!  Schedule its enslavement 
@@ -2280,7 +2343,7 @@ def events():
            # tell the captain about it if we can 
            if communicating():
                prout(_("Uhura- Captain, %s in Quadrant %s reports it is under attack") \
            # tell the captain about it if we can 
            if communicating():
                prout(_("Uhura- Captain, %s in Quadrant %s reports it is under attack") \
-                        % (q.planet, `w`))
+                        % (q.planet, repr(w)))
                prout(_("by a Klingon invasion fleet."))
                if cancelrest():
                    return
                prout(_("by a Klingon invasion fleet."))
                if cancelrest():
                    return
@@ -2311,11 +2374,11 @@ def events():
            if q.klingons <= 0:
                q.status = "secure"
                continue
            if q.klingons <= 0:
                q.status = "secure"
                continue
-           if game.state.remkl >=MAXKLGAME:
+           if game.state.remkl >= MAXKLGAME:
                continue                # full right now 
            # reproduce one Klingon 
            w = ev.quadrant
                continue                # full right now 
            # reproduce one Klingon 
            w = ev.quadrant
-            m = coord()
+            m = Coord()
            if game.klhere >= MAXKLQUAD:
                 try:
                     # this quadrant not ok, pick an adjacent one 
            if game.klhere >= MAXKLQUAD:
                 try:
                     # this quadrant not ok, pick an adjacent one 
@@ -2327,10 +2390,10 @@ def events():
                             # check for this quad ok (not full & no snova) 
                             if q.klingons >= MAXKLQUAD or q.supernova:
                                 continue
                             # check for this quad ok (not full & no snova) 
                             if q.klingons >= MAXKLQUAD or q.supernova:
                                 continue
-                            raise "FOUNDIT"
+                            raise JumpOut
                     else:
                         continue       # search for eligible quadrant failed
                     else:
                         continue       # search for eligible quadrant failed
-                except "FOUNDIT":
+                except JumpOut:
                     w = m
            # deliver the child 
            game.state.remkl += 1
                     w = m
            # deliver the child 
            game.state.remkl += 1
@@ -2367,7 +2430,7 @@ def wait():
        return
     if delay >= game.state.remtime or len(game.enemies) != 0:
        proutn(_("Are you sure? "))
        return
     if delay >= game.state.remtime or len(game.enemies) != 0:
        proutn(_("Are you sure? "))
-       if ja() == False:
+       if not ja():
            return
     # Alternate resting periods (events) with attacks 
     game.resting = True
            return
     # Alternate resting periods (events) with attacks 
     game.resting = True
@@ -2403,8 +2466,8 @@ def wait():
 
 def nova(nov):
     "Star goes nova." 
 
 def nova(nov):
     "Star goes nova." 
-    course = (0.0, 10.5, 12.0, 1.5, 9.0, 0.0, 3.0, 7.5, 6.0, 4.5)
-    newc = coord(); neighbor = coord(); bump = coord(0, 0)
+    ncourse = (0.0, 10.5, 12.0, 1.5, 9.0, 0.0, 3.0, 7.5, 6.0, 4.5)
+    newc = Coord(); neighbor = Coord(); bump = Coord(0, 0)
     if withprob(0.05):
        # Wow! We've supernova'ed 
        supernova(game.quadrant)
     if withprob(0.05):
        # Wow! We've supernova'ed 
        supernova(game.quadrant)
@@ -2418,11 +2481,11 @@ def nova(nov):
     hits = [nov]
     kount = 0
     while hits:
     hits = [nov]
     kount = 0
     while hits:
-        offset = coord()
+        offset = Coord()
         start = hits.pop()
         for offset.i in range(-1, 1+1):
             for offset.j in range(-1, 1+1):
         start = hits.pop()
         for offset.i in range(-1, 1+1):
             for offset.j in range(-1, 1+1):
-                if offset.j==0 and offset.i==0:
+                if offset.j == 0 and offset.i == 0:
                     continue
                 neighbor = start + offset
                 if not neighbor.valid_sector():
                     continue
                 neighbor = start + offset
                 if not neighbor.valid_sector():
@@ -2449,7 +2512,7 @@ def nova(nov):
                     if iquad == 'P':
                         game.state.nplankl += 1
                     else:
                     if iquad == 'P':
                         game.state.nplankl += 1
                     else:
-                        game.state.worldkl += 1
+                        game.state.nworldkl += 1
                     prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
                     game.iplnet.pclass = "destroyed"
                     game.iplnet = None
                     prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
                     game.iplnet.pclass = "destroyed"
                     game.iplnet = None
@@ -2484,7 +2547,7 @@ def nova(nov):
                         finish(FNOVA)
                         return
                     # add in course nova contributes to kicking starship
                         finish(FNOVA)
                         return
                     # add in course nova contributes to kicking starship
-                    bump += (game.sector-hits[mm]).sgn()
+                    bump += (game.sector-hits[-1]).sgn()
                 elif iquad == 'K': # kill klingon 
                     deadkl(neighbor, iquad, neighbor)
                 elif iquad in ('C','S','R'): # Damage/destroy big enemies 
                 elif iquad == 'K': # kill klingon 
                     deadkl(neighbor, iquad, neighbor)
                 elif iquad in ('C','S','R'): # Damage/destroy big enemies 
@@ -2495,7 +2558,7 @@ def nova(nov):
                     if game.enemies[ll].power <= 0.0:
                         deadkl(neighbor, iquad, neighbor)
                         break
                     if game.enemies[ll].power <= 0.0:
                         deadkl(neighbor, iquad, neighbor)
                         break
-                    newc = neighbor + neighbor - hits[mm]
+                    newc = neighbor + neighbor - hits[-1]
                     proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged"))
                     if not newc.valid_sector():
                         # can't leave quadrant 
                     proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged"))
                     if not newc.valid_sector():
                         # can't leave quadrant 
@@ -2517,17 +2580,17 @@ def nova(nov):
                     game.enemies[ll].move(newc)
     # Starship affected by nova -- kick it away. 
     dist = kount*0.1
                     game.enemies[ll].move(newc)
     # Starship affected by nova -- kick it away. 
     dist = kount*0.1
-    direc = course[3*(bump.i+1)+bump.j+2]
+    direc = ncourse[3*(bump.i+1)+bump.j+2]
     if direc == 0.0:
        dist = 0.0
     if dist == 0.0:
        return
     if direc == 0.0:
        dist = 0.0
     if dist == 0.0:
        return
-    course = course(bearing=direc, distance=dist)
-    game.optime = course.time(warp=4)
+    scourse = course(bearing=direc, distance=dist)
+    game.optime = scourse.time(warp=4)
     skip(1)
     prout(_("Force of nova displaces starship."))
     skip(1)
     prout(_("Force of nova displaces starship."))
-    imove(course, noattack=True)
-    game.optime = course.time(warp=4)
+    imove(scourse, noattack=True)
+    game.optime = scourse.time(warp=4)
     return
        
 def supernova(w):
     return
        
 def supernova(w):
@@ -2538,7 +2601,7 @@ def supernova(w):
     else:
        # Scheduled supernova -- select star at random. 
        stars = 0
     else:
        # Scheduled supernova -- select star at random. 
        stars = 0
-        nq = coord()
+        nq = Coord()
        for nq.i in range(GALSIZE):
            for nq.j in range(GALSIZE):
                stars += game.state.galaxy[nq.i][nq.j].stars
        for nq.i in range(GALSIZE):
            for nq.j in range(GALSIZE):
                stars += game.state.galaxy[nq.i][nq.j].stars
@@ -2552,9 +2615,9 @@ def supernova(w):
                    break
            if num <=0:
                break
                    break
            if num <=0:
                break
-       if idebug:
+       if game.idebug:
            proutn("=== Super nova here?")
            proutn("=== Super nova here?")
-           if ja() == True:
+           if ja():
                nq = game.quadrant
     if not nq == game.quadrant or game.justin:
        # it isn't here, or we just entered (treat as enroute) 
                nq = game.quadrant
     if not nq == game.quadrant or game.justin:
        # it isn't here, or we just entered (treat as enroute) 
@@ -2563,7 +2626,7 @@ def supernova(w):
            prout(_("Message from Starfleet Command       Stardate %.2f") % game.state.date)
            prout(_("     Supernova in Quadrant %s; caution advised.") % nq)
     else:
            prout(_("Message from Starfleet Command       Stardate %.2f") % game.state.date)
            prout(_("     Supernova in Quadrant %s; caution advised.") % nq)
     else:
-       ns = coord()
+       ns = Coord()
        # we are in the quadrant! 
        num = randrange(game.state.galaxy[nq.i][nq.j].stars) + 1
        for ns.i in range(QUADSIZE):
        # we are in the quadrant! 
        num = randrange(game.state.galaxy[nq.i][nq.j].stars) + 1
        for ns.i in range(QUADSIZE):
@@ -2655,7 +2718,6 @@ def selfdestruct():
     prout(_("SELF-DESTRUCT-SEQUENCE-WILL-BE-ABORTED"))
     skip(1)
     scanner.next()
     prout(_("SELF-DESTRUCT-SEQUENCE-WILL-BE-ABORTED"))
     skip(1)
     scanner.next()
-    scanner.chew()
     if game.passwd != scanner.token:
        prouts(_("PASSWORD-REJECTED;"))
        skip(1)
     if game.passwd != scanner.token:
        prouts(_("PASSWORD-REJECTED;"))
        skip(1)
@@ -2683,11 +2745,9 @@ def kaboom():
     skip(1)
     if len(game.enemies) != 0:
        whammo = 25.0 * game.energy
     skip(1)
     if len(game.enemies) != 0:
        whammo = 25.0 * game.energy
-       l=1
-       while l <= len(game.enemies):
+       for l in range(len(game.enemies)):
            if game.enemies[l].power*game.enemies[l].kdist <= whammo: 
                deadkl(game.enemies[l].location, game.quad[game.enemies[l].location.i][game.enemies[l].location.j], game.enemies[l].location)
            if game.enemies[l].power*game.enemies[l].kdist <= whammo: 
                deadkl(game.enemies[l].location, game.quad[game.enemies[l].location.i][game.enemies[l].location.j], game.enemies[l].location)
-           l += 1
     finish(FDILITHIUM)
                                
 def killrate():
     finish(FDILITHIUM)
                                
 def killrate():
@@ -2768,12 +2828,12 @@ def finish(ifin):
                    prout(_("Now you can retire and write your own Star Trek game!"))
                    skip(1)
                elif game.skill >= SKILL_EXPERT:
                    prout(_("Now you can retire and write your own Star Trek game!"))
                    skip(1)
                elif game.skill >= SKILL_EXPERT:
-                   if game.thawed and not idebug:
+                   if game.thawed and not game.idebug:
                        prout(_("You cannot get a citation, so..."))
                    else:
                        proutn(_("Do you want your Commodore Emeritus Citation printed? "))
                        scanner.chew()
                        prout(_("You cannot get a citation, so..."))
                    else:
                        proutn(_("Do you want your Commodore Emeritus Citation printed? "))
                        scanner.chew()
-                       if ja() == True:
+                       if ja():
                            igotit = True
            # Only grant long life if alive (original didn't!)
            skip(1)
                            igotit = True
            # Only grant long life if alive (original didn't!)
            skip(1)
@@ -2911,11 +2971,10 @@ def finish(ifin):
 def score():
     "Compute player's score."
     timused = game.state.date - game.indate
 def score():
     "Compute player's score."
     timused = game.state.date - game.indate
-    iskill = game.skill
     if (timused == 0 or (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0) and timused < 5.0:
        timused = 5.0
     if (timused == 0 or (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0) and timused < 5.0:
        timused = 5.0
-    perdate = killrate()
-    ithperd = 500*perdate + 0.5
+    game.perdate = killrate()
+    ithperd = 500*game.perdate + 0.5
     iwon = 0
     if game.gamewon:
        iwon = 100*game.skill
     iwon = 0
     if game.gamewon:
        iwon = 100*game.skill
@@ -2925,7 +2984,7 @@ def score():
        klship = 1
     else:
        klship = 2
        klship = 1
     else:
        klship = 2
-    iscore = 10*(game.inkling - game.state.remkl) \
+    game.score = 10*(game.inkling - game.state.remkl) \
              + 50*(game.incom - len(game.state.kcmdr)) \
              + ithperd + iwon \
              + 20*(game.inrom - game.state.nromrem) \
              + 50*(game.incom - len(game.state.kcmdr)) \
              + ithperd + iwon \
              + 20*(game.inrom - game.state.nromrem) \
@@ -2933,7 +2992,7 @@ def score():
             - game.state.nromrem \
              - badpoints()
     if not game.alive:
             - game.state.nromrem \
              - badpoints()
     if not game.alive:
-       iscore -= 200
+       game.score -= 200
     skip(2)
     prout(_("Your score --"))
     if game.inrom - game.state.nromrem:
     skip(2)
     prout(_("Your score --"))
     if game.inrom - game.state.nromrem:
@@ -2953,7 +3012,7 @@ def score():
              (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem)))
     if ithperd:
        prout(_("%6.2f Klingons per stardate              %5d") %
              (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem)))
     if ithperd:
        prout(_("%6.2f Klingons per stardate              %5d") %
-             (perdate, ithperd))
+             (game.perdate, ithperd))
     if game.state.starkl:
        prout(_("%6d stars destroyed by your action     %5d") %
              (game.state.starkl, -5*game.state.starkl))
     if game.state.starkl:
        prout(_("%6d stars destroyed by your action     %5d") %
              (game.state.starkl, -5*game.state.starkl))
@@ -2989,7 +3048,7 @@ def score():
        elif game.skill ==  SKILL_EMERITUS:     proutn(_("Emeritus game"))
        prout("           %5d" % iwon)
     skip(1)
        elif game.skill ==  SKILL_EMERITUS:     proutn(_("Emeritus game"))
        prout("           %5d" % iwon)
     skip(1)
-    prout(_("TOTAL SCORE                               %5d") % iscore)
+    prout(_("TOTAL SCORE                               %5d") % game.score)
 
 def plaque():
     "Emit winner's commemmorative plaque." 
 
 def plaque():
     "Emit winner's commemmorative plaque." 
@@ -3045,8 +3104,8 @@ def plaque():
     timestring = time.ctime()
     fp.write(_("                                                 This day of %.6s %.4s, %.8s\n\n") %
                     (timestring+4, timestring+20, timestring+11))
     timestring = time.ctime()
     fp.write(_("                                                 This day of %.6s %.4s, %.8s\n\n") %
                     (timestring+4, timestring+20, timestring+11))
-    fp.write(_("                                                        Your score:  %d\n\n") % iscore)
-    fp.write(_("                                                    Klingons per stardate:  %.2f\n") % perdate)
+    fp.write(_("                                                        Your score:  %d\n\n") % game.score)
+    fp.write(_("                                                    Klingons per stardate:  %.2f\n") % game.perdate)
     fp.close()
 
 # Code from io.c begins here
     fp.close()
 
 # Code from io.c begins here
@@ -3085,16 +3144,16 @@ def iostart():
        curses.nonl()
        curses.cbreak()
         if game.options & OPTION_COLOR:
        curses.nonl()
        curses.cbreak()
         if game.options & OPTION_COLOR:
-            curses.start_color();
+            curses.start_color()
             curses.use_default_colors()
             curses.use_default_colors()
-            curses.init_pair(curses.COLOR_BLACK,   curses.COLOR_BLACK, -1);
-            curses.init_pair(curses.COLOR_GREEN,   curses.COLOR_GREEN, -1);
-            curses.init_pair(curses.COLOR_RED,     curses.COLOR_RED, -1);
-            curses.init_pair(curses.COLOR_CYAN,    curses.COLOR_CYAN, -1);
-            curses.init_pair(curses.COLOR_WHITE,   curses.COLOR_WHITE, -1);
-            curses.init_pair(curses.COLOR_MAGENTA, curses.COLOR_MAGENTA, -1);
-            curses.init_pair(curses.COLOR_BLUE,    curses.COLOR_BLUE, -1);
-            curses.init_pair(curses.COLOR_YELLOW,  curses.COLOR_YELLOW, -1);
+            curses.init_pair(curses.COLOR_BLACK,   curses.COLOR_BLACK, -1)
+            curses.init_pair(curses.COLOR_GREEN,   curses.COLOR_GREEN, -1)
+            curses.init_pair(curses.COLOR_RED,     curses.COLOR_RED, -1)
+            curses.init_pair(curses.COLOR_CYAN,    curses.COLOR_CYAN, -1)
+            curses.init_pair(curses.COLOR_WHITE,   curses.COLOR_WHITE, -1)
+            curses.init_pair(curses.COLOR_MAGENTA, curses.COLOR_MAGENTA, -1)
+            curses.init_pair(curses.COLOR_BLUE,    curses.COLOR_BLUE, -1)
+            curses.init_pair(curses.COLOR_YELLOW,  curses.COLOR_YELLOW, -1)
         global fullscreen_window, srscan_window, report_window, status_window
         global lrscan_window, message_window, prompt_window
         (rows, columns)   = stdscr.getmaxyx()
         global fullscreen_window, srscan_window, report_window, status_window
         global lrscan_window, message_window, prompt_window
         (rows, columns)   = stdscr.getmaxyx()
@@ -3145,25 +3204,20 @@ def pause_game():
         global linecount
         sys.stdout.write('\n')
         proutn(prompt)
         global linecount
         sys.stdout.write('\n')
         proutn(prompt)
-        raw_input()
-        for j in range(rows):
-            sys.stdout.write('\n')
+        if not replayfp:
+            raw_input()
+        sys.stdout.write('\n' * rows)
         linecount = 0
 
 def skip(i):
     "Skip i lines.  Pause game if this would cause a scrolling event."
     for dummy in range(i):
        if game.options & OPTION_CURSES:
         linecount = 0
 
 def skip(i):
     "Skip i lines.  Pause game if this would cause a scrolling event."
     for dummy in range(i):
        if game.options & OPTION_CURSES:
-            (y, x) = curwnd.getyx()
-            (my, mx) = curwnd.getmaxyx()
-           if curwnd == message_window and y >= my - 2:
-               pause_game()
-               clrscr()
-           else:
-                try:
-                    curwnd.move(y+1, 0)
-                except curses.error:
-                    pass
+           (y, x) = curwnd.getyx()
+           try:
+               curwnd.move(y+1, 0)
+           except curses.error:
+               pass
        else:
             global linecount
            linecount += 1
        else:
             global linecount
            linecount += 1
@@ -3175,6 +3229,14 @@ def skip(i):
 def proutn(line):
     "Utter a line with no following line feed."
     if game.options & OPTION_CURSES:
 def proutn(line):
     "Utter a line with no following line feed."
     if game.options & OPTION_CURSES:
+       (y, x) = curwnd.getyx()
+       (my, mx) = curwnd.getmaxyx()
+       if curwnd == message_window and y >= my - 2:
+           pause_game()
+           clrscr()
+        # Uncomment this to debug curses problems
+        if logfp:
+            logfp.write("#curses: at %s proutn(%s)\n" % ((y, x), repr(line)))
        curwnd.addstr(line)
        curwnd.refresh()
     else:
        curwnd.addstr(line)
        curwnd.refresh()
     else:
@@ -3224,8 +3286,31 @@ def setwnd(wnd):
     "Change windows -- OK for this to be a no-op in tty mode."
     global curwnd
     if game.options & OPTION_CURSES:
     "Change windows -- OK for this to be a no-op in tty mode."
     global curwnd
     if game.options & OPTION_CURSES:
+        # Uncomment this to debug curses problems
+        if logfp:
+            if wnd == fullscreen_window:
+                legend = "fullscreen"
+            elif wnd == srscan_window:
+                legend = "srscan"
+            elif wnd == report_window:
+                legend = "report"
+            elif wnd == status_window:
+                legend = "status"
+            elif wnd == lrscan_window:
+                legend = "lrscan"
+            elif wnd == message_window:
+                legend = "message"
+            elif wnd == prompt_window:
+                legend = "prompt"
+            else:
+                legend = "unknown"
+            logfp.write("#curses: setwnd(%s)\n" % legend)
         curwnd = wnd
         curwnd = wnd
-        curses.curs_set(wnd == fullscreen_window or wnd == message_window or wnd == prompt_window)
+        # Some curses implementations get confused when you try this.
+        try:
+            curses.curs_set(wnd in (fullscreen_window, message_window, prompt_window))
+        except curses.error:
+            pass
 
 def clreol():
     "Clear to end of line -- can be a no-op in tty mode" 
 
 def clreol():
     "Clear to end of line -- can be a no-op in tty mode" 
@@ -3237,47 +3322,47 @@ def clrscr():
     "Clear screen -- can be a no-op in tty mode."
     global linecount
     if game.options & OPTION_CURSES:
     "Clear screen -- can be a no-op in tty mode."
     global linecount
     if game.options & OPTION_CURSES:
-       curwnd.clear()
-       curwnd.move(0, 0)
-       curwnd.refresh()
+        curwnd.clear()
+        curwnd.move(0, 0)
+        curwnd.refresh()
     linecount = 0
 
 def textcolor(color=DEFAULT):
     if game.options & OPTION_COLOR:
        if color == DEFAULT: 
     linecount = 0
 
 def textcolor(color=DEFAULT):
     if game.options & OPTION_COLOR:
        if color == DEFAULT: 
-           curwnd.attrset(0);
+           curwnd.attrset(0)
        elif color ==  BLACK: 
        elif color ==  BLACK: 
-           curwnd.attron(curses.color_pair(curses.COLOR_BLACK));
+           curwnd.attron(curses.color_pair(curses.COLOR_BLACK))
        elif color ==  BLUE: 
        elif color ==  BLUE: 
-           curwnd.attron(curses.color_pair(curses.COLOR_BLUE));
+           curwnd.attron(curses.color_pair(curses.COLOR_BLUE))
        elif color ==  GREEN: 
        elif color ==  GREEN: 
-           curwnd.attron(curses.color_pair(curses.COLOR_GREEN));
+           curwnd.attron(curses.color_pair(curses.COLOR_GREEN))
        elif color ==  CYAN: 
        elif color ==  CYAN: 
-           curwnd.attron(curses.color_pair(curses.COLOR_CYAN));
+           curwnd.attron(curses.color_pair(curses.COLOR_CYAN))
        elif color ==  RED: 
        elif color ==  RED: 
-           curwnd.attron(curses.color_pair(curses.COLOR_RED));
+           curwnd.attron(curses.color_pair(curses.COLOR_RED))
        elif color ==  MAGENTA: 
        elif color ==  MAGENTA: 
-           curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA));
+           curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA))
        elif color ==  BROWN: 
        elif color ==  BROWN: 
-           curwnd.attron(curses.color_pair(curses.COLOR_YELLOW));
+           curwnd.attron(curses.color_pair(curses.COLOR_YELLOW))
        elif color ==  LIGHTGRAY: 
        elif color ==  LIGHTGRAY: 
-           curwnd.attron(curses.color_pair(curses.COLOR_WHITE));
+           curwnd.attron(curses.color_pair(curses.COLOR_WHITE))
        elif color ==  DARKGRAY: 
        elif color ==  DARKGRAY: 
-           curwnd.attron(curses.color_pair(curses.COLOR_BLACK) | curses.A_BOLD);
+           curwnd.attron(curses.color_pair(curses.COLOR_BLACK) | curses.A_BOLD)
        elif color ==  LIGHTBLUE: 
        elif color ==  LIGHTBLUE: 
-           curwnd.attron(curses.color_pair(curses.COLOR_BLUE) | curses.A_BOLD);
+           curwnd.attron(curses.color_pair(curses.COLOR_BLUE) | curses.A_BOLD)
        elif color ==  LIGHTGREEN: 
        elif color ==  LIGHTGREEN: 
-           curwnd.attron(curses.color_pair(curses.COLOR_GREEN) | curses.A_BOLD);
+           curwnd.attron(curses.color_pair(curses.COLOR_GREEN) | curses.A_BOLD)
        elif color ==  LIGHTCYAN: 
        elif color ==  LIGHTCYAN: 
-           curwnd.attron(curses.color_pair(curses.COLOR_CYAN) | curses.A_BOLD);
+           curwnd.attron(curses.color_pair(curses.COLOR_CYAN) | curses.A_BOLD)
        elif color ==  LIGHTRED: 
        elif color ==  LIGHTRED: 
-           curwnd.attron(curses.color_pair(curses.COLOR_RED) | curses.A_BOLD);
+           curwnd.attron(curses.color_pair(curses.COLOR_RED) | curses.A_BOLD)
        elif color ==  LIGHTMAGENTA: 
        elif color ==  LIGHTMAGENTA: 
-           curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA) | curses.A_BOLD);
+           curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA) | curses.A_BOLD)
        elif color ==  YELLOW: 
        elif color ==  YELLOW: 
-           curwnd.attron(curses.color_pair(curses.COLOR_YELLOW) | curses.A_BOLD);
+           curwnd.attron(curses.color_pair(curses.COLOR_YELLOW) | curses.A_BOLD)
        elif color ==  WHITE:
        elif color ==  WHITE:
-           curwnd.attron(curses.color_pair(curses.COLOR_WHITE) | curses.A_BOLD);
+           curwnd.attron(curses.color_pair(curses.COLOR_WHITE) | curses.A_BOLD)
 
 def highvideo():
     if game.options & OPTION_COLOR:
 
 def highvideo():
     if game.options & OPTION_COLOR:
@@ -3341,7 +3426,7 @@ def warble():
        #nosound()
         pass
 
        #nosound()
         pass
 
-def tracktorpedo(origin, w, step, i, n, iquad):
+def tracktorpedo(w, step, i, n, iquad):
     "Torpedo-track animation." 
     if not game.options & OPTION_CURSES:
        if step == 1:
     "Torpedo-track animation." 
     if not game.options & OPTION_CURSES:
        if step == 1:
@@ -3401,9 +3486,9 @@ def prstat(txt, data):
 
 # Code from moving.c begins here
 
 
 # Code from moving.c begins here
 
-def imove(course=None, noattack=False):
+def imove(icourse=None, noattack=False):
     "Movement execution for warp, impulse, supernova, and tractor-beam events."
     "Movement execution for warp, impulse, supernova, and tractor-beam events."
-    w = coord()
+    w = Coord()
 
     def newquadrant(noattack):
         # Leaving quadrant -- allow final enemy attack 
 
     def newquadrant(noattack):
         # Leaving quadrant -- allow final enemy attack 
@@ -3424,17 +3509,17 @@ def imove(course=None, noattack=False):
         kinks = 0
         while True:
             kink = False
         kinks = 0
         while True:
             kink = False
-            if course.final.i < 0:
-                course.final.i = -course.final.i
+            if icourse.final.i < 0:
+                icourse.final.i = -icourse.final.i
                 kink = True
                 kink = True
-            if course.final.j < 0:
-                course.final.j = -course.final.j
+            if icourse.final.j < 0:
+                icourse.final.j = -icourse.final.j
                 kink = True
                 kink = True
-            if course.final.i >= GALSIZE*QUADSIZE:
-                course.final.i = (GALSIZE*QUADSIZE*2) - course.final.i
+            if icourse.final.i >= GALSIZE*QUADSIZE:
+                icourse.final.i = (GALSIZE*QUADSIZE*2) - icourse.final.i
                 kink = True
                 kink = True
-            if course.final.j >= GALSIZE*QUADSIZE:
-                course.final.j = (GALSIZE*QUADSIZE*2) - course.final.j
+            if icourse.final.j >= GALSIZE*QUADSIZE:
+                icourse.final.j = (GALSIZE*QUADSIZE*2) - icourse.final.j
                 kink = True
             if kink:
                 kinks += 1
                 kink = True
             if kink:
                 kinks += 1
@@ -3453,8 +3538,8 @@ def imove(course=None, noattack=False):
         # Compute final position in new quadrant 
         if trbeam: # Don't bother if we are to be beamed 
             return
         # Compute final position in new quadrant 
         if trbeam: # Don't bother if we are to be beamed 
             return
-        game.quadrant = course.final.quadrant()
-        game.sector = course.final.sector()
+        game.quadrant = icourse.final.quadrant()
+        game.sector = icourse.final.sector()
         skip(1)
         prout(_("Entering Quadrant %s.") % game.quadrant)
         game.quad[game.sector.i][game.sector.j] = game.ship
         skip(1)
         prout(_("Entering Quadrant %s.") % game.quadrant)
         game.quad[game.sector.i][game.sector.j] = game.ship
@@ -3466,7 +3551,7 @@ def imove(course=None, noattack=False):
         iquad = game.quad[h.i][h.j]
         if iquad != '.':
             # object encountered in flight path 
         iquad = game.quad[h.i][h.j]
         if iquad != '.':
             # object encountered in flight path 
-            stopegy = 50.0*course.distance/game.optime
+            stopegy = 50.0*icourse.distance/game.optime
             if iquad in ('T', 'K', 'C', 'S', 'R', '?'):
                 for enemy in game.enemies:
                     if enemy.location == game.sector:
             if iquad in ('T', 'K', 'C', 'S', 'R', '?'):
                 for enemy in game.enemies:
                     if enemy.location == game.sector:
@@ -3516,14 +3601,14 @@ def imove(course=None, noattack=False):
     if game.state.date+game.optime >= scheduled(FTBEAM):
        trbeam = True
        game.condition = "red"
     if game.state.date+game.optime >= scheduled(FTBEAM):
        trbeam = True
        game.condition = "red"
-       course.distance = course.distance*(scheduled(FTBEAM)-game.state.date)/game.optime + 0.1
+       icourse.distance = icourse.distance*(scheduled(FTBEAM)-game.state.date)/game.optime + 0.1
        game.optime = scheduled(FTBEAM) - game.state.date + 1e-5
     # Move out
     game.quad[game.sector.i][game.sector.j] = '.'
        game.optime = scheduled(FTBEAM) - game.state.date + 1e-5
     # Move out
     game.quad[game.sector.i][game.sector.j] = '.'
-    for m in range(course.moves):
-        course.next()
-        w = course.sector()
-        if course.origin.quadrant() != course.location.quadrant():
+    for m in range(icourse.moves):
+        icourse.next()
+        w = icourse.sector()
+        if icourse.origin.quadrant() != icourse.location.quadrant():
             newquadrant(noattack)
             break
         elif check_collision(w):
             newquadrant(noattack)
             break
         elif check_collision(w):
@@ -3538,7 +3623,7 @@ def imove(course=None, noattack=False):
             finald = (w-enemy.location).distance()
             enemy.kavgd = 0.5 * (finald + enemy.kdist)
             enemy.kdist = finald
             finald = (w-enemy.location).distance()
             enemy.kavgd = 0.5 * (finald + enemy.kdist)
             enemy.kdist = finald
-        game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
+        sortenemies()
         if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
             attack(torps_ok=False)
         for enemy in game.enemies:
         if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
             attack(torps_ok=False)
         for enemy in game.enemies:
@@ -3591,7 +3676,7 @@ def getcourse(isprobe):
     dquad = copy.copy(game.quadrant)
     navmode = "unspecified"
     itemp = "curt"
     dquad = copy.copy(game.quadrant)
     navmode = "unspecified"
     itemp = "curt"
-    dsect = coord()
+    dsect = Coord()
     iprompt = False
     if game.landed and not isprobe:
        prout(_("Dummy! You can't leave standard orbit until you"))
     iprompt = False
     if game.landed and not isprobe:
        prout(_("Dummy! You can't leave standard orbit until you"))
@@ -3633,7 +3718,7 @@ def getcourse(isprobe):
                prout(_("(Manual movement assumed.)"))
            navmode = "manual"
            break
                prout(_("(Manual movement assumed.)"))
            navmode = "manual"
            break
-    delta = coord()
+    delta = Coord()
     if navmode == "automatic":
        while key == "IHEOL":
            if isprobe:
     if navmode == "automatic":
        while key == "IHEOL":
            if isprobe:
@@ -3733,7 +3818,7 @@ class course:
             self.origin = cartesian(game.quadrant, game.sector)
         else:
             self.origin = cartesian(game.quadrant, origin)
             self.origin = cartesian(game.quadrant, game.sector)
         else:
             self.origin = cartesian(game.quadrant, origin)
-        self.increment = coord(-math.sin(self.angle), math.cos(self.angle))
+        self.increment = Coord(-math.sin(self.angle), math.cos(self.angle))
         bigger = max(abs(self.increment.i), abs(self.increment.j))
         self.increment /= bigger
         self.moves = int(round(10*self.distance*bigger))
         bigger = max(abs(self.increment.i), abs(self.increment.j))
         self.increment /= bigger
         self.moves = int(round(10*self.distance*bigger))
@@ -3790,26 +3875,26 @@ def impulse():
        scanner.chew()
        return
     # Make sure enough time is left for the trip 
        scanner.chew()
        return
     # Make sure enough time is left for the trip 
-    game.optime = course.dist/0.095
+    game.optime = course.distance/0.095
     if game.optime >= game.state.remtime:
        prout(_("First Officer Spock- \"Captain, our speed under impulse"))
        prout(_("power is only 0.95 sectors per stardate. Are you sure"))
        proutn(_("we dare spend the time?\" "))
     if game.optime >= game.state.remtime:
        prout(_("First Officer Spock- \"Captain, our speed under impulse"))
        prout(_("power is only 0.95 sectors per stardate. Are you sure"))
        proutn(_("we dare spend the time?\" "))
-       if ja() == False:
+       if not ja():
            return
     # Activate impulse engines and pay the cost 
     imove(course, noattack=False)
     game.ididit = True
     if game.alldone:
        return
            return
     # Activate impulse engines and pay the cost 
     imove(course, noattack=False)
     game.ididit = True
     if game.alldone:
        return
-    power = 20.0 + 100.0*course.dist
+    power = 20.0 + 100.0*course.distance
     game.energy -= power
     game.energy -= power
-    game.optime = course.dist/0.095
+    game.optime = course.distance/0.095
     if game.energy <= 0:
        finish(FNRG)
     return
 
     if game.energy <= 0:
        finish(FNRG)
     return
 
-def warp(course, involuntary):
+def warp(wcourse, involuntary):
     "ove under warp drive."
     blooey = False; twarp = False
     if not involuntary: # Not WARPX entry 
     "ove under warp drive."
     blooey = False; twarp = False
     if not involuntary: # Not WARPX entry 
@@ -3826,21 +3911,21 @@ def warp(course, involuntary):
            prout(_("  is repaired, I can only give you warp 4.\""))
            return
                # Read in course and distance
            prout(_("  is repaired, I can only give you warp 4.\""))
            return
                # Read in course and distance
-        if course==None:
+        if wcourse==None:
             try:
             try:
-                course = getcourse(isprobe=False)
+                wcourse = getcourse(isprobe=False)
             except TrekError:
                 return
        # Make sure starship has enough energy for the trip
         # Note: this formula is slightly different from the C version,
         # and lets you skate a bit closer to the edge.
             except TrekError:
                 return
        # Make sure starship has enough energy for the trip
         # Note: this formula is slightly different from the C version,
         # and lets you skate a bit closer to the edge.
-       if course.power(game.warpfac) >= game.energy:
+       if wcourse.power(game.warpfac) >= game.energy:
            # Insufficient power for trip 
            game.ididit = False
            skip(1)
            prout(_("Engineering to bridge--"))
            # Insufficient power for trip 
            game.ididit = False
            skip(1)
            prout(_("Engineering to bridge--"))
-           if not game.shldup or 0.5*power > game.energy:
-               iwarp = (game.energy/(course.dist+0.05)) ** 0.333333333
+           if not game.shldup or 0.5*wcourse.power(game.warpfac) > game.energy:
+               iwarp = (game.energy/(wcourse.distance+0.05)) ** 0.333333333
                if iwarp <= 0:
                    prout(_("We can't do it, Captain. We don't have enough energy."))
                else:
                if iwarp <= 0:
                    prout(_("We can't do it, Captain. We don't have enough energy."))
                else:
@@ -3854,7 +3939,7 @@ def warp(course, involuntary):
                prout(_("We haven't the energy to go that far with the shields up."))
            return                              
        # Make sure enough time is left for the trip 
                prout(_("We haven't the energy to go that far with the shields up."))
            return                              
        # Make sure enough time is left for the trip 
-       game.optime = course.time(game.warpfac)
+       game.optime = wcourse.time(game.warpfac)
        if game.optime >= 0.8*game.state.remtime:
            skip(1)
            prout(_("First Officer Spock- \"Captain, I compute that such"))
        if game.optime >= 0.8*game.state.remtime:
            skip(1)
            prout(_("First Officer Spock- \"Captain, I compute that such"))
@@ -3862,7 +3947,7 @@ def warp(course, involuntary):
                   (100.0*game.optime/game.state.remtime))
            prout(_(" percent of our"))
            proutn(_("  remaining time.  Are you sure this is wise?\" "))
                   (100.0*game.optime/game.state.remtime))
            prout(_(" percent of our"))
            proutn(_("  remaining time.  Are you sure this is wise?\" "))
-           if ja() == False:
+           if not ja():
                game.ididit = False
                game.optime=0 
                return
                game.ididit = False
                game.optime=0 
                return
@@ -3870,38 +3955,40 @@ def warp(course, involuntary):
     if game.warpfac > 6.0:
        # Decide if engine damage will occur
         # ESR: Seems wrong. Probability of damage goes *down* with distance? 
     if game.warpfac > 6.0:
        # Decide if engine damage will occur
         # ESR: Seems wrong. Probability of damage goes *down* with distance? 
-       prob = course.distance*(6.0-game.warpfac)**2/66.666666666
+       prob = wcourse.distance*(6.0-game.warpfac)**2/66.666666666
        if prob > randreal():
            blooey = True
        if prob > randreal():
            blooey = True
-           course.distance = randreal(course.distance)
+           wcourse.distance = randreal(wcourse.distance)
        # Decide if time warp will occur 
        # Decide if time warp will occur 
-       if 0.5*course.distance*math.pow(7.0,game.warpfac-10.0) > randreal():
+       if 0.5*wcourse.distance*math.pow(7.0,game.warpfac-10.0) > randreal():
            twarp = True
            twarp = True
-       if idebug and game.warpfac==10 and not twarp:
+       if game.idebug and game.warpfac==10 and not twarp:
            blooey = False
            proutn("=== Force time warp? ")
            blooey = False
            proutn("=== Force time warp? ")
-           if ja() == True:
+           if ja():
                twarp = True
        if blooey or twarp:
            # If time warp or engine damage, check path 
                twarp = True
        if blooey or twarp:
            # If time warp or engine damage, check path 
-           # If it is obstructed, don't do warp or damage 
-            for m in range(course.moves):
-                course.next()
-                w = course.sector()
+           # If it is obstructed, don't do warp or damage
+            look = wcourse.moves
+            while look > 0:
+                look -= 1
+                wcourse.next()
+                w = wcourse.sector()
                 if not w.valid_sector():
                     break
                if game.quad[w.i][w.j] != '.':
                    blooey = False
                    twarp = False
                 if not w.valid_sector():
                     break
                if game.quad[w.i][w.j] != '.':
                    blooey = False
                    twarp = False
-            course.reset()
+            wcourse.reset()
     # Activate Warp Engines and pay the cost 
     # Activate Warp Engines and pay the cost 
-    imove(course, noattack=False)
+    imove(wcourse, noattack=False)
     if game.alldone:
        return
     if game.alldone:
        return
-    game.energy -= course.power(game.warpfac)
+    game.energy -= wcourse.power(game.warpfac)
     if game.energy <= 0:
        finish(FNRG)
     if game.energy <= 0:
        finish(FNRG)
-    game.optime = course.time(game.warpfac)
+    game.optime = wcourse.time(game.warpfac)
     if twarp:
        timwrp()
     if blooey:
     if twarp:
        timwrp()
     if blooey:
@@ -4109,7 +4196,7 @@ def probe():
         else:
             prout(_("%d probes left") % game.nprobes)
        proutn(_("Are you sure you want to fire a probe? "))
         else:
             prout(_("%d probes left") % game.nprobes)
        proutn(_("Are you sure you want to fire a probe? "))
-       if ja() == False:
+       if not ja():
            return
     game.isarmed = False
     if key == "IHALPHA" and scanner.token == "armed":
            return
     game.isarmed = False
     if key == "IHALPHA" and scanner.token == "armed":
@@ -4183,7 +4270,7 @@ def mayday():
        elif m == 2: proutn(_("2nd"))
        elif m == 3: proutn(_("3rd"))
        proutn(_(" attempt to re-materialize ") + crmshp())
        elif m == 2: proutn(_("2nd"))
        elif m == 3: proutn(_("3rd"))
        proutn(_(" attempt to re-materialize ") + crmshp())
-       game.quad[ix][iy]=('-','o','O')[m-1]
+       game.quad[game.sector.i][game.sector.j]=('-','o','O')[m-1]
         textcolor(RED)
        warble()
        if randreal() > probf:
         textcolor(RED)
        warble()
        if randreal() > probf:
@@ -4192,16 +4279,16 @@ def mayday():
         textcolor(DEFAULT)
        curses.delay_output(500)
     if m > 3:
         textcolor(DEFAULT)
        curses.delay_output(500)
     if m > 3:
-       game.quad[ix][iy]='?'
+       game.quad[game.sector.i][game.sector.j]='?'
        game.alive = False
        drawmaps(1)
        setwnd(message_window)
        finish(FMATERIALIZE)
        return
        game.alive = False
        drawmaps(1)
        setwnd(message_window)
        finish(FMATERIALIZE)
        return
-    game.quad[ix][iy]=game.ship
-    textcolor(GREEN);
+    game.quad[game.sector.i][game.sector.j]=game.ship
+    textcolor(GREEN)
     prout(_("succeeds."))
     prout(_("succeeds."))
-    textcolor(DEFAULT);
+    textcolor(DEFAULT)
     dock(False)
     skip(1)
     prout(_("Lt. Uhura-  \"Captain, we made it!\""))
     dock(False)
     skip(1)
     prout(_("Lt. Uhura-  \"Captain, we made it!\""))
@@ -4324,15 +4411,15 @@ def survey():
            continue
        if (game.state.planets[i].known != "unknown" \
             and not game.state.planets[i].inhabited) \
            continue
        if (game.state.planets[i].known != "unknown" \
             and not game.state.planets[i].inhabited) \
-            or idebug:
+            or game.idebug:
            iknow = True
            iknow = True
-           if idebug and game.state.planets[i].known=="unknown":
+           if game.idebug and game.state.planets[i].known=="unknown":
                proutn("(Unknown) ")
            proutn(_("Quadrant %s") % game.state.planets[i].quadrant)
            proutn(_("   class "))
            proutn(game.state.planets[i].pclass)
            proutn("   ")
                proutn("(Unknown) ")
            proutn(_("Quadrant %s") % game.state.planets[i].quadrant)
            proutn(_("   class "))
            proutn(game.state.planets[i].pclass)
            proutn("   ")
-           if game.state.planets[i].crystals != present:
+           if game.state.planets[i].crystals != "present":
                proutn(_("no "))
            prout(_("dilithium crystals present."))
            if game.state.planets[i].known=="shuttle_down": 
                proutn(_("no "))
            prout(_("dilithium crystals present."))
            if game.state.planets[i].known=="shuttle_down": 
@@ -4404,7 +4491,7 @@ def beam():
        if not damaged(DSHUTTL) and (game.iplnet.known=="shuttle_down" or game.iscraft == "onship"):
            skip(1)
            proutn(_("Spock-  \"May I suggest the shuttle craft, Sir?\" "))
        if not damaged(DSHUTTL) and (game.iplnet.known=="shuttle_down" or game.iscraft == "onship"):
            skip(1)
            proutn(_("Spock-  \"May I suggest the shuttle craft, Sir?\" "))
-           if ja() == True:
+            if ja():
                shuttle()
        return
     if not game.inorbit:
                shuttle()
        return
     if not game.inorbit:
@@ -4422,7 +4509,7 @@ def beam():
        prout(_("Spock-  \"Captain, I fail to see the logic in"))
        prout(_("  exploring a planet with no dilithium crystals."))
        proutn(_("  Are you sure this is wise?\" "))
        prout(_("Spock-  \"Captain, I fail to see the logic in"))
        prout(_("  exploring a planet with no dilithium crystals."))
        proutn(_("  Are you sure this is wise?\" "))
-       if ja() == False:
+       if not ja():
            scanner.chew()
            return
     if not (game.options & OPTION_PLAIN):
            scanner.chew()
            return
     if not (game.options & OPTION_PLAIN):
@@ -4438,14 +4525,14 @@ def beam():
            if game.iplnet.known == "shuttle_down":
                prout(_("  Although the Galileo shuttle craft may still be on a surface."))
            proutn(_("  Are you sure this is wise?\" "))
            if game.iplnet.known == "shuttle_down":
                prout(_("  Although the Galileo shuttle craft may still be on a surface."))
            proutn(_("  Are you sure this is wise?\" "))
-           if ja() == False:
+           if not ja():
                scanner.chew()
                return
     if game.landed:
        # Coming from planet 
        if game.iplnet.known=="shuttle_down":
            proutn(_("Spock-  \"Wouldn't you rather take the Galileo?\" "))
                scanner.chew()
                return
     if game.landed:
        # Coming from planet 
        if game.iplnet.known=="shuttle_down":
            proutn(_("Spock-  \"Wouldn't you rather take the Galileo?\" "))
-           if ja() == True:
+           if ja():
                scanner.chew()
                return
            prout(_("Your crew hides the Galileo to prevent capture by aliens."))
                scanner.chew()
                return
            prout(_("Your crew hides the Galileo to prevent capture by aliens."))
@@ -4528,7 +4615,7 @@ def usecrystals():
     prout(_("  raw dilithium crystals into the ship's power"))
     prout(_("  system may risk a severe explosion."))
     proutn(_("  Are you sure this is wise?\" "))
     prout(_("  raw dilithium crystals into the ship's power"))
     prout(_("  system may risk a severe explosion."))
     proutn(_("  Are you sure this is wise?\" "))
-    if ja() == False:
+    if not ja():
        scanner.chew()
        return
     skip(1)
        scanner.chew()
        return
     skip(1)
@@ -4597,7 +4684,7 @@ def shuttle():
               int(100*game.optime/game.state.remtime))
        prout(_("remaining time."))
        proutn(_("Are you sure this is wise?\" "))
               int(100*game.optime/game.state.remtime))
        prout(_("remaining time."))
        proutn(_("Are you sure this is wise?\" "))
-       if ja() == False:
+       if not ja():
            game.optime = 0.0
            return
     if game.landed:
            game.optime = 0.0
            return
     if game.landed:
@@ -4606,7 +4693,7 @@ def shuttle():
            # Galileo on ship! 
            if not damaged(DTRANSP):
                proutn(_("Spock-  \"Would you rather use the transporter?\" "))
            # Galileo on ship! 
            if not damaged(DTRANSP):
                proutn(_("Spock-  \"Would you rather use the transporter?\" "))
-               if ja() == True:
+               if ja():
                    beam()
                    return
                proutn(_("Shuttle crew"))
                    beam()
                    return
                proutn(_("Shuttle crew"))
@@ -4675,7 +4762,7 @@ def deathray():
     prout(_("Spock-  \"Captain, the 'Experimental Death Ray'"))
     prout(_("  is highly unpredictible.  Considering the alternatives,"))
     proutn(_("  are you sure this is wise?\" "))
     prout(_("Spock-  \"Captain, the 'Experimental Death Ray'"))
     prout(_("  is highly unpredictible.  Considering the alternatives,"))
     proutn(_("  are you sure this is wise?\" "))
-    if ja() == False:
+    if not ja():
        return
     prout(_("Spock-  \"Acknowledged.\""))
     skip(1)
        return
     prout(_("Spock-  \"Acknowledged.\""))
     skip(1)
@@ -4739,7 +4826,6 @@ def deathray():
        finish(FDRAY)
        return
     if r <= 0.75:
        finish(FDRAY)
        return
     if r <= 0.75:
-       intj
        prouts(_("Sulu- \"Captain!  It's   --WHAT?!?!\""))
        skip(2)
        proutn(_("Spock-  \"I believe the word is"))
        prouts(_("Sulu- \"Captain!  It's   --WHAT?!?!\""))
        skip(2)
        proutn(_("Spock-  \"I believe the word is"))
@@ -4784,7 +4870,7 @@ def attackreport(curt):
 def report():
     # report on general game status 
     scanner.chew()
 def report():
     # report on general game status 
     scanner.chew()
-    s1 = "" and game.thawed and _("thawed ")
+    s1 = (game.thawed and _("thawed ")) or ""
     s2 = {1:"short", 2:"medium", 4:"long"}[game.length]
     s3 = (None, _("novice"), _("fair"),
           _("good"), _("expert"), _("emeritus"))[game.skill]
     s2 = {1:"short", 2:"medium", 4:"long"}[game.length]
     s3 = (None, _("novice"), _("fair"),
           _("good"), _("expert"), _("emeritus"))[game.skill]
@@ -4867,7 +4953,7 @@ def lrscan(silent):
         if not silent:
             proutn(" ")
         for y in range(game.quadrant.j-1, game.quadrant.j+2):
         if not silent:
             proutn(" ")
         for y in range(game.quadrant.j-1, game.quadrant.j+2):
-           if not coord(x, y).valid_quadrant():
+           if not Coord(x, y).valid_quadrant():
                 if not silent:
                     proutn("  -1")
            else:
                 if not silent:
                     proutn("  -1")
            else:
@@ -4956,7 +5042,7 @@ def sectscan(goodScan, i, j):
                    "docked":CYAN,
                    "dead":BROWN}[game.condition]) 
         if game.quad[i][j] != game.ship: 
                    "docked":CYAN,
                    "dead":BROWN}[game.condition]) 
         if game.quad[i][j] != game.ship: 
-            highvideo();
+            highvideo()
        proutn("%c " % game.quad[i][j])
         textcolor(DEFAULT)
     else:
        proutn("%c " % game.quad[i][j])
         textcolor(DEFAULT)
     else:
@@ -5056,7 +5142,7 @@ def srscan():
                
 def eta():
     "Use computer to get estimated time of arrival for a warp jump."
                
 def eta():
     "Use computer to get estimated time of arrival for a warp jump."
-    w1 = coord(); w2 = coord()
+    w1 = Coord(); w2 = Coord()
     prompt = False
     if damaged(DCOMPTR):
        prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR."))
     prompt = False
     if damaged(DCOMPTR):
        prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR."))
@@ -5198,7 +5284,6 @@ def freeze(boss):
     if key != "IHALPHA":
         huh()
         return
     if key != "IHALPHA":
         huh()
         return
-    scanner.chew()
     if '.' not in scanner.token:
         scanner.token += ".trk"
     try:
     if '.' not in scanner.token:
         scanner.token += ".trk"
     try:
@@ -5208,10 +5293,12 @@ def freeze(boss):
        return
     cPickle.dump(game, fp)
     fp.close()
        return
     cPickle.dump(game, fp)
     fp.close()
+    scanner.chew()
 
 def thaw():
 
 def thaw():
-    "Retrieve saved game." 
-    game.passwd[0] = '\0'
+    "Retrieve saved game."
+    global game
+    game.passwd = None
     key = scanner.next()
     if key == "IHEOL":
        proutn(_("File name: "))
     key = scanner.next()
     if key == "IHEOL":
        proutn(_("File name: "))
@@ -5219,7 +5306,6 @@ def thaw():
     if key != "IHALPHA":
        huh()
        return True
     if key != "IHALPHA":
        huh()
        return True
-    scanner.chew()
     if '.' not in scanner.token:
         scanner.token += ".trk"
     try:
     if '.' not in scanner.token:
         scanner.token += ".trk"
     try:
@@ -5229,6 +5315,7 @@ def thaw():
        return
     game = cPickle.load(fp)
     fp.close()
        return
     game = cPickle.load(fp)
     fp.close()
+    scanner.chew()
     return False
 
 # I used <http://www.memory-alpha.org> to find planets
     return False
 
 # I used <http://www.memory-alpha.org> to find planets
@@ -5304,7 +5391,7 @@ device = (
 
 def setup():
     "Prepare to play, set up cosmos."
 
 def setup():
     "Prepare to play, set up cosmos."
-    w = coord()
+    w = Coord()
     #  Decide how many of everything
     if choose():
        return # frozen game
     #  Decide how many of everything
     if choose():
        return # frozen game
@@ -5324,25 +5411,40 @@ def setup():
     for i in range(NDEVICES): 
        game.damage[i] = 0.0
     # Set up assorted game parameters
     for i in range(NDEVICES): 
        game.damage[i] = 0.0
     # Set up assorted game parameters
-    game.battle = coord()
+    game.battle = Coord()
     game.state.date = game.indate = 100.0 * randreal(20, 51)
     game.nkinks = game.nhelp = game.casual = game.abandoned = 0
     game.iscate = game.resting = game.imine = game.icrystl = game.icraft = False
     game.isatb = game.state.nplankl = 0
     game.state.date = game.indate = 100.0 * randreal(20, 51)
     game.nkinks = game.nhelp = game.casual = game.abandoned = 0
     game.iscate = game.resting = game.imine = game.icrystl = game.icraft = False
     game.isatb = game.state.nplankl = 0
-    game.state.starkl = game.state.basekl = 0
+    game.state.starkl = game.state.basekl = game.state.nworldkl = 0
     game.iscraft = "onship"
     game.landed = False
     game.alive = True
     game.iscraft = "onship"
     game.landed = False
     game.alive = True
+
+    # the galaxy
+    game.state.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
+    # the starchart
+    game.state.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
+
+    game.state.planets = []      # Planet information
+    game.state.baseq = []      # Base quadrant coordinates
+    game.state.kcmdr = []      # Commander quadrant coordinates
+    game.statekscmdr = Coord() # Supercommander quadrant coordinates
+
     # Starchart is functional but we've never seen it
     game.lastchart = FOREVER
     # Put stars in the galaxy
     game.instar = 0
     for i in range(GALSIZE):
        for j in range(GALSIZE):
     # Starchart is functional but we've never seen it
     game.lastchart = FOREVER
     # Put stars in the galaxy
     game.instar = 0
     for i in range(GALSIZE):
        for j in range(GALSIZE):
-           k = randrange(1, QUADSIZE**2/10+1)
+            # Can't have more stars per quadrant than fit in one decimal digit,
+            # if we do the chart representation will break. 
+           k = randrange(1, min(10, QUADSIZE**2/10))
            game.instar += k
            game.state.galaxy[i][j].stars = k
     # Locate star bases in galaxy
            game.instar += k
            game.state.galaxy[i][j].stars = k
     # Locate star bases in galaxy
+    if game.idebug:
+        prout("=== Allocating %d bases" % game.inbase)
     for i in range(game.inbase):
         while True:
             while True:
     for i in range(game.inbase):
         while True:
             while True:
@@ -5357,14 +5459,16 @@ def setup():
                distq = (w - game.state.baseq[j]).distance()
                if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75):
                    contflag = True
                distq = (w - game.state.baseq[j]).distance()
                if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75):
                    contflag = True
-                   if idebug:
+                   if game.idebug:
                        prout("=== Abandoning base #%d at %s" % (i, w))
                    break
                elif distq < 6.0 * (BASEMAX+1-game.inbase):
                        prout("=== Abandoning base #%d at %s" % (i, w))
                    break
                elif distq < 6.0 * (BASEMAX+1-game.inbase):
-                   if idebug:
+                   if game.idebug:
                        prout("=== Saving base #%d, close to #%d" % (i, j))
             if not contflag:
                 break
                        prout("=== Saving base #%d, close to #%d" % (i, j))
             if not contflag:
                 break
+        if game.idebug:
+            prout("=== Placing base #%d in quadrant %s" % (i, w))
        game.state.baseq.append(w)
        game.state.galaxy[w.i][w.j].starbase = game.state.chart[w.i][w.j].starbase = True
     # Position ordinary Klingon Battle Cruisers
        game.state.baseq.append(w)
        game.state.galaxy[w.i][w.j].starbase = game.state.chart[w.i][w.j].starbase = True
     # Position ordinary Klingon Battle Cruisers
@@ -5402,7 +5506,7 @@ def setup():
             w = randplace(GALSIZE) 
             if game.state.galaxy[w.i][w.j].planet == None:
                 break
             w = randplace(GALSIZE) 
             if game.state.galaxy[w.i][w.j].planet == None:
                 break
-        new = planet()
+        new = Planet()
        new.quadrant = w
         new.crystals = "absent"
        if (game.options & OPTION_WORLDS) and i < NINHAB:
        new.quadrant = w
         new.crystals = "absent"
        if (game.options & OPTION_WORLDS) and i < NINHAB:
@@ -5490,6 +5594,8 @@ def setup():
     if game.state.nscrem:
        prout(_("  YOU'LL NEED IT."))
     waitfor()
     if game.state.nscrem:
        prout(_("  YOU'LL NEED IT."))
     waitfor()
+    clrscr()
+    setwnd(message_window)
     newqad()
     if len(game.enemies) - (thing == game.quadrant) - (game.tholian != None):
        game.shldup = True
     newqad()
     if len(game.enemies) - (thing == game.quadrant) - (game.tholian != None):
        game.shldup = True
@@ -5502,8 +5608,9 @@ def choose():
        game.tourn = game.length = 0
        game.thawed = False
        game.skill = SKILL_NONE
        game.tourn = game.length = 0
        game.thawed = False
        game.skill = SKILL_NONE
-       if not scanner.inqueue: # Can start with command line options 
-           proutn(_("Would you like a regular, tournament, or saved game? "))
+       scanner.chew()
+#      if not scanner.inqueue: # Can start with command line options 
+       proutn(_("Would you like a regular, tournament, or saved game? "))
         scanner.next()
         if scanner.sees("tournament"):
            while scanner.next() == "IHEOL":
         scanner.next()
         if scanner.sees("tournament"):
            while scanner.next() == "IHEOL":
@@ -5529,7 +5636,7 @@ def choose():
            return True
         if scanner.sees("regular"):
            break
            return True
         if scanner.sees("regular"):
            break
-       proutn(_("What is \"%s\"?") % scanner.token)
+       proutn(_("What is \"%s\"? ") % scanner.token)
        scanner.chew()
     while game.length==0 or game.skill==SKILL_NONE:
        if scanner.next() == "IHALPHA":
        scanner.chew()
     while game.length==0 or game.skill==SKILL_NONE:
        if scanner.next() == "IHALPHA":
@@ -5579,7 +5686,7 @@ def choose():
     game.options &=~ OPTION_COLOR
     setpassword()
     if game.passwd == "debug":
     game.options &=~ OPTION_COLOR
     setpassword()
     if game.passwd == "debug":
-       idebug = True
+       game.idebug = True
        prout("=== Debug mode enabled.")
     # Use parameters to generate initial values of things
     game.damfac = 0.5 * game.skill
        prout("=== Debug mode enabled.")
     # Use parameters to generate initial values of things
     game.damfac = 0.5 * game.skill
@@ -5623,7 +5730,11 @@ def newcnd():
 
 def newkling():
     "Drop new Klingon into current quadrant."
 
 def newkling():
     "Drop new Klingon into current quadrant."
-    return enemy('K', loc=dropin(), power=randreal(300,450)+25.0*game.skill)
+    return Enemy('K', loc=dropin(), power=randreal(300,450)+25.0*game.skill)
+
+def sortenemies():
+    "Sort enemies by distance so 'nearest' is meaningful."
+    game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
 
 def newqad():
     "Set up a new state of quadrant, for when we enter or re-enter it."
 
 def newqad():
     "Set up a new state of quadrant, for when we enter or re-enter it."
@@ -5665,7 +5776,7 @@ def newqad():
            game.iscate = (game.state.remkl > 1)
     # Put in Romulans if needed
     for i in range(q.romulans):
            game.iscate = (game.state.remkl > 1)
     # Put in Romulans if needed
     for i in range(q.romulans):
-        enemy('R', loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill)
+        Enemy('R', loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill)
     # If quadrant needs a starbase, put it in
     if q.starbase:
        game.base = dropin('B')
     # If quadrant needs a starbase, put it in
     if q.starbase:
        game.base = dropin('B')
@@ -5690,7 +5801,7 @@ def newqad():
            prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!"))
     # Put in THING if needed
     if thing == game.quadrant:
            prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!"))
     # Put in THING if needed
     if thing == game.quadrant:
-        enemy(type='?', loc=dropin(),
+        Enemy(etype='?', loc=dropin(),
                   power=randreal(6000,6500.0)+250.0*game.skill)
         if not damaged(DSRSENS):
             skip(1)
                   power=randreal(6000,6500.0)+250.0*game.skill)
         if not damaged(DSRSENS):
             skip(1)
@@ -5701,13 +5812,13 @@ def newqad():
        if (game.skill < SKILL_GOOD and withprob(0.02)) or \
            (game.skill == SKILL_GOOD and withprob(0.05)) or \
             (game.skill > SKILL_GOOD and withprob(0.08)):
        if (game.skill < SKILL_GOOD and withprob(0.02)) or \
            (game.skill == SKILL_GOOD and withprob(0.05)) or \
             (game.skill > SKILL_GOOD and withprob(0.08)):
-            w = coord()
+            w = Coord()
             while True:
                w.i = withprob(0.5) * (QUADSIZE-1)
                w.j = withprob(0.5) * (QUADSIZE-1)
                 if game.quad[w.i][w.j] == '.':
                     break
             while True:
                w.i = withprob(0.5) * (QUADSIZE-1)
                w.j = withprob(0.5) * (QUADSIZE-1)
                 if game.quad[w.i][w.j] == '.':
                     break
-            game.tholian = enemy(type='T', loc=w,
+            game.tholian = Enemy(etype='T', loc=w,
                                  power=randrange(100, 500) + 25.0*game.skill)
            # Reserve unoccupied corners 
            if game.quad[0][0]=='.':
                                  power=randrange(100, 500) + 25.0*game.skill)
            # Reserve unoccupied corners 
            if game.quad[0][0]=='.':
@@ -5718,7 +5829,7 @@ def newqad():
                game.quad[QUADSIZE-1][0] = 'X'
            if game.quad[QUADSIZE-1][QUADSIZE-1]=='.':
                game.quad[QUADSIZE-1][QUADSIZE-1] = 'X'
                game.quad[QUADSIZE-1][0] = 'X'
            if game.quad[QUADSIZE-1][QUADSIZE-1]=='.':
                game.quad[QUADSIZE-1][QUADSIZE-1] = 'X'
-    game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
+    sortenemies()
     # And finally the stars
     for i in range(q.stars):
        dropin('*')
     # And finally the stars
     for i in range(q.stars):
        dropin('*')
@@ -5749,59 +5860,61 @@ def setpassword():
                break
     else:
         game.passwd = ""
                break
     else:
         game.passwd = ""
-        for i in range(3):
-           game.passwd += chr(ord('a')+randrange(26))
+        game.passwd += chr(ord('a')+randrange(26))
+        game.passwd += chr(ord('a')+randrange(26))
+        game.passwd += chr(ord('a')+randrange(26))
 
 # Code from sst.c begins here
 
 
 # Code from sst.c begins here
 
-commands = {
-    "SRSCAN":          OPTION_TTY,
-    "STATUS":          OPTION_TTY,
-    "REQUEST":         OPTION_TTY,
-    "LRSCAN":          OPTION_TTY,
-    "PHASERS":         0,
-    "TORPEDO":         0,
-    "PHOTONS":         0,
-    "MOVE":            0,
-    "SHIELDS":         0,
-    "DOCK":            0,
-    "DAMAGES":         0,
-    "CHART":           0,
-    "IMPULSE":         0,
-    "REST":            0,
-    "WARP":            0,
-    "SCORE":           0,
-    "SENSORS":         OPTION_PLANETS,
-    "ORBIT":           OPTION_PLANETS,
-    "TRANSPORT":       OPTION_PLANETS,
-    "MINE":            OPTION_PLANETS,
-    "CRYSTALS":        OPTION_PLANETS,
-    "SHUTTLE":         OPTION_PLANETS,
-    "PLANETS":         OPTION_PLANETS,
-    "REPORT":          0,
-    "COMPUTER":        0,
-    "COMMANDS":        0,
-    "EMEXIT":          0,
-    "PROBE":           OPTION_PROBE,
-    "SAVE":            0,
-    "FREEZE":          0,      # Synonym for SAVE
-    "ABANDON":         0,
-    "DESTRUCT":        0,
-    "DEATHRAY":        0,
-    "DEBUG":           0,
-    "MAYDAY":          0,
-    "SOS":             0,      # Synonym for MAYDAY
-    "CALL":            0,      # Synonym for MAYDAY
-    "QUIT":            0,
-    "HELP":            0,
-}
+commands = [
+    ("SRSCAN",         OPTION_TTY),
+    ("STATUS",         OPTION_TTY),
+    ("REQUEST",        OPTION_TTY),
+    ("LRSCAN",         OPTION_TTY),
+    ("PHASERS",        0),
+    ("TORPEDO",        0),
+    ("PHOTONS",        0),
+    ("MOVE",           0),
+    ("SHIELDS",        0),
+    ("DOCK",           0),
+    ("DAMAGES",        0),
+    ("CHART",          0),
+    ("IMPULSE",        0),
+    ("REST",           0),
+    ("WARP",           0),
+    ("SCORE",          0),
+    ("SENSORS",        OPTION_PLANETS),
+    ("ORBIT",          OPTION_PLANETS),
+    ("TRANSPORT",      OPTION_PLANETS),
+    ("MINE",           OPTION_PLANETS),
+    ("CRYSTALS",       OPTION_PLANETS),
+    ("SHUTTLE",        OPTION_PLANETS),
+    ("PLANETS",        OPTION_PLANETS),
+    ("REPORT",         0),
+    ("COMPUTER",       0),
+    ("COMMANDS",       0),
+    ("EMEXIT",         0),
+    ("PROBE",          OPTION_PROBE),
+    ("SAVE",           0),
+    ("FREEZE",         0),     # Synonym for SAVE
+    ("ABANDON",        0),
+    ("DESTRUCT",       0),
+    ("DEATHRAY",       0),
+    ("DEBUG",          0),
+    ("MAYDAY",         0),
+    ("SOS",            0),     # Synonym for MAYDAY
+    ("CALL",           0),     # Synonym for MAYDAY
+    ("QUIT",           0),
+    ("HELP",           0),
+    ("",               0),
+]
 
 def listCommands():
     "Generate a list of legal commands."
     prout(_("LEGAL COMMANDS ARE:"))
     emitted = 0
 
 def listCommands():
     "Generate a list of legal commands."
     prout(_("LEGAL COMMANDS ARE:"))
     emitted = 0
-    for key in commands:
-       if not commands[key] or (commands[key] & game.options):
+    for (key, opt) in commands:
+       if not opt or (opt & game.options):
             proutn("%-12s " % key)
             emitted += 1
             if emitted % 5 == 4:
             proutn("%-12s " % key)
             emitted += 1
             if emitted % 5 == 4:
@@ -5819,7 +5932,8 @@ def helpme():
        setwnd(message_window)
        if key == "IHEOL":
            return
        setwnd(message_window)
        if key == "IHEOL":
            return
-        if scanner.token.upper() in commands or scanner.token == "ABBREV":
+       cmds = map(lambda x: x[0], commands)
+       if scanner.token.upper() in cmds or scanner.token.upper() == "ABBREV":
            break
        skip(1)
        listCommands()
            break
        skip(1)
        listCommands()
@@ -5863,8 +5977,6 @@ def helpme():
 
 def makemoves():
     "Command-interpretation loop."
 
 def makemoves():
     "Command-interpretation loop."
-    clrscr()
-    setwnd(message_window)
     while True:        # command loop 
        drawmaps(1)
         while True:    # get a command 
     while True:        # command loop 
        drawmaps(1)
         while True:    # get a command 
@@ -5884,16 +5996,19 @@ def makemoves():
            clrscr()
            setwnd(message_window)
            clrscr()
            clrscr()
            setwnd(message_window)
            clrscr()
-            candidates = filter(lambda x: x.startswith(scanner.token.upper()),
-                                commands)
-            if len(candidates) == 1:
-                cmd = candidates[0]
-                break
-            elif candidates and not (game.options & OPTION_PLAIN):
-                prout("Commands with prefix '%s': %s" % (scanner.token, " ".join(candidates)))
-            else:
+           abandon_passed = False
+           for (cmd, opt) in commands:
+               # commands after ABANDON cannot be abbreviated
+               if cmd == "ABANDON":
+                   abandon_passed = True
+               if cmd == scanner.token.upper() or (not abandon_passed \
+                       and cmd.startswith(scanner.token.upper())):
+                   break
+           if cmd == "":
                 listCommands()
                 continue
                 listCommands()
                 continue
+            else:
+               break
        if cmd == "SRSCAN":             # srscan
            srscan()
        elif cmd == "STATUS":           # status
        if cmd == "SRSCAN":             # srscan
            srscan()
        elif cmd == "STATUS":           # status
@@ -5911,7 +6026,7 @@ def makemoves():
            if game.ididit:
                hitme = True
        elif cmd == "MOVE":             # move under warp
            if game.ididit:
                hitme = True
        elif cmd == "MOVE":             # move under warp
-           warp(course=None, involuntary=False)
+           warp(wcourse=None, involuntary=False)
        elif cmd == "SHIELDS":          # shields
            doshield(shraise=False)
            if game.ididit:
        elif cmd == "SHIELDS":          # shields
            doshield(shraise=False)
            if game.ididit:
@@ -5966,7 +6081,7 @@ def makemoves():
        elif cmd == "EMEXIT":           # Emergency exit
            clrscr()                    # Hide screen
            freeze(True)                # forced save
        elif cmd == "EMEXIT":           # Emergency exit
            clrscr()                    # Hide screen
            freeze(True)                # forced save
-           raise SysExit,1                     # And quick exit
+           raise SystemExit,1          # And quick exit
        elif cmd == "PROBE":
            probe()                     # Launch probe
            if game.ididit:
        elif cmd == "PROBE":
            probe()                     # Launch probe
            if game.ididit:
@@ -6015,7 +6130,7 @@ def makemoves():
            break
        if game.alldone:
            break
            break
        if game.alldone:
            break
-    if idebug:
+    if game.idebug:
        prout("=== Ending")
 
 def cramen(type):
        prout("=== Ending")
 
 def cramen(type):
@@ -6061,7 +6176,7 @@ def expran(avrage):
 
 def randplace(size):
     "Choose a random location."
 
 def randplace(size):
     "Choose a random location."
-    w = coord()
+    w = Coord()
     w.i = randrange(size) 
     w.j = randrange(size)
     return w
     w.i = randrange(size) 
     w.j = randrange(size)
     return w
@@ -6122,7 +6237,7 @@ class sstscanner:
         # Round token value to nearest integer
         return int(round(scanner.real))
     def getcoord(self):
         # Round token value to nearest integer
         return int(round(scanner.real))
     def getcoord(self):
-        s = coord()
+        s = Coord()
         scanner.next()
        if scanner.type != "IHREAL":
            huh()
         scanner.next()
        if scanner.type != "IHREAL":
            huh()
@@ -6134,7 +6249,7 @@ class sstscanner:
            return None
        s.j = scanner.int()-1
         return s
            return None
        s.j = scanner.int()-1
         return s
-    def __repr__(str):
+    def __repr__(self):
         return "<sstcanner: token=%s, type=%s, queue=%s>" % (scanner.token, scanner.type, scanner.inqueue)
 
 def ja():
         return "<sstcanner: token=%s, type=%s, queue=%s>" % (scanner.token, scanner.type, scanner.inqueue)
 
 def ja():
@@ -6158,26 +6273,26 @@ def huh():
 def debugme():
     "Access to the internals for debugging."
     proutn("Reset levels? ")
 def debugme():
     "Access to the internals for debugging."
     proutn("Reset levels? ")
-    if ja() == True:
+    if ja():
        if game.energy < game.inenrg:
            game.energy = game.inenrg
        game.shield = game.inshld
        game.torps = game.intorps
        game.lsupres = game.inlsr
     proutn("Reset damage? ")
        if game.energy < game.inenrg:
            game.energy = game.inenrg
        game.shield = game.inshld
        game.torps = game.intorps
        game.lsupres = game.inlsr
     proutn("Reset damage? ")
-    if ja() == True:
+    if ja():
        for i in range(NDEVICES): 
            if game.damage[i] > 0.0: 
                game.damage[i] = 0.0
     proutn("Toggle debug flag? ")
        for i in range(NDEVICES): 
            if game.damage[i] > 0.0: 
                game.damage[i] = 0.0
     proutn("Toggle debug flag? ")
-    if ja() == True:
-       idebug = not idebug
-       if idebug:
+    if ja():
+       game.idebug = not game.idebug
+       if game.idebug:
            prout("Debug output ON")        
        else:
            prout("Debug output OFF")
     proutn("Cause selective damage? ")
            prout("Debug output ON")        
        else:
            prout("Debug output OFF")
     proutn("Cause selective damage? ")
-    if ja() == True:
+    if ja():
        for i in range(NDEVICES):
            proutn("Kill %s?" % device[i])
            scanner.chew()
        for i in range(NDEVICES):
            proutn("Kill %s?" % device[i])
            scanner.chew()
@@ -6185,9 +6300,9 @@ def debugme():
             if key == "IHALPHA" and scanner.sees("y"):
                game.damage[i] = 10.0
     proutn("Examine/change events? ")
             if key == "IHALPHA" and scanner.sees("y"):
                game.damage[i] = 10.0
     proutn("Examine/change events? ")
-    if ja() == True:
-       ev = event()
-       w = coord()
+    if ja():
+       ev = Event()
+       w = Coord()
         legends = {
             FSNOVA:  "Supernova       ",
             FTBEAM:  "T Beam          ",
         legends = {
             FSNOVA:  "Supernova       ",
             FTBEAM:  "T Beam          ",
@@ -6238,19 +6353,17 @@ def debugme():
                        ev.quadrant = w
        scanner.chew()
     proutn("Induce supernova here? ")
                        ev.quadrant = w
        scanner.chew()
     proutn("Induce supernova here? ")
-    if ja() == True:
+    if ja():
        game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova = True
        atover(True)
 
 if __name__ == '__main__':
     import getopt, socket
     try:
        game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova = True
        atover(True)
 
 if __name__ == '__main__':
     import getopt, socket
     try:
-        global line, thing, game, idebug
+        global line, thing, game
         game = None
         game = None
-        thing = coord()
-        thing.angry = False
-        game = gamestate()
-        idebug = 0
+        thing = Thingy()
+        game = Gamestate()
         game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY)
         if os.getenv("TERM"):
             game.options |= OPTION_CURSES
         game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY)
         if os.getenv("TERM"):
             game.options |= OPTION_CURSES
@@ -6258,6 +6371,7 @@ if __name__ == '__main__':
             game.options |= OPTION_TTY
         seed = int(time.time())
         (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:txV")
             game.options |= OPTION_TTY
         seed = int(time.time())
         (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:txV")
+        replay = False
         for (switch, val) in options:
             if switch == '-r':
                 try:
         for (switch, val) in options:
             if switch == '-r':
                 try:
@@ -6267,11 +6381,12 @@ if __name__ == '__main__':
                     raise SystemExit, 1
                 try:
                     line = replayfp.readline().strip()
                     raise SystemExit, 1
                 try:
                     line = replayfp.readline().strip()
-                    (leader, key, seed) = line.split()
+                    (leader, __, seed) = line.split()
                     seed = eval(seed)
                     sys.stderr.write("sst2k: seed set to %s\n" % seed)
                     line = replayfp.readline().strip()
                     arguments += line.split()[2:]
                     seed = eval(seed)
                     sys.stderr.write("sst2k: seed set to %s\n" % seed)
                     line = replayfp.readline().strip()
                     arguments += line.split()[2:]
+                    replay = True
                 except ValueError:
                     sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
                     raise SystemExit(1)
                 except ValueError:
                     sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
                     raise SystemExit(1)
@@ -6283,7 +6398,7 @@ if __name__ == '__main__':
                 game.options |= OPTION_TTY
                 game.options &=~ OPTION_CURSES
             elif switch == '-x':
                 game.options |= OPTION_TTY
                 game.options &=~ OPTION_CURSES
             elif switch == '-x':
-                idebug = True
+                game.idebug = True
             elif switch == '-V':
                 print "SST2K", version
                 raise SystemExit, 0 
             elif switch == '-V':
                 print "SST2K", version
                 raise SystemExit, 0 
@@ -6303,6 +6418,7 @@ if __name__ == '__main__':
         if logfp:
             logfp.write("# seed %s\n" % seed)
             logfp.write("# options %s\n" % " ".join(arguments))
         if logfp:
             logfp.write("# seed %s\n" % seed)
             logfp.write("# options %s\n" % " ".join(arguments))
+            logfp.write("# SST2K version %s\n" % version)
             logfp.write("# recorded by %s@%s on %s\n" % \
                     (getpass.getuser(),socket.gethostname(),time.ctime()))
         random.seed(seed)
             logfp.write("# recorded by %s@%s on %s\n" % \
                     (getpass.getuser(),socket.gethostname(),time.ctime()))
         random.seed(seed)
@@ -6320,12 +6436,14 @@ if __name__ == '__main__':
                     game.alldone = False
                 else:
                     makemoves()
                     game.alldone = False
                 else:
                     makemoves()
+                if replay:
+                    break
                 skip(1)
                 stars()
                 skip(1)
                 if game.tourn and game.alldone:
                     proutn(_("Do you want your score recorded?"))
                 skip(1)
                 stars()
                 skip(1)
                 if game.tourn and game.alldone:
                     proutn(_("Do you want your score recorded?"))
-                    if ja() == True:
+                    if ja():
                         scanner.chew()
                         scanner.push("\n")
                         freeze(False)
                         scanner.chew()
                         scanner.push("\n")
                         freeze(False)
@@ -6342,3 +6460,5 @@ if __name__ == '__main__':
         if logfp:
             logfp.close()
         print ""
         if logfp:
             logfp.close()
         print ""
+
+# End.