OK, warp flight between quadrants works now.
[super-star-trek.git] / src / sst.py
index 7a54d8b89068674854335678c1e771234843e2ea..aa22fe10418a10d26f86d952bd3a65b574e164df 100644 (file)
+#!/usr/bin/env python
 """
 sst.py =-- Super Star Trek in Python
 
 This code is a Python translation of a C translation of a FORTRAN original.
-The FORTRANness still shows in many ways, notably the use of 1-origin index
-an a lot of parallel arrays where a more modern language would use structures
-or objects.
+The FORTRANness still shows in many ways, notably the use of a lot of
+parallel arrays where a more modern language would use structures
+or objects.  (However, 1-origin array indexing was fixed.)
+
+Dave Matuszek says:
+
+SRSCAN, MOVE, PHASERS, CALL, STATUS, IMPULSE, PHOTONS, ABANDON,
+LRSCAN, WARP, SHIELDS, DESTRUCT, CHART, REST, DOCK, QUIT, and DAMAGE
+were in the original non-"super" version of UT FORTRAN Star Trek.
+
+Tholians were not in the original. Dave is dubious about their merits.
+(They are now controlled by OPTION_THOLIAN and turned off if the game
+type is "plain".)
+
+Planets and dilithium crystals were not in the original.  Dave is OK
+with this idea. (It's now controlled by OPTION_PLANETS and turned 
+off if the game type is "plain".)
+
+Dave says the bit about the Galileo getting turned into a
+McDonald's is "consistant with our original vision".  (This has been
+left permanently enabled, as it can only happen if OPTION_PLANETS
+is on.)
+
+Dave also says the Space Thingy should not be preserved across saved
+games, so you can't prove to others that you've seen it.  He says it
+shouldn't fire back, either.  It should do nothing except scream and
+disappear when hit by photon torpedos.  It's OK that it may move
+when attacked, but it didn't in the original.  (Whether the Thingy
+can fire back is now controlled by OPTION_THINGY and turned off if the
+game type is "plain" or "almy".  The no-save behavior has been restored.)
+
+The Faerie Queen, black holes, and time warping were in the original.
+
+Here are Tom Almy's changes:
+
+In early 1997, I got the bright idea to look for references to
+"Super Star Trek" on the World Wide Web. There weren't many hits,
+but there was one that came up with 1979 Fortran sources! This
+version had a few additional features that mine didn't have,
+however mine had some feature it didn't have. So I merged its
+features that I liked. I also took a peek at the DECUS version (a
+port, less sources, to the PDP-10), and some other variations.
+
+1, Compared to the original UT version, I've changed the "help" command to
+"call" and the "terminate" command to "quit" to better match
+user expectations. The DECUS version apparently made those changes
+as well as changing "freeze" to "save". However I like "freeze".
+(Both "freeze" and "save" work in SST2K.)
+
+2. The experimental deathray originally had only a 5% chance of
+success, but could be used repeatedly. I guess after a couple
+years of use, it was less "experimental" because the 1979
+version had a 70% success rate. However it was prone to breaking
+after use. I upgraded the deathray, but kept the original set of
+failure modes (great humor!).  (Now controlled by OPTION_DEATHRAY
+and turned off if game type is "plain".)
+
+3. The 1979 version also mentions srscan and lrscan working when
+docked (using the starbase's scanners), so I made some changes here
+to do this (and indicating that fact to the player), and then realized
+the base would have a subspace radio as well -- doing a Chart when docked
+updates the star chart, and all radio reports will be heard. The Dock
+command will also give a report if a base is under attack.
+
+4. Tholian Web from the 1979 version.  (Now controlled by
+OPTION_THOLIAN and turned off if game type is "plain".)
+
+5. Enemies can ram the Enterprise. (Now controlled by OPTION_RAMMING
+and turned off if game type is "plain".)
+
+6. Regular Klingons and Romulans can move in Expert and Emeritus games. 
+This code could use improvement. (Now controlled by OPTION_MVBADDY
+and turned off if game type is "plain".)
+
+7. The deep-space probe feature from the DECUS version.  (Now controlled
+by OPTION_PROBE and turned off if game type is "plain").
+
+8. 'emexit' command from the 1979 version.
+
+9. Bugfix: Klingon commander movements are no longer reported if long-range 
+sensors are damaged.
+
+10. Bugfix: Better base positioning at startup (more spread out).
+That made sense to add because most people abort games with 
+bad base placement.
+
+In June 2002, I fixed two known bugs and a documentation typo.
+In June 2004 I fixed a number of bugs involving: 1) parsing invalid
+numbers, 2) manual phasers when SR scan is damaged and commander is
+present, 3) time warping into the future, 4) hang when moving
+klingons in crowded quadrants.  (These fixes are in SST2K.)
+
+Here are Stas Sergeev's changes:
+
+1. The Space Thingy can be shoved, if you ram it, and can fire back if 
+fired upon. (Now controlled by OPTION_THINGY and turned off if game 
+type is "plain" or "almy".)
+
+2. When you are docked, base covers you with an almost invincible shield. 
+(A commander can still ram you, or a Romulan can destroy the base,
+or a SCom can even succeed with direct attack IIRC, but this rarely 
+happens.)  (Now controlled by OPTION_BASE and turned off if game 
+type is "plain" or "almy".)
+
+3. Ramming a black hole is no longer instant death.  There is a
+chance you might get timewarped instead. (Now controlled by 
+OPTION_BLKHOLE and turned off if game type is "plain" or "almy".)
+
+4. The Tholian can be hit with phasers.
+
+5. SCom can't escape from you if no more enemies remain 
+(without this, chasing SCom can take an eternity).
+
+6. Probe target you enter is now the destination quadrant. Before I don't 
+remember what it was, but it was something I had difficulty using.
+
+7. Secret password is now autogenerated.
+
+8. "Plaque" is adjusted for A4 paper :-)
+
+9. Phasers now tells you how much energy needed, but only if the computer 
+is alive.
+
+10. Planets are auto-scanned when you enter the quadrant.
+
+11. Mining or using crystals in presense of enemy now yields an attack.
+There are other minor adjustments to what yields an attack
+and what does not.
+
+12. "freeze" command reverts to "save", most people will understand this
+better anyway. (SST2K recognizes both.)
+
+13. Screen-oriented interface, with sensor scans always up.  (SST2K
+supports both screen-oriented and TTY modes.)
+
+Eric Raymond's changes:
+
+Mainly, I translated this C code out of FORTRAN into C -- created #defines
+for a lot of magic numbers and refactored the heck out of it.
+
+1. "sos" and "call" becomes "mayday", "freeze" and "save" are both good.
+
+2. Status report now indicates when dilithium crystals are on board.
+
+3. Per Dave Matuszek's remarks, Thingy state is never saved across games.
+
+4. Added game option selection so you can play a close (but not bug-for-
+bug identical) approximation of older versions.
+
+5. Half the quadrants now have inhabited planets, from which one 
+cannot mine dilithium (there will still be the same additional number
+of dilithium-bearing planets).  Torpedoing an inhabited world is *bad*.
+There is BSD-Trek-like logic for Klingons to attack and enslave 
+inhabited worlds, producing more ships (only is skill is 'good' or 
+better). (Controlled by OPTION_WORLDS and turned off if game 
+type is "plain" or "almy".)
+
+6. User input is now logged so we can do regression testing.
+
+7. More BSD-Trek features: You can now lose if your entire crew
+dies in battle.  When abandoning ship in a game with inhabited
+worlds enabled, they must have one in the quadrant to beam down
+to; otherwise they die in space and this counts heavily against
+your score.  Docking at a starbase replenishes your crew.
+
+8. Still more BSD-Trek: we now have a weighted damage table.
+Also, the nav subsystem (enabling automatic course
+setting) can be damaged separately from the main computer (which
+handles weapons targeting, ETA calculation, and self-destruct).
 """
-import os, sys, math, curses, time, atexit, readline
+import os,sys,math,curses,time,atexit,readline,cPickle,random,getopt,copy
 
-SSTDOC = "/usr/share/doc/sst/sst.doc"
+SSTDOC         = "/usr/share/doc/sst/sst.doc"
+DOC_NAME       = "sst.doc"
 
 # Stub to be replaced
 def _(str): return str
@@ -19,6 +187,7 @@ NINHAB       = (GALSIZE * GALSIZE / 2)
 MAXUNINHAB     = 10
 PLNETMAX       = (NINHAB + MAXUNINHAB)
 QUADSIZE       = 10
+BASEMIN                = 2
 BASEMAX        = (GALSIZE * GALSIZE / 12)
 MAXKLGAME      = 127
 MAXKLQUAD      = 9
@@ -26,8 +195,8 @@ FULLCREW     = 428   # BSD Trek was 387, that's wrong
 FOREVER        = 1e30
 
 # These functions hide the difference between 0-origin and 1-origin addressing.
-def VALID_QUADRANT(x, y):      return ((x)>=1 and (x)<=GALSIZE and (y)>=1 and (y)<=GALSIZE)
-def VALID_SECTOR(x, y):        return ((x)>=1 and (x)<=QUADSIZE and (y)>=1 and (y)<=QUADSIZE)
+def VALID_QUADRANT(x, y):      return ((x)>=0 and (x)<GALSIZE and (y)>=0 and (y)<GALSIZE)
+def VALID_SECTOR(x, y):        return ((x)>=0 and (x)<QUADSIZE and (y)>=0 and (y)<QUADSIZE)
 
 def square(i):         return ((i)*(i))
 def distance(c1, c2):  return math.sqrt(square(c1.x - c2.x) + square(c1.y - c2.y))
@@ -54,8 +223,12 @@ IHMATER0 = '-',
 IHMATER1 = 'o',
 IHMATER2 = '0'
 
+IHEOL = '\n'
+IHREAL = 0.0
+IHALPHA = " "
+
 class coord:
-    def __init(self, x=None, y=None):
+    def __init__(self, x=None, y=None):
         self.x = x
         self.y = y
     def invalidate(self):
@@ -63,7 +236,7 @@ class coord:
     def is_valid(self):
         return self.x != None and self.y != None
     def __eq__(self, other):
-        return self.x == other.y and self.x == other.y
+        return other != None and self.x == other.y and self.x == other.y
     def __add__(self, other):
         return coord(self.x+self.x, self.y+self.y)
     def __sub__(self, other):
@@ -75,21 +248,22 @@ class coord:
     def __hash__(self):
         return hash((x, y))
     def __str__(self):
-        return "%d - %d" % (self.x, self.y)
+        return "%s - %s" % (self.x+1, self.y+1)
+    __repr__ = __str__
 
 class planet:
-    def __init(self):
+    def __init__(self):
         self.name = None       # string-valued if inhabited
         self.w = coord()       # quadrant located
         self.pclass = None     # could be ""M", "N", "O", or "destroyed"
-        self.crystals = None   # could be "mined", "present", "absent"
-        self.known = None      # could be "unknown", "known", "shuttle_down"
+        self.crystals = "absent"# could be "mined", "present", "absent"
+        self.known = "unknown" # could be "unknown", "known", "shuttle_down"
+        self.inhabited = False # is it inhabites?
     def __str__(self):
         return self.name
 
-NOPLANET = None
 class quadrant:
-    def __init(self):
+    def __init__(self):
         self.stars = None
         self.planet = None
        self.starbase = None
@@ -100,47 +274,48 @@ class quadrant:
         self.status = None     # Could be "secure", "distressed", "enslaved"
 
 class page:
-    def __init(self):
+    def __init__(self):
        self.stars = None
        self.starbase = None
        self.klingons = None
 
+def fill2d(size, fillfun):
+    "Fill an empty list in 2D."
+    lst = []
+    for i in range(size):
+        lst.append([]) 
+        for j in range(size):
+            lst[i].append(fillfun(i, j))
+    return lst
+
 class snapshot:
-    def __init(self):
+    def __init__(self):
         self.snap = False      # snapshot taken
-        self.crew = None       # crew complement
-       self.remkl = None       # remaining klingons
-       self.remcom = None      # remaining commanders
-       self.nscrem = None      # remaining super commanders
-       self.rembase = None     # remaining bases
-       self.starkl = None      # destroyed stars
-       self.basekl = None      # destroyed bases
-       self.nromrem = None     # Romulans remaining
-       self.nplankl = None     # destroyed uninhabited planets
-       self.nworldkl = None    # destroyed inhabited planets
+        self.crew = 0          # crew complement
+       self.remkl = 0          # remaining klingons
+       self.remcom = 0         # remaining commanders
+       self.nscrem = 0         # remaining super commanders
+       self.rembase = 0        # remaining bases
+       self.starkl = 0         # destroyed stars
+       self.basekl = 0         # destroyed bases
+       self.nromrem = 0        # Romulans remaining
+       self.nplankl = 0        # destroyed uninhabited planets
+       self.nworldkl = 0       # destroyed inhabited planets
         self.planets = []      # Planet information
-        for i in range(PLNETMAX):
-            self.planets.append(planet())
-        self.date = None       # stardate
-       self.remres = None      # remaining resources
-       self.remtime = None     # remaining time
+        self.date = 0.0        # stardate
+       self.remres = 0         # remaining resources
+       self.remtime = 0        # remaining time
         self.baseq = []        # Base quadrant coordinates
-        for i in range(BASEMAX+1):
+        for i in range(BASEMAX):
             self.baseq.append(coord())
         self.kcmdr = []        # Commander quadrant coordinates
-        for i in range(QUADSIZE+1):
+        for i in range(QUADSIZE):
             self.kcmdr.append(coord())
        self.kscmdr = coord()   # Supercommander quadrant coordinates
-        self.galaxy = []       # The Galaxy (subscript 0 not used)
-        for i in range(GALSIZE+1):
-            self.chart.append([])
-            for j in range(GALSIZE+1):
-                self.galaxy[i].append(quadrant())
-       self.chart = []         # the starchart (subscript 0 not used)
-        for i in range(GALSIZE+1):
-            self.chart.append([])
-            for j in range(GALSIZE+1):
-                self.chart[i].append(page())
+        # the galaxy (subscript 0 not used)
+        self.galaxy = fill2d(GALSIZE, lambda i, j: quadrant())
+        # the starchart (subscript 0 not used)
+       self.chart = fill2d(GALSIZE, lambda i, j: page())
 
 class event:
     def __init__(self):
@@ -219,18 +394,18 @@ def findevent(evtype):    return game.future[evtype]
 class gamestate:
     def __init__(self):
         self.options = None    # Game options
-        self.state = None      # A snapshot structure
-        self.snapsht = None    # Last snapshot taken for time-travel purposes
-        self.quad = [[IHDOT * (QUADSIZE+1)] * (QUADSIZE+1)]    # contents of our quadrant
-        self.kpower = [[0 * (QUADSIZE+1)] * (QUADSIZE+1)]      # enemy energy levels
-        self.kdist = [[0 * (QUADSIZE+1)] * (QUADSIZE+1)]       # enemy distances
-        self.kavgd = [[0 * (QUADSIZE+1)] * (QUADSIZE+1)]       # average distances
-        self.damage = [0] * NDEVICES   # damage encountered
-        self.future = [0.0] * NEVENTS  # future events
+        self.state = snapshot()        # A snapshot structure
+        self.snapsht = snapshot()      # Last snapshot taken for time-travel purposes
+        self.quad = fill2d(QUADSIZE, lambda i, j: IHDOT)       # contents of our quadrant
+        self.kpower = fill2d(QUADSIZE, lambda i, j: 0.0)       # enemy energy levels
+        self.kdist = fill2d(QUADSIZE, lambda i, j: 0.0)                # enemy distances
+        self.kavgd = fill2d(QUADSIZE, lambda i, j: 0.0)        # average distances
+        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.ks = [[None * (QUADSIZE+1)] * (QUADSIZE+1)]       # enemy sector locations
+        self.ks = fill2d(QUADSIZE, lambda i, j: coord())       # enemy sector locations
         self.quadrant = None   # where we are in the large
         self.sector = None     # where we are in the small
         self.tholian = None    # coordinates of Tholian
@@ -278,7 +453,7 @@ class gamestate:
         self.casual = 0                # causalties
         self.nhelp = 0         # calls for help
         self.nkinks = 0                # count of energy-barrier crossings
-        self.iplnet = 0                # planet # in quadrant
+        self.iplnet = None     # planet # in quadrant
         self.inplan = 0                # initial planets
         self.nenhere = 0       # number of enemies in quadrant
         self.irhere = 0                # Romulans in quadrant
@@ -397,7 +572,7 @@ def tryexit(look, ienm, loccom, irun):
     if not irun:
        # avoid intruding on another commander's territory 
        if ienm == IHC:
-           for n in range(1, game.state.remcom+1):
+           for n in range(game.state.remcom):
                if game.state.kcmdr[n] == iq:
                    return False
            # refuse to leave if currently attacking starbase 
@@ -434,7 +609,7 @@ def tryexit(look, ienm, loccom, irun):
        unschedule(FSCDBAS)
        game.state.kscmdr=iq
     else:
-       for n in range(1, game.state.remcom+1):
+       for n in range(game.state.remcom):
            if game.state.kcmdr[n] == game.quadrant:
                game.state.kcmdr[n]=iq
                break
@@ -518,12 +693,12 @@ def movebaddy(com, loccom, ienm):
            forces += 1000.0
        motion = 0
         if forces <= 1000.0 and game.condition != "docked": # Typical situation 
-           motion = ((forces+200.0*Rand())/150.0) - 5.0
+           motion = ((forces+200.0*random.random())/150.0) - 5.0
        else:
             if forces > 1000.0: # Very strong -- move in for kill 
-               motion = (1.0-square(Rand()))*dist1 + 1.0
+               motion = (1.0-square(random.random()))*dist1 + 1.0
            if game.condition=="docked" and (game.options & OPTION_BASE): # protected by base -- back off ! 
-               motion -= game.skill*(2.0-square(Rand()))
+               motion -= game.skill*(2.0-square(random.random()))
        if idebug:
            proutn("=== MOTION = %d, FORCES = %1.2f, " % (motion, forces))
        # don't move if no motion 
@@ -585,14 +760,14 @@ def movebaddy(com, loccom, ienm):
        attempts = 0; # Settle mysterious hang problem 
        while attempts < 20 and not success:
             attempts += 1
-           if look.x < 1 or look.x > QUADSIZE:
+           if look.x < 0 or look.x >= QUADSIZE:
                if motion < 0 and tryexit(look, ienm, loccom, irun):
                    return
                if krawlx == mx or my == 0:
                    break
                look.x = next.x + krawlx
                krawlx = -krawlx
-           elif look.y < 1 or look.y > QUADSIZE:
+           elif look.y < 0 or look.y >= QUADSIZE:
                if motion < 0 and tryexit(look, ienm, loccom, irun):
                    return
                if krawly == my or mx == 0:
@@ -648,13 +823,13 @@ def moveklings():
     # Figure out which Klingon is the commander (or Supercommander)
     # and do move
     if game.comhere:
-       for i in range(1, game.nenhere+1):
+       for i in range(game.nenhere):
            w = game.ks[i]
            if game.quad[w.x][w.y] == IHC:
                movebaddy(w, i, IHC)
                break
     if game.ishere:
-       for i in range(1, game.nenhere+1):
+       for i in range(game.nenhere):
            w = game.ks[i]
            if game.quad[w.x][w.y] == IHS:
                movebaddy(w, i, IHS)
@@ -663,7 +838,7 @@ def moveklings():
     # Move these last so they can base their actions on what the
     # commander(s) do.
     if game.skill >= SKILL_EXPERT and (game.options & OPTION_MVBADDY):
-       for i in range(1, game.nenhere+1):
+       for i in range(game.nenhere):
            w = game.ks[i]
            if game.quad[w.x][w.y] == IHK or game.quad[w.x][w.y] == IHR:
                movebaddy(w, i, game.quad[w.x][w.y])
@@ -677,7 +852,7 @@ def movescom(iq, avoid):
        return 1
     if avoid:
        # Avoid quadrants with bases if we want to avoid Enterprise 
-       for i in range(1, game.state.rembase+1):
+       for i in range(game.state.rembase):
            if game.state.baseq[i] == iq:
                return True
     if game.justin and not game.iscate:
@@ -693,7 +868,7 @@ def movescom(iq, avoid):
        game.ishere = False
        game.ientesc = False
        unschedule(FSCDBAS)
-       for i in range(1, game.nenhere+1):
+       for i in range(game.nenhere):
            if game.quad[game.ks[i].x][game.ks[i].y] == IHS:
                break
        game.quad[game.ks[i].x][game.ks[i].y] = IHDOT
@@ -712,7 +887,7 @@ def movescom(iq, avoid):
            game.state.planets[i].crystals == "present":
            # destroy the planet 
            game.state.planets[i].pclass = "destroyed"
-           game.state.galaxy[game.state.kscmdr.x][game.state.kscmdr.y].planet = NOPLANET
+           game.state.galaxy[game.state.kscmdr.x][game.state.kscmdr.y].planet = None
            if communicating():
                announce()
                prout(_("Lt. Uhura-  \"Captain, Starfleet Intelligence reports"))
@@ -744,14 +919,14 @@ def supercommander():
            unschedule(FSCMOVE)
            return
        sc = game.state.kscmdr
-       for i in range(1, game.state.rembase+1):
+       for i in range(game.state.rembase):
            basetbl.append((i, distance(game.state.baseq[i], sc)))
        if game.state.rembase > 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 in range(1, game.state.rembase+1):
+       for i2 in range(game.state.rembase):
            i = basetbl[i2][0]; # bug in original had it not finding nearest
            ibq = game.state.baseq[i]
            if ibq == game.quadrant or ibq == game.battle or \
@@ -760,7 +935,7 @@ def supercommander():
                continue
            # if there is a commander, and no other base is appropriate,
            #   we will take the one with the commander
-           for j in range(1, game.state.remcom+1):
+           for j in range(game.state.remcom):
                if ibq == game.state.kcmdr[j] and ifindit!= 2:
                    ifindit = 2
                    iwhichb = i
@@ -805,7 +980,7 @@ def supercommander():
     if game.state.rembase == 0:
        unschedule(FSCMOVE)
     else:
-       for i in range(1, game.state.rembase+1):
+       for i in range(game.state.rembase):
            ibq = game.state.baseq[i]
            if ibq == game.state.kscmdr and game.state.kscmdr == game.battle:
                # attack the base 
@@ -813,7 +988,7 @@ def supercommander():
                    return; # no, don't attack base! 
                game.iseenit = False
                game.isatb = 1
-               schedule(FSCDBAS, 1.0 +2.0*Rand())
+               schedule(FSCDBAS, 1.0 +2.0*random.random())
                if is_scheduled(FCDBAS):
                    postpone(FSCDBAS, scheduled(FCDBAS)-game.state.date)
                if not communicating():
@@ -835,7 +1010,7 @@ def supercommander():
                return
     # Check for intelligence report 
     if not idebug and \
-       (Rand() > 0.2 or \
+       (random.random() > 0.2 or \
         (not communicating()) or \
         not game.state.galaxy[game.state.kscmdr.x][game.state.kscmdr.y].charted):
        return
@@ -849,14 +1024,14 @@ def movetholian():
     if not game.ithere or game.justin:
        return
 
-    if game.tholian.x == 1 and game.tholian.y == 1:
-       idx = 1; idy = QUADSIZE
-    elif game.tholian.x == 1 and game.tholian.y == QUADSIZE:
-       idx = QUADSIZE; idy = QUADSIZE
-    elif game.tholian.x == QUADSIZE and game.tholian.y == QUADSIZE:
-       idx = QUADSIZE; idy = 1
-    elif game.tholian.x == QUADSIZE and game.tholian.y == 1:
-       idx = 1; idy = 1
+    if game.tholian.x == 0 and game.tholian.y == 0:
+       idx = 0; idy = QUADSIZE-1
+    elif game.tholian.x == 0 and game.tholian.y == QUADSIZE-1:
+       idx = QUADSIZE-1; idy = QUADSIZE-1
+    elif game.tholian.x == QUADSIZE-1 and game.tholian.y == QUADSIZE-1:
+       idx = QUADSIZE-1; idy = 0
+    elif game.tholian.x == QUADSIZE-1 and game.tholian.y == 0:
+       idx = 0; idy = 0
     else:
        # something is wrong! 
        game.ithere = False
@@ -885,12 +1060,12 @@ def movetholian():
     game.ks[game.nenhere] = game.tholian
 
     # check to see if all holes plugged 
-    for i in range(1, QUADSIZE+1):
-       if game.quad[1][i]!=IHWEB and game.quad[1][i]!=IHT:
+    for i in range(QUADSIZE):
+       if game.quad[0][i]!=IHWEB and game.quad[0][i]!=IHT:
            return
        if game.quad[QUADSIZE][i]!=IHWEB and game.quad[QUADSIZE][i]!=IHT:
            return
-       if game.quad[i][1]!=IHWEB and game.quad[i][1]!=IHT:
+       if game.quad[i][0]!=IHWEB and game.quad[i][0]!=IHT:
            return
        if game.quad[i][QUADSIZE]!=IHWEB and game.quad[i][QUADSIZE]!=IHT:
            return
@@ -977,7 +1152,7 @@ def doshield(shraise):
            chew()
            proutn(_("Energy to transfer to shields- "))
        chew()
-       if aaitem==0:
+       if aaitem == 0:
            return
        if aaitem > game.energy:
            prout(_("Insufficient ship energy."))
@@ -1028,7 +1203,7 @@ def randdevice():
     # 
     # This is one place where OPTION_PLAIN does not restore the
     # original behavior, which was equiprobable damage across
-    # all devices.  If we wanted that, we'd return NDEVICES*Rand()
+    # all devices.  If we wanted that, we'd return NDEVICES*random.random()
     # and have done with it.  Also, in the original game, DNAVYS
     # and DCOMPTR were the same device. 
     # 
@@ -1056,7 +1231,7 @@ def randdevice():
        10,     # DDRAY: death ray                       1.0% 
        30,     # DDSP: deep-space probes                3.0% 
     )
-    idx = Rand() * 1000.0      # weights must sum to 1000 
+    idx = random.random() * 1000.0     # weights must sum to 1000 
     sum = 0
     for (i, w) in enumerate(weights):
        sum += w
@@ -1085,7 +1260,7 @@ def ram(ibumpd, ienm, w):
     proutn("***")
     crmshp()
     prout(_(" heavily damaged."))
-    icas = 10.0+20.0*Rand()
+    icas = 10 + random.randrange(20)
     prout(_("***Sickbay reports %d casualties"), icas)
     game.casual += icas
     game.state.crew -= icas
@@ -1094,12 +1269,12 @@ def ram(ibumpd, ienm, w):
     # which was silly.  Instead, pick up to half the devices at
     # random according to our weighting table,
     # 
-    ncrits = Rand() * (NDEVICES/2)
+    ncrits = random.randrange(NDEVICES/2)
     for m in range(ncrits):
        dev = randdevice()
        if game.damage[dev] < 0:
            continue
-       extradm = (10.0*hardness*Rand()+1.0)*game.damfac
+       extradm = (10.0*hardness*random.random()+1.0)*game.damfac
        # Damage for at least time of travel! 
        game.damage[dev] += game.optime + extradm
     game.shldup = False
@@ -1151,13 +1326,13 @@ def torpedo(course, r, incoming, i, n):
            proutn(_("Torpedo hits "))
            crmshp()
            prout(".")
-           hit = 700.0 + 100.0*Rand() - \
+           hit = 700.0 + 100.0*random.random() - \
                1000.0 * distance(w, incoming) * math.fabs(math.sin(bullseye-angle))
            newcnd(); # we're blown out of dock 
            # We may be displaced. 
            if game.landed or game.condition=="docked":
                return hit # Cheat if on a planet 
-           ang = angle + 2.5*(Rand()-0.5)
+           ang = angle + 2.5*(random.random()-0.5)
            temp = math.fabs(math.sin(ang))
            if math.fabs(math.cos(ang)) > temp:
                temp = math.fabs(math.cos(ang))
@@ -1177,18 +1352,18 @@ def torpedo(course, r, incoming, i, n):
            crmshp()
            shoved = True
        elif iquad in (IHC, IHS): # Hit a commander 
-           if Rand() <= 0.05:
+           if random.random() <= 0.05:
                crmena(True, iquad, sector, w)
                prout(_(" uses anti-photon device;"))
                prout(_("   torpedo neutralized."))
                return None
        elif iquad in (IHR, IHK): # Hit a regular enemy 
            # find the enemy 
-           for ll in range(1, game.nenhere+1):
+           for ll in range(game.nenhere):
                if w == game.ks[ll]:
                    break
            kp = math.fabs(game.kpower[ll])
-           h1 = 700.0 + 100.0*Rand() - \
+           h1 = 700.0 + 100.0*random.random() - \
                1000.0 * distance(w, incoming) * math.fabs(math.sin(bullseye-angle))
            h1 = math.fabs(h1)
            if kp < h1:
@@ -1202,7 +1377,7 @@ def torpedo(course, r, incoming, i, n):
                return None
            crmena(True, iquad, "sector", w)
            # If enemy damaged but not destroyed, try to displace 
-           ang = angle + 2.5*(Rand()-0.5)
+           ang = angle + 2.5*(random.random()-0.5)
            temp = math.fabs(math.sin(ang))
            if math.fabs(math.cos(ang)) > temp:
                temp = math.fabs(math.cos(ang))
@@ -1228,7 +1403,7 @@ def torpedo(course, r, incoming, i, n):
        elif iquad == IHB: # Hit a base 
            skip(1)
            prout(_("***STARBASE DESTROYED.."))
-           for ll in range(1, game.state.rembase+1):
+           for ll in range(game.state.rembase):
                if game.state.baseq[ll] == game.quadrant:
                    game.state.baseq[ll]=game.state.baseq[game.state.rembase]
                    break
@@ -1244,9 +1419,9 @@ def torpedo(course, r, incoming, i, n):
            crmena(True, iquad, sector, w)
            prout(_(" destroyed."))
            game.state.nplankl += 1
-           game.state.galaxy[game.quadrant.x][game.quadrant.y].planet = NOPLANET
-           game.state.planets[game.iplnet].pclass = destroyed
-           game.iplnet = 0
+           game.state.galaxy[game.quadrant.x][game.quadrant.y].planet = None
+           game.iplnet.pclass = "destroyed"
+           game.iplnet = None
            invalidate(game.plnet)
            game.quad[w.x][w.y] = IHDOT
            if game.landed:
@@ -1257,9 +1432,9 @@ def torpedo(course, r, incoming, i, n):
            crmena(True, iquad, sector, w)
            prout(_(" destroyed."))
            game.state.nworldkl += 1
-           game.state.galaxy[game.quadrant.x][game.quadrant.y].planet = NOPLANET
-           game.state.planets[game.iplnet].pclass = destroyed
-           game.iplnet = 0
+           game.state.galaxy[game.quadrant.x][game.quadrant.y].planet = None
+           game.iplnet.pclass = "destroyed"
+           game.iplnet = None
            invalidate(game.plnet)
            game.quad[w.x][w.y] = IHDOT
            if game.landed:
@@ -1269,14 +1444,14 @@ def torpedo(course, r, incoming, i, n):
            prout(_("Celebratory rallies are being held on the Klingon homeworld."))
            return None
        elif iquad == IHSTAR: # Hit a star 
-           if Rand() > 0.10:
+           if random.random() > 0.10:
                nova(w)
                return None
            crmena(True, IHSTAR, sector, w)
            prout(_(" unaffected by photon blast."))
            return None
        elif iquad == IHQUEST: # Hit a thingy 
-           if not (game.options & OPTION_THINGY) or Rand()>0.7:
+           if not (game.options & OPTION_THINGY) or random.random()>0.7:
                skip(1)
                prouts(_("AAAAIIIIEEEEEEEEAAAAAAAAUUUUUGGGGGHHHHHHHHHHHH!!!"))
                skip(1)
@@ -1291,7 +1466,8 @@ def torpedo(course, r, incoming, i, n):
                # 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.
-               # 
+               #
+                global iqengry
                iqengry = True
                shoved = True
            return None
@@ -1305,7 +1481,7 @@ def torpedo(course, r, incoming, i, n):
            prout(_("***Torpedo absorbed by Tholian web."))
            return None
        elif iquad == IHT:  # Hit a Tholian 
-           h1 = 700.0 + 100.0*Rand() - \
+           h1 = 700.0 + 100.0*random.random() - \
                1000.0 * distance(w, incoming) * math.fabs(math.sin(bullseye-angle))
            h1 = math.fabs(h1)
            if h1 >= 600:
@@ -1315,7 +1491,7 @@ def torpedo(course, r, incoming, i, n):
                return None
            skip(1)
            crmena(True, IHT, sector, w)
-           if Rand() > 0.05:
+           if random.random() > 0.05:
                prout(_(" survives photon blast."))
                return None
            prout(_(" disappears."))
@@ -1337,7 +1513,7 @@ def torpedo(course, r, incoming, i, n):
        game.quad[w.x][w.y]=IHDOT
        game.quad[jw.x][jw.y]=iquad
        prout(_(" displaced by blast to Sector %s ") % jw)
-       for ll in range(1, game.nenhere+1):
+       for ll in range(game.nenhere):
            game.kdist[ll] = game.kavgd[ll] = distance(game.sector,game.ks[ll])
        sortklings()
        return None
@@ -1349,10 +1525,9 @@ def fry(hit):
     # critical-hit resolution 
     ktr=1
     # a critical hit occured 
-    if hit < (275.0-25.0*game.skill)*(1.0+0.5*Rand()):
+    if hit < (275.0-25.0*game.skill)*(1.0+0.5*random.random()):
        return
-
-    ncrit = 1.0 + hit/(500.0+100.0*Rand())
+    ncrit = 1.0 + hit/(500.0+100.0*random.random())
     proutn(_("***CRITICAL HIT--"))
     # Select devices and cause damage
     cdam = []
@@ -1363,7 +1538,7 @@ def fry(hit):
             if not (game.damage[j]<0.0 or (j==DSHUTTL and game.iscraft != "onship")):
                 break
        cdam.append(j)
-       extradm = (hit*game.damfac)/(ncrit*(75.0+25.0*Rand()))
+       extradm = (hit*game.damfac)/(ncrit*(75.0+25.0*random.random()))
        game.damage[j] += extradm
        if loop1 > 0:
             for loop2 in range(loop1):
@@ -1388,47 +1563,37 @@ def attack(torps_ok):
     hitmax=0.0; hittot=0.0; chgfac=1.0
     jay = coord()
     where = "neither"
-
     # game could be over at this point, check 
     if game.alldone:
        return
-
     if idebug:
        prout("=== ATTACK!")
-
-    # Tholian gewts to move before attacking 
+    # Tholian gets to move before attacking 
     if game.ithere:
        movetholian()
-
     # if you have just entered the RNZ, you'll get a warning 
     if game.neutz: # The one chance not to be attacked 
        game.neutz = False
        return
-
     # commanders get a chance to tac-move towards you 
     if (((game.comhere or game.ishere) and not game.justin) or game.skill == SKILL_EMERITUS) and torps_ok:
        moveklings()
-
     # if no enemies remain after movement, we're done 
-    if game.nenhere==0 or (game.nenhere==1 and iqhere and not iqengry):
+    if game.nenhere==0 or (game.nenhere==1 and thing == game.quadrant and not iqengry):
        return
-
     # set up partial hits if attack happens during shield status change 
     pfac = 1.0/game.inshld
     if game.shldchg:
-       chgfac = 0.25+0.5*Rand()
-
+       chgfac = 0.25+0.5*random.random()
     skip(1)
-
     # message verbosity control 
     if game.skill <= SKILL_FAIR:
        where = "sector"
-
-    for loop in range(1, game.nenhere+1):
+    for loop in range(game.nenhere):
        if game.kpower[loop] < 0:
            continue;   # too weak to attack 
        # compute hit strength and diminish shield power 
-       r = Rand()
+       r = random.random()
        # Increase chance of photon torpedos if docked or enemy energy low 
        if game.condition == "docked":
            r *= 0.25
@@ -1449,7 +1614,7 @@ def attack(torps_ok):
            if game.condition == "docked":
                continue; # Don't waste the effort! 
            attempt = True; # Attempt to attack 
-           dustfac = 0.8+0.05*Rand()
+           dustfac = 0.8+0.05*random.random()
            hit = game.kpower[loop]*math.pow(dustfac,game.kavgd[loop])
            game.kpower[loop] *= 0.75
        else: # Enemy uses photon torpedo 
@@ -1461,7 +1626,7 @@ def attack(torps_ok):
                crmena(False, iquad, where, jay)
            attempt = True
            prout("  ")
-           r = (Rand()+Rand())*0.5 -0.5
+           r = (random.random()+random.random())*0.5 -0.5
            r += 0.002*game.kpower[loop]*r
            hit = torpedo(course, r, jay, 1, 1)
            if (game.state.remkl + game.state.remcom + game.state.nscrem)==0:
@@ -1531,7 +1696,7 @@ def attack(torps_ok):
     prout(_("%d%%,   torpedoes left %d") % (percent, game.torps))
     # Check if anyone was hurt 
     if hitmax >= 200 or hittot >= 500:
-       icas= hittot*Rand()*0.015
+       icas= hittot*random.random()*0.015
        if icas >= 2:
            skip(1)
            prout(_("Mc Coy-  \"Sickbay to bridge.  We suffered %d casualties") % icas)
@@ -1539,7 +1704,7 @@ def attack(torps_ok):
            game.casual += icas
            game.state.crew -= icas
     # After attack, reset average distance to enemies 
-    for loop in range(1, game.nenhere+1):
+    for loop in range(game.nenhere):
        game.kavgd[loop] = game.kdist[loop]
     sortklings()
     return;
@@ -1547,7 +1712,6 @@ def attack(torps_ok):
 def deadkl(w, type, mv):
     # kill a Klingon, Tholian, Romulan, or Thingy 
     # Added mv to allow enemy to "move" before dying 
-
     crmena(True, type, sector, mv)
     # Decide what kind of enemy it is and update appropriately 
     if type == IHR:
@@ -1559,8 +1723,9 @@ def deadkl(w, type, mv):
        # Killed a Tholian 
        game.ithere = False
     elif type == IHQUEST:
-       # Killed a Thingy 
-       iqhere = iqengry = False
+       # Killed a Thingy
+        global iqengry
+       iqengry = False
        invalidate(thing)
     else:
        # Some type of a Klingon 
@@ -1568,7 +1733,7 @@ def deadkl(w, type, mv):
        game.klhere -= 1
        if type == IHC:
            game.comhere = False
-           for i in range(1, game.state.remcom+1):
+           for i in range(game.state.remcom):
                if game.state.kcmdr[i] == game.quadrant:
                    break
            game.state.kcmdr[i] = game.state.kcmdr[game.state.remcom]
@@ -1589,7 +1754,6 @@ def deadkl(w, type, mv):
            unschedule(FSCDBAS)
        else:
            prout("*** Internal error, deadkl() called on %s\n" % type)
-
     # For each kind of enemy, finish message to player 
     prout(_(" destroyed."))
     game.quad[w.x][w.y] = IHDOT
@@ -1599,20 +1763,20 @@ def deadkl(w, type, mv):
     # Remove enemy ship from arrays describing local conditions 
     if is_scheduled(FCDBAS) and game.battle == game.quadrant and type==IHC:
        unschedule(FCDBAS)
-    for i in range(1, game.nenhere+1):
+    for i in range(game.nenhere):
        if game.ks[i] == w:
+            for j in range(i, game.nenhere):
+                game.ks[j] = game.ks[j+1]
+                game.kpower[j] = game.kpower[j+1]
+                game.kavgd[j] = game.kdist[j] = game.kdist[j+1]
+            game.ks[game.nenhere].x = 0
+            game.ks[game.nenhere].y = 0
+            game.kdist[game.nenhere] = 0
+            game.kavgd[game.nenhere] = 0
+            game.kpower[game.nenhere] = 0
+            game.nenhere -= 1
            break
-    game.nenhere -= 1
-    if i <= game.nenhere:
-        for j in range(i, game.nenhere+1):
-           game.ks[j] = game.ks[j+1]
-           game.kpower[j] = game.kpower[j+1]
-           game.kavgd[j] = game.kdist[j] = game.kdist[j+1]
-    game.ks[game.nenhere+1].x = 0
-    game.ks[game.nenhere+1].x = 0
-    game.kdist[game.nenhere+1] = 0
-    game.kavgd[game.nenhere+1] = 0
-    game.kpower[game.nenhere+1] = 0
+        break
     return;
 
 def targetcheck(x, y):
@@ -1698,12 +1862,12 @@ def photon():
            if key != IHREAL:
                huh()
                return
-           targ[i][1] = aaitem
+           targ[i][1] = int(aaitem-0.5)
            key = scan()
            if key != IHREAL:
                huh()
                return
-           targ[i][2] = aaitem
+           targ[i][2] = int(aaitem-0.5)
            chew()
             course[i] = targetcheck(targ[i][1], targ[i][2])
             if course[i] == None:
@@ -1713,10 +1877,10 @@ def photon():
     for i in range(1, n+1):
        if game.condition != "docked":
            game.torps -= 1
-       r = (Rand()+Rand())*0.5 -0.5
+       r = (random.random()+random.random())*0.5 -0.5
        if math.fabs(r) >= 0.47:
            # misfire! 
-           r = (Rand()+1.2) * r
+           r = (random.random()+1.2) * r
            if n>1:
                prouts(_("***TORPEDO NUMBER %d MISFIRES") % i)
            else:
@@ -1724,9 +1888,9 @@ def photon():
            skip(1)
            if i < n:
                prout(_("  Remainder of burst aborted."))
-           if Rand() <= 0.2:
+           if random.random() <= 0.2:
                prout(_("***Photon tubes damaged by misfire."))
-               game.damage[DPHOTON] = game.damfac*(1.0+2.0*Rand())
+               game.damage[DPHOTON] = game.damfac*(1.0+2.0*random.random())
            break
        if game.shldup or game.condition == "docked":
            r *= 1.0 + 0.0001*game.shield
@@ -1740,15 +1904,14 @@ def overheat(rpow):
     # check for phasers overheating 
     if rpow > 1500:
        chekbrn = (rpow-1500.)*0.00038
-       if Rand() <= chekbrn:
+       if random.random() <= chekbrn:
            prout(_("Weapons officer Sulu-  \"Phasers overheated, sir.\""))
-           game.damage[DPHASER] = game.damfac*(1.0 + Rand()) * (1.0+chekbrn)
+           game.damage[DPHASER] = game.damfac*(1.0 + random.random()) * (1.0+chekbrn)
 
 def checkshctrl(rpow):
     # check shield control 
-       
     skip(1)
-    if Rand() < 0.998:
+    if random.random() < 0.998:
        prout(_("Shields lowered."))
        return False
     # Something bad has happened 
@@ -1766,7 +1929,7 @@ def checkshctrl(rpow):
     prouts(_("Sulu-  \"Captain! Shield malfunction! Phaser fire contained!\""))
     skip(2)
     prout(_("Lt. Uhura-  \"Sir, all decks reporting damage.\""))
-    icas = hit*Rand()*0.012
+    icas = hit*random.random()*0.012
     skip(1)
     fry(0.8*hit)
     if icas:
@@ -1781,16 +1944,16 @@ def checkshctrl(rpow):
     overheat(rpow)
     return True;
 
-def hittem(doublehits):
+def hittem(hits):
     # register a phaser hit on Klingons and Romulans 
     nenhr2=game.nenhere; kk=1
     w = coord()
     skip(1)
-    for k in range(1, nenhr2+1):
+    for k in range(nenhr2):
         wham = hits[k]
        if wham==0:
            continue
-       dustfac = 0.9 + 0.01*Rand()
+       dustfac = 0.9 + 0.01*random.random()
        hit = wham*math.pow(dustfac,game.kdist[kk])
        kpini = game.kpower[kk]
        kp = math.fabs(kpini)
@@ -1810,6 +1973,7 @@ def hittem(doublehits):
            proutn(_("Very small hit on "))
        ienm = game.quad[w.x][w.y]
        if ienm==IHQUEST:
+            global iqengry
            iqengry = True
        crmena(False, ienm, "sector", w)
        skip(1)
@@ -1821,8 +1985,8 @@ def hittem(doublehits):
                return
            kk -= 1; # don't do the increment 
        else: # decide whether or not to emasculate klingon 
-           if kpow > 0 and Rand() >= 0.9 and \
-               kpow <= ((0.4 + 0.4*Rand())*kpini):
+           if kpow > 0 and random.random() >= 0.9 and \
+               kpow <= ((0.4 + 0.4*random.random())*kpini):
                prout(_("***Mr. Spock-  \"Captain, the vessel at Sector %s"), w)
                prout(_("   has just lost its firepower.\""))
                game.kpower[kk] = -kpow
@@ -1836,7 +2000,6 @@ def phasers():
     ifast = False; no = False; itarg = True; msgflag = True
     automode = "NOTSET"
     key=0
-
     skip(1)
     # SR sensors and Computer are needed fopr automode 
     if damaged(DSRSENS) or damaged(DCOMPTR):
@@ -1860,8 +2023,8 @@ def phasers():
            return
        prout(_("Weapons Officer Sulu-  \"High-speed shield control enabled, sir.\""))
        ifast = True
-               
-    # Original code so convoluted, I re-did it all 
+    # 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=scan()
        if key == IHALPHA:
@@ -1917,8 +2080,8 @@ def phasers():
         while True:
            chew()
            if not kz:
-               for i in range(1, game.nenhere+1):
-                   irec += math.fabs(game.kpower[i])/(PHASEFAC*math.pow(0.90,game.kdist[i]))*(1.01+0.05*Rand()) + 1.0
+               for i in range(game.nenhere):
+                   irec += math.fabs(game.kpower[i])/(PHASEFAC*math.pow(0.90,game.kdist[i]))*(1.01+0.05*random.random()) + 1.0
            kz=1
            proutn(_("%d units required. ") % irec)
            chew()
@@ -1950,12 +2113,12 @@ def phasers():
        if game.nenhere:
            extra = 0.0
            powrem = rpow
-           for i in range(1, game.nenhere+1):
+           for i in range(game.nenhere):
                hits[i] = 0.0
                if powrem <= 0:
                    continue
                hits[i] = math.fabs(game.kpower[i])/(PHASEFAC*math.pow(0.90,game.kdist[i]))
-               over = (0.01 + 0.05*Rand())*hits[i]
+               over = (0.01 + 0.05*random.random())*hits[i]
                temp = powrem
                powrem -= hits[i] + over
                if powrem <= 0 and temp < hits[i]:
@@ -1990,7 +2153,7 @@ def phasers():
            skip(1)
     elif automode == "MANUAL":
        rpow = 0.0
-        for k in range(1, game.nenhere+1):
+        for k in range(game.nenhere):
            aim = game.ks[k]
            ienm = game.quad[aim.x][aim.y]
            if msgflag:
@@ -2010,7 +2173,7 @@ def phasers():
            if key == IHEOL:
                chew()
                if itarg and k > kz:
-                   irec=(abs(game.kpower[k])/(PHASEFAC*math.pow(0.9,game.kdist[k]))) * (1.01+0.05*Rand()) + 1.0
+                   irec=(abs(game.kpower[k])/(PHASEFAC*math.pow(0.9,game.kdist[k]))) * (1.01+0.05*random.random()) + 1.0
                kz = k
                proutn("(")
                if not damaged(DCOMPTR):
@@ -2066,7 +2229,7 @@ def phasers():
     if ifast:
        skip(1)
        if no == 0:
-           if Rand() >= 0.99:
+           if random.random() >= 0.99:
                prout(_("Sulu-  \"Sir, the high-speed shield control has malfunctioned . . ."))
                prouts(_("         CLICK   CLICK   POP  . . ."))
                prout(_(" No response, sir!"))
@@ -2084,8 +2247,6 @@ def phasers():
 # only have one FDISTR/FENSLV/FREPRO sequence going at any given time
 # BSD Trek, from which we swiped the idea, can have up to 5.
 
-import math
-
 def unschedule(evtype):
     # remove an event from the schedule 
     game.future[evtype].date = FOREVER
@@ -2100,7 +2261,7 @@ def scheduled(evtype):
     return game.future[evtype].date
 
 def schedule(evtype, offset):
-    # schedule an event of specified type 
+    # schedule an event of specified type
     game.future[evtype].date = game.state.date + offset
     return game.future[evtype]
 
@@ -2117,7 +2278,6 @@ def cancelrest():
            game.resting = False
            game.optime = 0.0
            return True
-
     return False
 
 def events():
@@ -2147,7 +2307,7 @@ def events():
         # Check to see if shuttle is aboard 
         if game.iscraft == "offship":
             skip(1)
-            if Rand() > 0.5:
+            if random.random() > 0.5:
                 prout(_("Galileo, left on the planet surface, is captured"))
                 prout(_("by aliens and made into a flying McDonald's."))
                 game.damage[DSHUTTL] = -10
@@ -2272,7 +2432,7 @@ def events():
        if game.condition == "docked":
            repair /= game.docfac
        # Don't fix Deathray here 
-       for l in range(0, NDEVICES):
+       for l in range(NDEVICES):
            if game.damage[l] > 0.0 and l != DDRAY:
                 if game.damage[l]-repair > 0.0:
                     game.damage[l] -= repair
@@ -2319,7 +2479,7 @@ def events():
             if game.state.remcom == 0:
                 unschedule(FTBEAM)
                 continue
-            i = Rand()*game.state.remcom+1.0
+            i = random.randrange(game.state.remcom)
             yank = square(game.state.kcmdr[i].x-game.quadrant.x) + square(game.state.kcmdr[i].y-game.quadrant.y)
             if istract or game.condition == "docked" or yank == 0:
                 # Drats! Have to reschedule 
@@ -2339,8 +2499,8 @@ def events():
                unschedule(FCDBAS)
                 continue
            i = 0
-           for j in range(1, game.state.rembase+1):
-               for k in range(1, game.state.remcom+1):
+           for j in range(game.state.rembase):
+               for k in range(game.state.remcom):
                    if game.state.baseq[j] == game.state.kcmdr[k] and \
                        not game.state.baseq[j] == game.quadrant and \
                         not game.state.baseq[j] == game.state.kscmdr:
@@ -2354,7 +2514,7 @@ def events():
                continue
            # commander + starbase combination found -- launch attack 
            game.battle = game.state.baseq[j]
-           schedule(FCDBAS, 1.0+3.0*Rand())
+           schedule(FCDBAS, 1.0+3.0*random.random())
            if game.isatb: # extra time if SC already attacking 
                postpone(FCDBAS, scheduled(FSCDBAS)-game.state.date)
            game.future[FBATTAK].date = game.future[FCDBAS].date + expran(0.3*game.intime)
@@ -2382,7 +2542,7 @@ def events():
            if evcode==FCDBAS:
                unschedule(FCDBAS)
                # find the lucky pair 
-               for i in range(1, game.state.remcom+1):
+               for i in range(game.state.remcom):
                    if game.state.kcmdr[i] == game.battle: 
                        break
                if i > game.state.remcom or game.state.rembase == 0 or \
@@ -2448,8 +2608,8 @@ def events():
                # supernova'ed, and which has some Klingons in it
                w = randplace(GALSIZE)
                q = game.state.galaxy[w.x][w.y]
-                if not (game.quadrant == w or q.planet == NOPLANET or \
-                     game.state.planets[q.planet].inhabited == UNINHABITED or \
+                if not (game.quadrant == w or q.planet == None or \
+                     not q.planet.inhabited or \
                      q.supernova or q.status!=secure or q.klingons<=0):
                     break
             else:
@@ -2532,7 +2692,7 @@ def events():
                    prout(_("launched a warship from %s.") % q.planet)
                else:
                    prout(_("Uhura- Starfleet reports increased Klingon activity"))
-                   if q.planet != NOPLANET:
+                   if q.planet != None:
                        proutn(_("near %s") % q.planet)
                    prout(_("in Quadrant %s.") % w)
                                
@@ -2555,9 +2715,7 @@ def wait():
        proutn(_("Are you sure? "))
        if ja() == False:
            return
-
     # Alternate resting periods (events) with attacks 
-
     game.resting = True
     while True:
        if delay <= 0:
@@ -2567,7 +2725,7 @@ def wait():
            return
        temp = game.optime = delay
        if game.nenhere:
-           rtime = 1.0 + Rand()
+           rtime = 1.0 + random.random()
            if rtime < temp:
                temp = rtime
            game.optime = temp
@@ -2600,12 +2758,10 @@ 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(); scratch = coord()
-
-    if Rand() < 0.05:
+    if random.random() < 0.05:
        # Wow! We've supernova'ed 
        supernova(False, nov)
        return
-
     # handle initial nova 
     game.quad[nov.x][nov.y] = IHDOT
     crmena(False, IHSTAR, sector, nov)
@@ -2634,7 +2790,7 @@ def nova(nov):
                     if iquad in (IHDOT, IHQUEST, IHBLANK, IHT, IHWEB):
                        break
                    elif iquad == IHSTAR: # Affect another star 
-                       if Rand() < 0.05:
+                       if random.random() < 0.05:
                            # This star supernovas 
                            scratch = supernova(False)
                            return
@@ -2647,12 +2803,12 @@ def nova(nov):
                        prout(_(" novas."))
                        game.quad[scratch.x][scratch.y] = IHDOT
                    elif iquad == IHP: # Destroy planet 
-                       game.state.galaxy[game.quadrant.x][game.quadrant.y].planet = NOPLANET
+                       game.state.galaxy[game.quadrant.x][game.quadrant.y].planet = None
                        game.state.nplankl += 1
                        crmena(True, IHP, sector, scratch)
                        prout(_(" destroyed."))
-                       game.state.planets[game.iplnet].pclass = destroyed
-                       game.iplnet = 0
+                       game.iplnet.pclass = "destroyed"
+                       game.iplnet = None
                        invalidate(game.plnet)
                        if game.landed:
                            finish(FPNOVA)
@@ -2660,7 +2816,7 @@ def nova(nov):
                        game.quad[scratch.x][scratch.y] = IHDOT
                    elif iquad == IHB: # Destroy base 
                        game.state.galaxy[game.quadrant.x][game.quadrant.y].starbase = False
-                       for i in range(1, game.state.rembase+1):
+                       for i in range(game.state.rembase):
                            if game.state.baseq[i] == game.quadrant: 
                                break
                        game.state.baseq[i] = game.state.baseq[game.state.rembase]
@@ -2682,7 +2838,7 @@ def nova(nov):
                                game.shield = 0.0
                                game.shldup = False
                                prout(_("***Shields knocked out."))
-                               game.damage[DSHIELD] += 0.005*game.damfac*Rand()*diff
+                               game.damage[DSHIELD] += 0.005*game.damfac*random.random()*diff
                        else:
                            game.energy -= 2000.0
                        if game.energy <= 0:
@@ -2695,7 +2851,7 @@ def nova(nov):
                    elif iquad == IHK: # kill klingon 
                        deadkl(scratch,iquad, scratch)
                     elif iquad in (IHC,IHS,IHR): # Damage/destroy big enemies 
-                       for ll in range(1, game.nenhere+1):
+                       for ll in range(game.nenhere):
                            if game.ks[ll] == scratch:
                                break
                        game.kpower[ll] -= 800.0 # If firepower is lost, die 
@@ -2746,7 +2902,7 @@ def nova(nov):
     game.optime = 10.0*game.dist/16.0
     skip(1)
     prout(_("Force of nova displaces starship."))
-    imove(True)
+    imove(novapush=True)
     game.optime = 10.0*game.dist/16.0
     return
        
@@ -2754,7 +2910,6 @@ def supernova(induced, w=None):
     # star goes supernova 
     num = 0; npdead = 0
     nq = coord()
-
     if w != None: 
        nq = w
     else:
@@ -2762,14 +2917,14 @@ def supernova(induced, w=None):
        # Scheduled supernova -- select star 
        # logic changed here so that we won't favor quadrants in top
         # left of universe 
-       for nq.x in range(1, GALSIZE+1):
-           for nq.y in range(1, GALSIZE+1):
+       for nq.x in range(GALSIZE):
+           for nq.y in range(GALSIZE):
                stars += game.state.galaxy[nq.x][nq.y].stars
        if stars == 0:
            return # nothing to supernova exists 
-       num = Rand()*stars + 1
-       for nq.x in range(1, GALSIZE+1):
-           for nq.y in range(1, GALSIZE+1):
+       num = random.randrange(stars) + 1
+       for nq.x in range(GALSIZE):
+           for nq.y in range(GALSIZE):
                num -= game.state.galaxy[nq.x][nq.y].stars
                if num <= 0:
                    break
@@ -2779,7 +2934,6 @@ def supernova(induced, w=None):
            proutn("=== Super nova here?")
            if ja() == True:
                nq = game.quadrant
-
     if not nq == game.quadrant or game.justin:
        # it isn't here, or we just entered (treat as enroute) 
        if communicating():
@@ -2789,16 +2943,15 @@ def supernova(induced, w=None):
     else:
        ns = coord()
        # we are in the quadrant! 
-       num = Rand()* game.state.galaxy[nq.x][nq.y].stars + 1
-       for ns.x in range(1, QUADSIZE+1):
-           for ns.y in range(1, QUADSIZE+1):
+       num = random.randrange(game.state.galaxy[nq.x][nq.y].stars) + 1
+       for ns.x in range(QUADSIZE):
+           for ns.y in range(QUADSIZE):
                if game.quad[ns.x][ns.y]==IHSTAR:
                    num -= 1
                    if num==0:
                        break
            if num==0:
                break
-
        skip(1)
        prouts(_("***RED ALERT!  RED ALERT!"))
        skip(1)
@@ -2821,7 +2974,7 @@ def supernova(induced, w=None):
        unschedule(FSCDBAS)
     if game.state.remcom:
        maxloop = game.state.remcom
-       for l in range(1, maxloop+1):
+       for l in range(maxloop):
            if game.state.kcmdr[l] == nq:
                game.state.kcmdr[l] = game.state.kcmdr[game.state.remcom]
                invalidate(game.state.kcmdr[game.state.remcom])
@@ -2838,12 +2991,12 @@ def supernova(induced, w=None):
     # Destroy planets 
     for loop in range(game.inplan):
        if game.state.planets[loop].w == nq:
-           game.state.planets[loop].pclass = destroyed
+           game.state.planets[loop].pclass = "destroyed"
            npdead += 1
     # Destroy any base in supernovaed quadrant 
     if game.state.rembase:
        maxloop = game.state.rembase
-       for loop in range(1, maxloop+1):
+       for loop in range(maxloop):
            if game.state.baseq[loop] == nq:
                game.state.baseq[loop] = game.state.baseq[game.state.rembase]
                invalidate(game.state.baseq[game.state.rembase])
@@ -2907,7 +3060,7 @@ def selfdestruct():
     prouts("                         3"); skip(1)
     prouts("                            2"); skip(1)
     prouts("                              1"); skip(1)
-    if Rand() < 0.15:
+    if random.random() < 0.15:
        prouts(_("GOODBYE-CRUEL-WORLD"))
        skip(1)
     kaboom()
@@ -2950,7 +3103,6 @@ def badpoints():
         badpt += 200.0
     return badpt
 
-
 def finish(ifin):
     # end the game, with appropriate notfications 
     igotit = False
@@ -3139,10 +3291,10 @@ def finish(ifin):
     if (game.state.remkl + game.state.remcom + game.state.nscrem) != 0:
        goodies = game.state.remres/game.inresor
        baddies = (game.state.remkl + 2.0*game.state.remcom)/(game.inkling+2.0*game.incom)
-       if goodies/baddies >= 1.0+0.5*Rand():
+       if goodies/baddies >= 1.0+0.5*random.random():
            prout(_("As a result of your actions, a treaty with the Klingon"))
            prout(_("Empire has been signed. The terms of the treaty are"))
-           if goodies/baddies >= 3.0+Rand():
+           if goodies/baddies >= 3.0+random.random():
                prout(_("favorable to the Federation."))
                skip(1)
                prout(_("Congratulations!"))
@@ -3161,7 +3313,6 @@ def finish(ifin):
 def score():
     # compute player's score 
     timused = game.state.date - game.indate
-
     iskill = game.skill
     if (timused == 0 or (game.state.remkl + game.state.remcom + game.state.nscrem) != 0) and timused < 5.0:
        timused = 5.0
@@ -3249,7 +3400,7 @@ def plaque():
     skip(2)
     while True:
         proutn(_("File or device name for your plaque: "))
-        cgetline(winner, sizeof(winner))
+        winner = cgetline()
         try:
             fp = open(winner, "w")
             break
@@ -3257,10 +3408,9 @@ def plaque():
             prout(_("Invalid name."))
 
     proutn(_("Enter name to go on plaque (up to 30 characters): "))
-    cgetline(winner, sizeof(winner))
+    winner = cgetline()
     # The 38 below must be 64 for 132-column paper 
     nskip = 38 - len(winner)/2
-
     fp.write("\n\n\n\n")
     # --------DRAW ENTERPRISE PICTURE. 
     fp.write("                                       EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n" )
@@ -3307,6 +3457,7 @@ def plaque():
 
 rows = linecount = 0   # for paging 
 stdscr = None
+replayfp = None
 fullscreen_window = None
 srscan_window     = None
 report_window     = None
@@ -3314,6 +3465,7 @@ status_window     = None
 lrscan_window     = None
 message_window    = None
 prompt_window     = None
+curwnd = None
 
 def outro():
     "wrap up, either normally or due to signal"
@@ -3324,12 +3476,12 @@ def outro():
        #resetterm()
        #echo()
        curses.endwin()
-       stdout.write('\n')
+       sys.stdout.write('\n')
     if logfp:
        logfp.close()
 
 def iostart():
-    global stdscr
+    global stdscr, rows
     #setlocale(LC_ALL, "")
     #bindtextdomain(PACKAGE, LOCALEDIR)
     #textdomain(PACKAGE)
@@ -3371,7 +3523,6 @@ def iostart():
        setwnd(fullscreen_window)
        textcolor(DEFAULT)
 
-
 def waitfor():
     "wait for user action -- OK to do nothing if on a TTY"
     if game.options & OPTION_CURSES:
@@ -3402,16 +3553,16 @@ def pause_game():
         setwnd(message_window)
     else:
         global linecount
-        stdout.write('\n')
+        sys.stdout.write('\n')
         proutn(prompt)
         raw_input()
-        for j in range(0, rows):
-            stdout.write('\n')
+        for j in range(rows):
+            sys.stdout.write('\n')
         linecount = 0
 
 def skip(i):
     "Skip i lines.  Pause game if this would cause a scrolling event."
-    while dummy in range(i):
+    for dummy in range(i):
        if game.options & OPTION_CURSES:
             (y, x) = curwnd.getyx()
             (my, mx) = curwnd.getmaxyx()
@@ -3423,10 +3574,10 @@ def skip(i):
        else:
             global linecount
            linecount += 1
-           if linecount >= rows:
+           if rows and linecount >= rows:
                pause_game()
            else:
-               stdout.write('\n')
+               sys.stdout.write('\n')
 
 def proutn(line):
     "Utter a line with no following line feed."
@@ -3434,7 +3585,8 @@ def proutn(line):
        curwnd.addstr(line)
        curwnd.refresh()
     else:
-       stdout.write(line)
+       sys.stdout.write(line)
+        sys.stdout.flush()
 
 def prout(line):
     proutn(line)
@@ -3443,15 +3595,15 @@ def prout(line):
 def prouts(line):
     "print slowly!" 
     for c in line:
-       curses.delay_output(30)
+       time.sleep(0.03)
        proutn(c)
        if game.options & OPTION_CURSES:
            wrefresh(curwnd)
        else:
            sys.stdout.flush()
-    curses.delay_output(300)
+    time.sleep(0.03)
 
-def cgetline(line, max):
+def cgetline():
     "Get a line of input."
     if game.options & OPTION_CURSES:
        line = curwnd.getstr() + "\n"
@@ -3460,12 +3612,14 @@ def cgetline(line, max):
        if replayfp and not replayfp.closed:
            line = replayfp.readline()
        else:
-           sys.stdin.readline()
+           line = raw_input()
     if logfp:
        logfp.write(line)
+    return line
 
 def setwnd(wnd):
-    "Change windows -- OK for this to be a no-op in tty mode." 
+    "Change windows -- OK for this to be a no-op in tty mode."
+    global curwnd
     if game.options & OPTION_CURSES:
         curwnd = wnd
         curses.curs_set(wnd == fullscreen_window or wnd == message_window or wnd == prompt_window)
@@ -3528,9 +3682,6 @@ def highvideo():
     if game.options & OPTION_CURSES:
        curwnd.attron(curses.A_REVERSE)
  
-def commandhook(cmd, before):
-    pass
-
 #
 # Things past this point have policy implications.
 # 
@@ -3550,7 +3701,7 @@ def drawmaps(mode):
            setwnd(report_window)
            report_window.clear()
            report_window.move(0, 0)
-           status(0)
+           status()
            setwnd(lrscan_window)
            lrscan_window.clear()
            lrscan_window.move(0, 0)
@@ -3570,7 +3721,7 @@ def boom(w):
        srscan_window.attron(curses.A_REVERSE)
        put_srscan_sym(w, game.quad[w.x][w.y])
        #sound(500)
-       #delay(1000)
+       #time.sleep(1.0)
        #nosound()
        srscan_window.attroff(curses.A_REVERSE)
        put_srscan_sym(w, game.quad[w.x][w.y])
@@ -3606,18 +3757,18 @@ def tracktorpedo(w, l, i, n, iquad):
        if not damaged(DSRSENS) or game.condition=="docked":
            if i != 1 and l == 1:
                drawmaps(2)
-               curses.delay_output(400)
+               time.sleep(0.4)
            if (iquad==IHDOT) or (iquad==IHBLANK):
                put_srscan_sym(w, '+')
                #sound(l*10)
-               #curses.delay_output(100)
+               #time.sleep(0.1)
                #nosound()
                put_srscan_sym(w, iquad)
            else:
                curwnd.attron(curses.A_REVERSE)
                put_srscan_sym(w, iquad)
                #sound(500)
-               #curses.delay_output(1000)
+               #time.sleep(1.0)
                #nosound()
                curwnd.attroff(curses.A_REVERSE)
                put_srscan_sym(w, iquad)
@@ -3641,8 +3792,8 @@ def prstat(txt, data):
        skip(1)
        setwnd(status_window)
     else:
-        proutn(" " * NSYM - len(tx))
-    vproutn(data)
+        proutn(" " * (NSYM - len(txt)))
+    proutn(data)
     skip(1)
     if game.options & OPTION_CURSES:
        setwnd(report_window)
@@ -3655,27 +3806,25 @@ def imove(novapush):
     trbeam = False
 
     def no_quad_change():
-        # No quadrant change -- compute new avg enemy distances 
+        # No quadrant change -- compute new average enemy distances 
         game.quad[game.sector.x][game.sector.y] = game.ship
         if game.nenhere:
-            for m in range(1, game.nenhere+1):
+            for m in range(game.nenhere):
                 finald = distance(w, game.ks[m])
                 game.kavgd[m] = 0.5 * (finald+game.kdist[m])
                 game.kdist[m] = finald
             sortklings()
             if not game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova:
                 attack(False)
-            for m in range(1, game.nenhere+1):
+            for m in range(game.nenhere):
                 game.kavgd[m] = game.kdist[m]
         newcnd()
         drawmaps(0)
         setwnd(message_window)
-
     w.x = w.y = 0
     if game.inorbit:
        prout(_("Helmsman Sulu- \"Leaving standard orbit.\""))
        game.inorbit = False
-
     angle = ((15.0 - game.direc) * 0.5235988)
     deltax = -math.sin(angle)
     deltay = math.cos(angle)
@@ -3683,10 +3832,8 @@ def imove(novapush):
        bigger = math.fabs(deltax)
     else:
        bigger = math.fabs(deltay)
-               
     deltay /= bigger
     deltax /= bigger
-
     # If tractor beam is to occur, don't move full distance 
     if game.state.date+game.optime >= scheduled(FTBEAM):
        trbeam = True
@@ -3697,20 +3844,19 @@ def imove(novapush):
     game.quad[game.sector.x][game.sector.y] = IHDOT
     x = game.sector.x
     y = game.sector.y
-    n = 10.0*game.dist*bigger+0.5
-
+    n = int(10.0*game.dist*bigger+0.5)
     if n > 0:
        for m in range(1, n+1):
             x += deltax
             y += deltay
-           w.x = x + 0.5
-           w.y = y + 0.5
+           w.x = int(round(x))
+           w.y = int(round(y))
            if not VALID_SECTOR(w.x, w.y):
                # Leaving quadrant -- allow final enemy attack 
                # Don't do it if being pushed by Nova 
                if game.nenhere != 0 and not novapush:
                    newcnd()
-                   for m in range(1, game.nenhere+1):
+                   for m in range(game.nenhere):
                        finald = distance(w, game.ks[m])
                        game.kavgd[m] = 0.5 * (finald + game.kdist[m])
                    #
@@ -3723,31 +3869,30 @@ def imove(novapush):
                    if game.alldone:
                        return
                # compute final position -- new quadrant and sector 
-               x = QUADSIZE*(game.quadrant.x-1)+game.sector.x
-               y = QUADSIZE*(game.quadrant.y-1)+game.sector.y
-               w.x = x+10.0*game.dist*bigger*deltax+0.5
-               w.y = y+10.0*game.dist*bigger*deltay+0.5
+               x = (QUADSIZE*game.quadrant.x)+game.sector.x
+               y = (QUADSIZE*game.quadrant.y)+game.sector.y
+               w.x = int(round(x+10.0*game.dist*bigger*deltax))
+               w.y = int(round(y+10.0*game.dist*bigger*deltay))
                # check for edge of galaxy 
                kinks = 0
                 while True:
-                   kink = 0
-                   if w.x <= 0:
-                       w.x = -w.x + 1
-                       kink = 1
-                   if w.y <= 0:
-                       w.y = -w.y + 1
-                       kink = 1
-                   if w.x > GALSIZE*QUADSIZE:
-                       w.x = (GALSIZE*QUADSIZE*2)+1 - w.x
-                       kink = 1
-                   if w.y > GALSIZE*QUADSIZE:
-                       w.y = (GALSIZE*QUADSIZE*2)+1 - w.y
-                       kink = 1
+                   kink = False
+                   if w.x < 0:
+                       w.x = -w.x
+                       kink = True
+                   if w.y < 0:
+                       w.y = -w.y
+                       kink = True
+                   if w.x >= GALSIZE*QUADSIZE:
+                       w.x = (GALSIZE*QUADSIZE*2) - w.x
+                       kink = True
+                   if w.y >= GALSIZE*QUADSIZE:
+                       w.y = (GALSIZE*QUADSIZE*2) - w.y
+                       kink = True
                    if kink:
-                       kinks = 1
-               if not kink:
-                    break
-
+                       kinks += 1
+                    else:
+                        break
                if kinks:
                    game.nkinks += 1
                    if game.nkinks == 3:
@@ -3761,10 +3906,10 @@ def imove(novapush):
                # Compute final position in new quadrant 
                if trbeam: # Don't bother if we are to be beamed 
                    return
-               game.quadrant.x = (w.x+(QUADSIZE-1))/QUADSIZE
-               game.quadrant.y = (w.y+(QUADSIZE-1))/QUADSIZE
-               game.sector.x = w.x - QUADSIZE*(game.quadrant.x-1)
-               game.sector.y = w.y - QUADSIZE*(game.quadrant.y-1)
+               game.quadrant.x = w.x/QUADSIZE
+               game.quadrant.y = w.y/QUADSIZE
+               game.sector.x = w.x - (QUADSIZE*game.quadrant.x)
+               game.sector.y = w.y - (QUADSIZE*game.quadrant.y)
                skip(1)
                prout(_("Entering Quadrant %s.") % game.quadrant)
                game.quad[game.sector.x][game.sector.y] = game.ship
@@ -3777,7 +3922,7 @@ def imove(novapush):
                # object encountered in flight path 
                stopegy = 50.0*game.dist/game.optime
                game.dist = distance(game.sector, w) / (QUADSIZE * 1.0)
-                if iquad in (IHT. IHK, OHC, IHS, IHR, IHQUEST):
+                if iquad in (IHT, IHK, OHC, IHS, IHR, IHQUEST):
                    game.sector = w
                    ram(False, iquad, game.sector)
                    final = game.sector
@@ -3794,11 +3939,11 @@ def imove(novapush):
                    # possibility that you'll get timewarped instead.
                    # 
                    n=0
-                   for m in range(0, NDEVICES):
+                   for m in range(NDEVICES):
                        if game.damage[m]>0: 
                            n += 1
                    probf=math.pow(1.4,(game.energy+game.shield)/5000.0-1.0)*math.pow(1.3,1.0/(n+1)-1.0)
-                   if (game.options & OPTION_BLKHOLE) and Rand()>probf: 
+                   if (game.options & OPTION_BLKHOLE) and random.random()>probf: 
                        timwrp()
                    else: 
                        finish(FHOLE)
@@ -3858,8 +4003,7 @@ def dock(verbose):
        prout(_("Lt. Uhura- \"Captain, an important message from the starbase:\""))
        attackreport(False)
        game.iseenit = True
-
-# 
 # This program originally required input in terms of a (clock)
 # direction and distance. Somewhere in history, it was changed to
 # cartesian coordinates. So we need to convert.  Probably
@@ -3867,25 +4011,20 @@ def dock(verbose):
 # pain if the computer isn't working! Manual mode is still confusing
 # because it involves giving x and y motions, yet the coordinates
 # are always displayed y - x, where +y is downward!
-# 
 
-def getcd(isprobe, akey):
-    # get course and distance 
-    irowq=game.quadrant.x; icolq=game.quadrant.y; key=0
+def getcourse(isprobe, akey):
+    # get course and distance
+    key = 0
+    dquad = copy.copy(game.quadrant)
     navmode = "unspecified"
     itemp = "curt"
-    incr = coord()
+    dsect = coord()
     iprompt = False
-
-    # Get course direction and distance. If user types bad values, return
-    # with DIREC = -1.0.
-    game.direc = -1.0
-       
     if game.landed and not isprobe:
        prout(_("Dummy! You can't leave standard orbit until you"))
        proutn(_("are back aboard the ship."))
        chew()
-       return
+       return False
     while navmode == "unspecified":
        if damaged(DNAVSYS):
            if isprobe:
@@ -3902,7 +4041,6 @@ def getcd(isprobe, akey):
            akey = -1
        else: 
            key = scan()
-
        if key == IHEOL:
            proutn(_("Manual or automatic- "))
            iprompt = True
@@ -3919,7 +4057,7 @@ def getcd(isprobe, akey):
            else:
                huh()
                chew()
-               return
+               return False
        else: # numeric 
            if isprobe:
                prout(_("(Manual navigation assumed.)"))
@@ -3927,7 +4065,6 @@ def getcd(isprobe, akey):
                prout(_("(Manual movement assumed.)"))
            navmode = "manual"
            break
-
     if navmode == "automatic":
        while key == IHEOL:
            if isprobe:
@@ -3937,52 +4074,53 @@ def getcd(isprobe, akey):
            chew()
            iprompt = True
            key = scan()
-
        if key != IHREAL:
            huh()
-           return
-       xi = aaitem
+           return False
+       xi = int(round(aaitem))-1
        key = scan()
        if key != IHREAL:
            huh()
-           return
-       xj = aaitem
+           return False
+       xj = int(round(aaitem))-1
        key = scan()
        if key == IHREAL:
            # both quadrant and sector specified 
-           xk = aaitem
+           xk = int(round(aaitem))-1
            key = scan()
            if key != IHREAL:
                huh()
-               return
-           xl = aaitem
-
-           irowq = xi + 0.5
-           icolq = xj + 0.5
-           incr.y = xk + 0.5
-           incr.x = xl + 0.5
+               return False
+           xl = int(round(aaitem))-1
+           dquad.x = xi
+           dquad.y = xj
+           dsect.y = xk
+           dsect.x = xl
        else:
+            # only one pair of numbers was specified
            if isprobe:
                # only quadrant specified -- go to center of dest quad 
-               irowq = xi + 0.5
-               icolq = xj + 0.5
-               incr.y = incr.x = 5
+               dquad.x = xi
+               dquad.y = xj
+               dsect.y = dsect.x = 4   # preserves 1-origin behavior
            else:
-               incr.y = xi + 0.5
-               incr.x = xj + 0.5
+                # only sector specified
+               dsect.y = xi
+               dsect.x = xj
            itemp = "normal"
-       if not VALID_QUADRANT(icolq,irowq) or not VALID_SECTOR(incr.x,incr.y):
+       if not VALID_QUADRANT(dquad.y,dquad.x) or not VALID_SECTOR(dsect.x,dsect.y):
            huh()
-           return
+           return False
        skip(1)
        if not isprobe:
            if itemp > "curt":
                if iprompt:
-                   prout(_("Helmsman Sulu- \"Course locked in for Sector %s.\"") % incr)
+                   prout(_("Helmsman Sulu- \"Course locked in for Sector %s.\"") % dsect)
            else:
                prout(_("Ensign Chekov- \"Course laid in, Captain.\""))
-       deltax = icolq - game.quadrant.y + 0.1*(incr.x-game.sector.y)
-       deltay = game.quadrant.x - irowq + 0.1*(game.sector.x-incr.y)
+        # the actual deltas get computed here
+       deltax = dquad.y-game.quadrant.y + 0.1*(dsect.x-game.sector.y)
+       deltay = game.quadrant.x-dquad.x + 0.1*(game.sector.x-dsect.y)
     else: # manual 
        while key == IHEOL:
            proutn(_("X and Y displacements- "))
@@ -3992,26 +4130,27 @@ def getcd(isprobe, akey):
        itemp = "verbose"
        if key != IHREAL:
            huh()
-           return
+           return False
        deltax = aaitem
        key = scan()
        if key != IHREAL:
            huh()
-           return
+           return False
        deltay = aaitem
     # Check for zero movement 
     if deltax == 0 and deltay == 0:
        chew()
-       return
+       return False
     if itemp == "verbose" and not isprobe:
        skip(1)
        prout(_("Helmsman Sulu- \"Aye, Sir.\""))
+    # Course actually laid in.
     game.dist = math.sqrt(deltax*deltax + deltay*deltay)
     game.direc = math.atan2(deltax, deltay)*1.90985932
     if game.direc < 0.0:
        game.direc += 12.0
     chew()
-    return
+    return True
 
 def impulse():
     # move under impulse power 
@@ -4022,13 +4161,11 @@ def impulse():
        prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
        return
     if game.energy > 30.0:
-       getcd(False, 0)
-       if game.direc == -1.0:
+        if not getcourse(isprobe=False, akey=0):
            return
        power = 20.0 + 100.0*game.dist
     else:
        power = 30.0
-
     if power >= game.energy:
        # Insufficient power for trip 
        skip(1)
@@ -4051,7 +4188,7 @@ def impulse():
        if ja() == False:
            return
     # Activate impulse engines and pay the cost 
-    imove(False)
+    imove(novapush=False)
     game.ididit = True
     if game.alldone:
        return
@@ -4078,12 +4215,9 @@ def warp(timewarp):
            prout(_("Engineer Scott- \"Sorry, Captain. Until this damage"))
            prout(_("  is repaired, I can only give you warp 4.\""))
            return
-                       
-       # Read in course and distance 
-       getcd(False, 0)
-       if game.direc == -1.0:
+               # Read in course and distance 
+        if not getcourse(isprobe=False, akey=0):
            return
-
        # Make sure starship has enough energy for the trip 
        power = (game.dist+0.05)*game.warpfac*game.warpfac*game.warpfac*(game.shldup+1)
        if power >= game.energy:
@@ -4123,11 +4257,11 @@ def warp(timewarp):
     if game.warpfac > 6.0:
        # Decide if engine damage will occur 
        prob = game.dist*(6.0-game.warpfac)*(6.0-game.warpfac)/66.666666666
-       if prob > Rand():
+       if prob > random.random():
            blooey = True
-           game.dist = Rand()*game.dist
+           game.dist = random.random()*game.dist
        # Decide if time warp will occur 
-       if 0.5*game.dist*math.pow(7.0,game.warpfac-10.0) > Rand():
+       if 0.5*game.dist*math.pow(7.0,game.warpfac-10.0) > random.random():
            twarp = True
        if idebug and game.warpfac==10 and not twarp:
            blooey = False
@@ -4160,10 +4294,8 @@ def warp(timewarp):
                if game.quad[ix][iy] != IHDOT:
                    blooey = False
                    twarp = False
-                               
-
     # Activate Warp Engines and pay the cost 
-    imove(False)
+    imove(novapush=False)
     if game.alldone:
        return
     game.energy -= game.dist*game.warpfac*game.warpfac*game.warpfac*(game.shldup+1)
@@ -4173,7 +4305,7 @@ def warp(timewarp):
     if twarp:
        timwrp()
     if blooey:
-       game.damage[DWARPEN] = game.damfac*(3.0*Rand()+1.0)
+       game.damage[DWARPEN] = game.damfac*(3.0*random.random()+1.0)
        skip(1)
        prout(_("Engineering to bridge--"))
        prout(_("  Scott here.  The warp engines are damaged."))
@@ -4224,7 +4356,6 @@ def setwarp():
 
 def atover(igrab):
     # cope with being tossed out of quadrant by supernova or yanked by beam 
-
     chew()
     # is captain on planet? 
     if game.landed:
@@ -4236,7 +4367,7 @@ def atover(igrab):
            prout(_("But with the shields up it's hopeless."))
            finish(FPNOVA)
        prouts(_("His desperate attempt to rescue you . . ."))
-       if Rand() <= 0.5:
+       if random.random() <= 0.5:
            prout(_("fails."))
            finish(FPNOVA)
            return
@@ -4244,20 +4375,18 @@ def atover(igrab):
        if game.imine:
            game.imine = False
            proutn(_("The crystals mined were "))
-           if Rand() <= 0.25:
+           if random.random() <= 0.25:
                prout(_("lost."))
            else:
                prout(_("saved."))
                game.icrystl = True
     if igrab:
        return
-
     # Check to see if captain in shuttle craft 
     if game.icraft:
        finish(FSTRACTOR)
     if game.alldone:
        return
-
     # Inform captain of attempt to reach safety 
     skip(1)
     while True:
@@ -4281,16 +4410,16 @@ def atover(igrab):
            prout(_("Warp engines damaged."))
            finish(FSNOVAED)
            return
-       game.warpfac = 6.0+2.0*Rand()
+       game.warpfac = 6.0+2.0*random.random()
        game.wfacsq = game.warpfac * game.warpfac
        prout(_("Warp factor set to %d") % int(game.warpfac))
        power = 0.75*game.energy
        game.dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1))
-       distreq = 1.4142+Rand()
+       distreq = 1.4142+random.random()
        if distreq < game.dist:
            game.dist = distreq
        game.optime = 10.0*game.dist/game.wfacsq
-       game.direc = 12.0*Rand()        # How dumb! 
+       game.direc = 12.0*random.random()       # How dumb! 
        game.justin = False
        game.inorbit = False
        warp(True)
@@ -4311,7 +4440,7 @@ def atover(igrab):
 def timwrp():
     # let's do the time warp again 
     prout(_("***TIME WARP ENTERED."))
-    if game.state.snap and Rand() < 0.5:
+    if game.state.snap and random.random() < 0.5:
        # Go back in time 
        prout(_("You are traveling backwards in time %d stardates.") %
              int(game.state.date-game.snapsht.date))
@@ -4352,7 +4481,7 @@ def timwrp():
        prout(_("Spock has reconstructed a correct star chart from memory"))
     else:
        # Go forward in time 
-       game.optime = -0.5*game.intime*math.log(Rand())
+       game.optime = -0.5*game.intime*math.log(random.random())
        prout(_("You are traveling forward in time %d stardates.") % int(game.optime))
        # cheat to make sure no tractor beams occur during time warp 
        postpone(FTBEAM, game.optime)
@@ -4386,7 +4515,6 @@ def probe():
            prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""))
        return
     key = scan()
-
     if key == IHEOL:
        # slow mode, so let Kirk know how many probes there are left
         if game.nprobes == 1:
@@ -4396,7 +4524,6 @@ def probe():
        proutn(_("Are you sure you want to fire a probe? "))
        if ja() == False:
            return
-
     game.isarmed = False
     if key == IHALPHA and citem == "armed":
        game.isarmed = True
@@ -4404,8 +4531,7 @@ def probe():
     elif key == IHEOL:
        proutn(_("Arm NOVAMAX warhead? "))
        game.isarmed = ja()
-    getcd(True, key)
-    if game.direc == -1.0:
+    if not getcourse(isprobe=True, akey=key):
        return
     game.nprobes -= 1
     angle = ((15.0 - game.direc) * 0.5235988)
@@ -4415,7 +4541,6 @@ def probe():
        bigger = math.fabs(game.probeinx)
     else:
        bigger = math.fabs(game.probeiny)
-               
     game.probeiny /= bigger
     game.probeinx /= bigger
     game.proben = 10.0*game.dist*bigger +0.5
@@ -4448,7 +4573,6 @@ def mayday():
     # yell for help from nearest starbase 
     # There's more than one way to move in this game! 
     line = 0
-
     chew()
     # Test for conditions which prevent calling for help 
     if game.condition == "docked":
@@ -4472,7 +4596,7 @@ def mayday():
        ddist = distance(game.base, game.sector)
     else:
        ddist = FOREVER
-       for m in range(1, game.state.rembase+1):
+       for m in range(game.state.rembase):
            xdist = QUADSIZE * distance(game.state.baseq[m], game.quadrant)
            if xdist < ddist:
                ddist = xdist
@@ -4487,8 +4611,8 @@ def mayday():
     prout(_(" dematerializes."))
     game.sector.x=0
     for m in range(1, 5+1):
-       ix = game.base.x+3.0*Rand()-1
-       iy = game.base.y+3.0*Rand()-1
+       ix = game.base.x+3.0*random.random()-1
+       iy = game.base.y+3.0*random.random()-1
        if VALID_SECTOR(ix,iy) and game.quad[ix][iy]==IHDOT:
            # found one -- finish up 
            game.sector.x=ix
@@ -4509,7 +4633,7 @@ def mayday():
        game.quad[ix][iy]=(IHMATER0,IHMATER1,IHMATER2)[m-1]
        textcolor(RED)
        warble()
-       if Rand() > probf:
+       if random.random() > probf:
            break
        prout(_("fails."))
        curses.delay_output(500)
@@ -4587,7 +4711,7 @@ def abandon():
        if not (game.options & OPTION_WORLDS) and not damaged(DTRANSP):
            prout(_("Remainder of ship's complement beam down"))
            prout(_("to nearest habitable planet."))
-       elif q.planet != NOPLANET and not damaged(DTRANSP):
+       elif q.planet != None and not damaged(DTRANSP):
            prout(_("Remainder of ship's complement beam down to %s.") %
                    q.planet)
        else:
@@ -4602,7 +4726,7 @@ def abandon():
        game.nprobes = 0 # No probes 
        prout(_("You are captured by Klingons and released to"))
        prout(_("the Federation in a prisoner-of-war exchange."))
-       nb = Rand()*game.state.rembase+1
+       nb = random.random()*game.state.rembase+1
        # Set up quadrant and position FQ adjacient to base 
        if not game.quadrant == game.state.baseq[nb]:
            game.quadrant = game.state.baseq[nb]
@@ -4611,9 +4735,9 @@ def abandon():
        while True:
            # position next to base by trial and error 
            game.quad[game.sector.x][game.sector.y] = IHDOT
-           for l in range(1, QUADSIZE+1):
-               game.sector.x = 3.0*Rand() - 1.0 + game.base.x
-               game.sector.y = 3.0*Rand() - 1.0 + game.base.y
+           for l in range(QUADSIZE):
+               game.sector.x = 3.0*random.random() - 1.0 + game.base.x
+               game.sector.y = 3.0*random.random() - 1.0 + game.base.y
                if VALID_SECTOR(game.sector.x, game.sector.y) and \
                        game.quad[game.sector.x][game.sector.y] == IHDOT:
                     break
@@ -4634,7 +4758,7 @@ def abandon():
     game.iscraft = "offship" # Galileo disappears 
     # Resupply ship 
     game.condition="docked"
-    for l in range(0, NDEVICES): 
+    for l in range(NDEVICES): 
        game.damage[l] = 0.0
     game.damage[DSHUTTL] = -1
     game.energy = game.inenrg = 3000.0
@@ -4664,10 +4788,10 @@ def survey():
     prout(_("Spock-  \"Planet report follows, Captain.\""))
     skip(1)
     for i in range(game.inplan):
-       if game.state.planets[i].pclass == destroyed:
+       if game.state.planets[i].pclass == "destroyed":
            continue
        if (game.state.planets[i].known != "unknown" \
-            and game.state.planets[i].inhabited == UNINHABITED) \
+            and not game.state.planets[i].inhabited) \
             or idebug:
            iknow = True
            if idebug and game.state.planets[i].known=="unknown":
@@ -4699,12 +4823,12 @@ def orbit():
        prout(_(" not adjacent to planet."))
        skip(1)
        return
-    game.optime = 0.02+0.03*Rand()
+    game.optime = 0.02+0.03*random.random()
     prout(_("Helmsman Sulu-  \"Entering standard orbit, Sir.\""))
     newcnd()
     if consumeTime():
        return
-    game.height = (1400.0+7200.0*Rand())
+    game.height = (1400.0+7200.0*random.random())
     prout(_("Sulu-  \"Entered orbit at altitude %.2f kilometers.\"") % game.height)
     game.inorbit = True
     game.ididit = True
@@ -4715,23 +4839,26 @@ def sensor():
        if game.options & OPTION_TTY:
            prout(_("Short range sensors damaged."))
        return
-    if not is_valid(game.plnet):
+    if game.iplnet == None:
        if game.options & OPTION_TTY:
            prout(_("Spock- \"No planet in this quadrant, Captain.\""))
        return
-    if game.state.planets[game.iplnet].known == "unknown":
+    if game.iplnet.known == "unknown":
        prout(_("Spock-  \"Sensor scan for Quadrant %s-") % game.quadrant)
        skip(1)
        prout(_("         Planet at Sector %s is of class %s.") %
-             (sector,game.plnet, game.state.planets[game.iplnet]))
-       if game.state.planets[game.iplnet].known=="shuttle_down": 
+             (game.plnet, game.iplnet.pclass))
+       if game.iplnet.known=="shuttle_down": 
            prout(_("         Sensors show Galileo still on surface."))
        proutn(_("         Readings indicate"))
-       if game.state.planets[game.iplnet].crystals != present:
+       if game.iplnet.crystals != "present":
            proutn(_(" no"))
        prout(_(" dilithium crystals present.\""))
-       if game.state.planets[game.iplnet].known == "unknown":
-           game.state.planets[game.iplnet].known = "known"
+       if game.iplnet.known == "unknown":
+           game.iplnet.known = "known"
+    elif game.iplnet.inhabited:
+        prout(_("Spock-  \"The inhabited planet %s ") % game.iplnet.name)
+        prout(_("        is located at Sector %s, Captain.\"") % game.plnet)
 
 def beam():
     # use the transporter 
@@ -4740,7 +4867,7 @@ def beam():
     skip(1)
     if damaged(DTRANSP):
        prout(_("Transporter damaged."))
-       if not damaged(DSHUTTL) and (game.state.planets[game.iplnet].known=="shuttle_down" or game.iscraft == "onship"):
+       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:
@@ -4753,12 +4880,12 @@ def beam():
     if game.shldup:
        prout(_("Impossible to transport through shields."))
        return
-    if game.state.planets[game.iplnet].known=="unknown":
+    if game.iplnet.known=="unknown":
        prout(_("Spock-  \"Captain, we have no information on this planet"))
        prout(_("  and Starfleet Regulations clearly state that in this situation"))
        prout(_("  you may not go down.\""))
        return
-    if not game.landed and game.state.planets[game.iplnet].crystals==absent:
+    if not game.landed and game.iplnet.crystals=="absent":
        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?\" "))
@@ -4775,7 +4902,7 @@ def beam():
            prout(_("Engineering to bridge--"))
            prout(_("  Captain, we have enough energy only to transport you down to"))
            prout(_("  the planet, but there wouldn't be an energy for the trip back."))
-           if game.state.planets[game.iplnet].known == "shuttle_down":
+           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:
@@ -4783,7 +4910,7 @@ def beam():
                return
     if game.landed:
        # Coming from planet 
-       if game.state.planets[game.iplnet].known=="shuttle_down":
+       if game.iplnet.known=="shuttle_down":
            proutn(_("Spock-  \"Wouldn't you rather take the Galileo?\" "))
            if ja() == True:
                chew()
@@ -4806,7 +4933,7 @@ def beam():
     skip(1)
     prouts("WWHOOOIIIIIRRRRREEEE.E.E.  .  .  .  .   .    .")
     skip(2)
-    if Rand() > 0.98:
+    if random.random() > 0.98:
        prouts("BOOOIIIOOOIIOOOOIIIOIING . . .")
        skip(2)
        prout(_("Scotty-  \"Oh my God!  I've lost them.\""))
@@ -4817,7 +4944,7 @@ def beam():
     game.energy -= nrgneed
     skip(2)
     prout(_("Transport complete."))
-    if game.landed and game.state.planets[game.iplnet].known=="shuttle_down":
+    if game.landed and game.iplnet.known=="shuttle_down":
        prout(_("The shuttle craft Galileo is here!"))
     if not game.landed and game.imine:
        game.icrystl = True
@@ -4832,10 +4959,10 @@ def mine():
     if not game.landed:
        prout(_("Mining party not on planet."))
        return
-    if game.state.planets[game.iplnet].crystals == mined:
+    if game.iplnet.crystals == "mined":
        prout(_("This planet has already been strip-mined for dilithium."))
        return
-    elif game.state.planets[game.iplnet].crystals == absent:
+    elif game.iplnet.crystals == "absent":
        prout(_("No dilithium crystals on this planet."))
        return
     if game.imine:
@@ -4847,11 +4974,11 @@ def mine():
        skip(1)
        prout(_("there's no reason to mine more at this time."))
        return
-    game.optime = (0.1+0.2*Rand())*game.state.planets[game.iplnet].pclass
+    game.optime = (0.1+0.2*random.random())*game.iplnet.pclass
     if consumeTime():
        return
     prout(_("Mining operation complete."))
-    game.state.planets[game.iplnet].crystals = mined
+    game.iplnet.crystals = "mined"
     game.imine = game.ididit = True
 
 def usecrystals():
@@ -4882,7 +5009,7 @@ def usecrystals():
     skip(1)
     prouts(_("Scotty-  \"Keep your fingers crossed, Sir!\""))
     skip(1)
-    if Rand() <= game.cryprob:
+    if random.random() <= game.cryprob:
        prouts(_("  \"Activating now! - - No good!  It's***"))
        skip(2)
        prouts(_("***RED ALERT!  RED A*L********************************"))
@@ -4892,7 +5019,7 @@ def usecrystals():
        skip(1)
        kaboom()
        return
-    game.energy += 5000.0*(1.0 + 0.9*Rand())
+    game.energy += 5000.0*(1.0 + 0.9*random.random())
     prouts(_("  \"Activating now! - - "))
     prout(_("The instruments"))
     prout(_("   are going crazy, but I think it's"))
@@ -4906,7 +5033,7 @@ def shuttle():
     skip(1)
     if damaged(DSHUTTL):
        if game.damage[DSHUTTL] == -1.0:
-           if game.inorbit and game.state.planets[game.iplnet].known == "shuttle_down":
+           if game.inorbit and game.iplnet.known == "shuttle_down":
                prout(_("Ye Faerie Queene has no shuttle craft bay to dock it at."))
            else:
                prout(_("Ye Faerie Queene had no shuttle craft."))
@@ -4919,16 +5046,16 @@ def shuttle():
        crmshp()
        prout(_(" not in standard orbit."))
        return
-    if (game.state.planets[game.iplnet].known != "shuttle_down") and game.iscraft != "onship":
+    if (game.iplnet.known != "shuttle_down") and game.iscraft != "onship":
        prout(_("Shuttle craft not currently available."))
        return
-    if not game.landed and game.state.planets[game.iplnet].known=="shuttle_down":
+    if not game.landed and game.iplnet.known=="shuttle_down":
        prout(_("You will have to beam down to retrieve the shuttle craft."))
        return
     if game.shldup or game.condition == "docked":
        prout(_("Shuttle craft cannot pass through shields."))
        return
-    if game.state.planets[game.iplnet].known=="unknown":
+    if game.iplnet.known=="unknown":
        prout(_("Spock-  \"Captain, we have no information on this planet"))
        prout(_("  and Starfleet Regulations clearly state that in this situation"))
        prout(_("  you may not fly down.\""))
@@ -4960,7 +5087,7 @@ def shuttle():
            skip(1)
            if consumeTime():
                return
-           game.state.planets[game.iplnet].known="shuttle_down"
+           game.iplnet.known="shuttle_down"
            prout(_("Trip complete."))
            return
        else:
@@ -4970,7 +5097,7 @@ def shuttle():
            skip(1)
            prouts(_("The short hop begins . . ."))
            skip(1)
-           game.state.planets[game.iplnet].known="known"
+           game.iplnet.known="known"
            game.icraft = True
            skip(1)
            game.landed = False
@@ -4996,7 +5123,7 @@ def shuttle():
        game.iscraft = "offship"
        if consumeTime():
            return
-       game.state.planets[game.iplnet].known = "shuttle_down"
+       game.iplnet.known = "shuttle_down"
        game.landed = True
        game.icraft = False
        prout(_("Trip complete."))
@@ -5004,8 +5131,7 @@ def shuttle():
 
 def deathray():
     # use the big zapper 
-    r = Rand()
-       
+    r = random.random()
     game.ididit = False
     skip(1)
     chew()
@@ -5050,13 +5176,13 @@ def deathray():
            finish(FWON)    
        if (game.options & OPTION_PLAIN) == 0:
            prout(_("Spock-  \"Captain, I believe the `Experimental Death Ray'"))
-           if Rand() <= 0.05:
+           if random.random() <= 0.05:
                prout(_("   is still operational.\""))
            else:
                prout(_("   has been rendered nonfunctional.\""))
                game.damage[DDRAY] = 39.95
        return
-    r = Rand() # Pick failure method 
+    r = random.random()        # Pick failure method 
     if r <= .30:
        prouts(_("Sulu- \"Captain!  It's working!\""))
        skip(1)
@@ -5090,8 +5216,8 @@ def deathray():
        proutn(_("Spock-  \"I believe the word is"))
        prouts(_(" *ASTONISHING*"))
        prout(_(" Mr. Sulu."))
-       for i in range(1, QUADSIZE+1):
-           for j in range(1, QUADSIZE+1):
+       for i in range(QUADSIZE):
+           for j in range(QUADSIZE):
                if game.quad[i][j] == IHDOT:
                    game.quad[i][j] = IHQUEST
        prout(_("  Captain, our quadrant is now infested with"))
@@ -5243,8 +5369,8 @@ def damagereport():
 def rechart():
     # update the chart in the Enterprise's computer from galaxy data 
     game.lastchart = game.state.date
-    for i in range(1, GALSIZE+1):
-       for j in range(1, GALSIZE+1):
+    for i in range(GALSIZE):
+       for j in range(GALSIZE):
            if game.state.galaxy[i][j].charted:
                game.state.chart[i][j].klingons = game.state.galaxy[i][j].klingons
                game.state.chart[i][j].starbase = game.state.galaxy[i][j].starbase
@@ -5263,22 +5389,22 @@ def chart():
     if game.state.date > game.lastchart:
        prout(_("(Last surveillance update %d stardates ago).") % ((int)(game.state.date-game.lastchart)))
     prout("      1    2    3    4    5    6    7    8")
-    for i in range(1, GALSIZE+1):
-       proutn("%d |" % (i))
-       for j in range(1, GALSIZE+1):
+    for i in range(GALSIZE):
+       proutn("%d |" % (i+1))
+       for j in range(GALSIZE):
            if (game.options & OPTION_SHOWME) and i == game.quadrant.x and j == game.quadrant.y:
                proutn("<")
            else:
                proutn(" ")
            if game.state.galaxy[i][j].supernova:
-               strcpy(buf, "***")
+               show = "***"
            elif not game.state.galaxy[i][j].charted and game.state.galaxy[i][j].starbase:
-               strcpy(buf, ".1.")
+               show = ".1."
            elif game.state.galaxy[i][j].charted:
-               sprintf(buf, "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars))
+               show = "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars)
            else:
-               strcpy(buf, "...")
-           proutn(buf)
+               show = "..."
+           proutn(show)
            if (game.options & OPTION_SHOWME) and i == game.quadrant.x and j == game.quadrant.y:
                proutn(">")
            else:
@@ -5303,57 +5429,57 @@ def sectscan(goodScan, i, j):
     else:
        proutn("- ")
 
-def status(req):
+def status(req=0):
     # print status report lines 
 
     if not req or req == 1:
        prstat(_("Stardate"), _("%.1f, Time Left %.2f") \
                % (game.state.date, game.state.remtime))
-    elif not req or req == 2:
+    if not req or req == 2:
        if game.condition != "docked":
            newcnd()
         dam = 0
-       for t in range(0, NDEVICES):
+       for t in range(NDEVICES):
            if game.damage[t]>0: 
                dam += 1
        prstat(_("Condition"), _("%s, %i DAMAGES") % (game.condition.upper(), dam))
-    elif not req or req == 3:
+    if not req or req == 3:
        prstat(_("Position"), "%s , %s" % (game.quadrant, game.sector))
-    elif not req or req == 4:
+    if not req or req == 4:
        if damaged(DLIFSUP):
            if game.condition == "docked":
-               sprintf(s, _("DAMAGED, Base provides"))
+               s = _("DAMAGED, Base provides")
            else:
-               sprintf(s, _("DAMAGED, reserves=%4.2f") % game.lsupres)
+               s = _("DAMAGED, reserves=%4.2f") % game.lsupres
        else:
-           sprintf(s, _("ACTIVE"))
+           s = _("ACTIVE")
        prstat(_("Life Support"), s)
-    elif not req or req == 5:
-       prstat(_("Warp Factor"), "%.1f" % (game.warpfac))
-    elif not req or req == 6:
+    if not req or req == 5:
+       prstat(_("Warp Factor"), "%.1f" % game.warpfac)
+    if not req or req == 6:
         extra = ""
         if game.icrystl and (game.options & OPTION_SHOWME):
             extra = _(" (have crystals)")
-       prstat(_("Energy"), "%.2f%s" % game.energy, extra)
-    elif not req or req == 7:
+       prstat(_("Energy"), "%.2f%s" % (game.energy, extra))
+    if not req or req == 7:
        prstat(_("Torpedoes"), "%d" % (game.torps))
-    elif not req or req == 8:
+    if not req or req == 8:
        if damaged(DSHIELD):
-           strcpy(s, _("DAMAGED,"))
+           s = _("DAMAGED,")
        elif game.shldup:
-           strcpy(s, _("UP,"))
+           s = _("UP,")
        else:
-           strcpy(s, _("DOWN,"))
+           s = _("DOWN,")
        data = _(" %d%% %.1f units") \
                % (int((100.0*game.shield)/game.inshld + 0.5), game.shield)
-       prstat(_("Shields"), s)
-    elif not req or req == 9:
+       prstat(_("Shields"), s+data)
+    if not req or req == 9:
         prstat(_("Klingons Left"), "%d" \
                % (game.state.remkl + game.state.remcom + game.state.nscrem))
-    elif not req or req == 10:
+    if not req or req == 10:
        if game.options & OPTION_WORLDS:
            plnet = game.state.galaxy[game.quadrant.x][game.quadrant.y].planet
-           if plnet != NOPLANET and game.state.planets[plnet].inhabited != UNINHABITED:
+           if plnet and plnet.inhabited:
                prstat(_("Major system"), plnet.name)
            else:
                prout(_("Sector is uninhabited"))
@@ -5392,9 +5518,9 @@ def srscan():
     prout("    1 2 3 4 5 6 7 8 9 10")
     if game.condition != "docked":
        newcnd()
-    for i in range(1, QUADSIZE+1):
-       proutn("%2d  " % (i))
-       for j in range(1, QUADSIZE+1):
+    for i in range(QUADSIZE):
+       proutn("%2d  " % (i+1))
+       for j in range(QUADSIZE):
            sectscan(goodScan, i, j)
        skip(1)
                        
@@ -5414,34 +5540,32 @@ def eta():
        if scan()!=IHREAL:
            huh()
            return
-    w1.y = aaitem +0.5
+    w1.y = int(aaitem-0.5)
     if scan() != IHREAL:
        huh()
        return
-    w1.x = aaitem + 0.5
+    w1.x = int(aaitem-0.5)
     if scan() == IHREAL:
-       w2.y = aaitem + 0.5
+       w2.y = int(aaitem-0.5)
        if scan() != IHREAL:
            huh()
            return
-       w2.x = aaitem + 0.5
+       w2.x = int(aaitem-0.5)
     else:
        if game.quadrant.y>w1.x:
-           w2.x = 1
+           w2.x = 0
        else:
-           w2.x=QUADSIZE
+           w2.x=QUADSIZE-1
        if game.quadrant.x>w1.y:
-           w2.y = 1
+           w2.y = 0
        else:
-           w2.y=QUADSIZE
-
+           w2.y=QUADSIZE-1
     if not VALID_QUADRANT(w1.x, w1.y) or not VALID_SECTOR(w2.x, w2.y):
        huh()
        return
     game.dist = math.sqrt(square(w1.y-game.quadrant.y+0.1*(w2.y-game.sector.y))+
                square(w1.x-game.quadrant.x+0.1*(w2.x-game.sector.x)))
     wfl = False
-
     if prompt:
        prout(_("Answer \"no\" if you don't know the value:"))
     while True:
@@ -5566,7 +5690,7 @@ def visual():
        co = '?'
     else:
        co = game.quad[ix][iy]
-    printf("%d,%d %c " % (ix, iy, co))
+    printf("%d,%d %c " % (ix+1, iy+1, co))
     v += 1
     ix = game.sector.x + v.x
     iy = game.sector.y + v.y
@@ -5582,7 +5706,1233 @@ def visual():
        co = '?'
     else:
        co = game.quad[ix][iy]
-    prout("%c %d,%d\n" % (co, ix, iy))
+    prout("%c %d,%d\n" % (co, ix+1, iy+1))
     game.optime = 0.5
     game.ididit = True
 #endif
+
+# Code from setup.c begins here
+
+def prelim():
+    # issue a historically correct banner 
+    skip(2)
+    prout(_("-SUPER- STAR TREK"))
+    skip(1)
+#ifdef __HISTORICAL__
+#    prout(_("Latest update-21 Sept 78"))
+#    skip(1)
+#endif __HISTORICAL__ 
+
+def freeze(boss):
+    # save game 
+    if boss:
+       citem = "emsave.trk"
+    else:
+        key = scan()
+       if key == IHEOL:
+           proutn(_("File name: "))
+           key = scan()
+       if key != IHALPHA:
+           huh()
+           return
+       chew()
+        if '.' not in citem:
+           citem += ".trk"
+    try:
+        fp = open(citem, "wb")
+    except IOError:
+       prout(_("Can't freeze game as file %s") % citem)
+       return
+    cPickle.dump(game, fp)
+    fp.close()
+
+def thaw():
+    # retrieve saved game 
+    game.passwd[0] = '\0'
+    key = scan()
+    if key == IHEOL:
+       proutn(_("File name: "))
+       key = scan()
+    if key != IHALPHA:
+       huh()
+       return True
+    chew()
+    if '.' not in citem:
+        citem += ".trk"
+    try:
+        fp = open(citem, "rb")
+    except IOError:
+       prout(_("Can't thaw game in %s") % citem)
+       return
+    game = cPickle.load(fp)
+    fp.close()
+    return False
+
+# I used <http://www.memory-alpha.org> to find planets
+# with references in ST:TOS.  Eath and the Alpha Centauri
+# Colony have been omitted.
+# 
+# Some planets marked Class G and P here will be displayed as class M
+# because of the way planets are generated. This is a known bug.
+systnames = (
+    # Federation Worlds 
+    _("Andoria (Fesoan)"),     # several episodes 
+    _("Tellar Prime (Miracht)"),       # TOS: "Journey to Babel" 
+    _("Vulcan (T'Khasi)"),     # many episodes 
+    _("Medusa"),               # TOS: "Is There in Truth No Beauty?" 
+    _("Argelius II (Nelphia)"),# TOS: "Wolf in the Fold" ("IV" in BSD) 
+    _("Ardana"),               # TOS: "The Cloud Minders" 
+    _("Catulla (Cendo-Prae)"), # TOS: "The Way to Eden" 
+    _("Gideon"),               # TOS: "The Mark of Gideon" 
+    _("Aldebaran III"),        # TOS: "The Deadly Years" 
+    _("Alpha Majoris I"),      # TOS: "Wolf in the Fold" 
+    _("Altair IV"),            # TOS: "Amok Time 
+    _("Ariannus"),             # TOS: "Let That Be Your Last Battlefield" 
+    _("Benecia"),              # TOS: "The Conscience of the King" 
+    _("Beta Niobe I (Sarpeidon)"),     # TOS: "All Our Yesterdays" 
+    _("Alpha Carinae II"),     # TOS: "The Ultimate Computer" 
+    _("Capella IV (Kohath)"),  # TOS: "Friday's Child" (Class G) 
+    _("Daran V"),              # TOS: "For the World is Hollow and I Have Touched the Sky" 
+    _("Deneb II"),             # TOS: "Wolf in the Fold" ("IV" in BSD) 
+    _("Eminiar VII"),          # TOS: "A Taste of Armageddon" 
+    _("Gamma Canaris IV"),     # TOS: "Metamorphosis" 
+    _("Gamma Tranguli VI (Vaalel)"),   # TOS: "The Apple" 
+    _("Ingraham B"),           # TOS: "Operation: Annihilate" 
+    _("Janus IV"),             # TOS: "The Devil in the Dark" 
+    _("Makus III"),            # TOS: "The Galileo Seven" 
+    _("Marcos XII"),           # TOS: "And the Children Shall Lead", 
+    _("Omega IV"),             # TOS: "The Omega Glory" 
+    _("Regulus V"),            # TOS: "Amok Time 
+    _("Deneva"),               # TOS: "Operation -- Annihilate!" 
+    # Worlds from BSD Trek 
+    _("Rigel II"),             # TOS: "Shore Leave" ("III" in BSD) 
+    _("Beta III"),             # TOS: "The Return of the Archons" 
+    _("Triacus"),              # TOS: "And the Children Shall Lead", 
+    _("Exo III"),              # TOS: "What Are Little Girls Made Of?" (Class P) 
+#      # Others 
+#    _("Hansen's Planet"),     # TOS: "The Galileo Seven" 
+#    _("Taurus IV"),           # TOS: "The Galileo Seven" (class G) 
+#    _("Antos IV (Doraphane)"),        # TOS: "Whom Gods Destroy", "Who Mourns for Adonais?" 
+#    _("Izar"),                        # TOS: "Whom Gods Destroy" 
+#    _("Tiburon"),             # TOS: "The Way to Eden" 
+#    _("Merak II"),            # TOS: "The Cloud Minders" 
+#    _("Coridan (Desotriana)"),        # TOS: "Journey to Babel" 
+#    _("Iotia"),               # TOS: "A Piece of the Action" 
+)
+
+device = (
+       _("S. R. Sensors"), \
+       _("L. R. Sensors"), \
+       _("Phasers"), \
+       _("Photon Tubes"), \
+       _("Life Support"), \
+       _("Warp Engines"), \
+       _("Impulse Engines"), \
+       _("Shields"), \
+       _("Subspace Radio"), \
+       _("Shuttle Craft"), \
+       _("Computer"), \
+       _("Navigation System"), \
+       _("Transporter"), \
+       _("Shield Control"), \
+       _("Death Ray"), \
+       _("D. S. Probe"), \
+)
+
+def setup(needprompt):
+    # prepare to play, set up cosmos 
+    w = coord()
+    #  Decide how many of everything
+    if choose(needprompt):
+       return # frozen game
+    # Prepare the Enterprise
+    game.alldone = game.gamewon = False
+    game.ship = IHE
+    game.state.crew = FULLCREW
+    game.energy = game.inenrg = 5000.0
+    game.shield = game.inshld = 2500.0
+    game.shldchg = False
+    game.shldup = False
+    game.inlsr = 4.0
+    game.lsupres = 4.0
+    game.quadrant = randplace(GALSIZE)
+    game.sector = randplace(QUADSIZE)
+    game.torps = game.intorps = 10
+    game.nprobes = int(3.0*random.random() + 2.0)      # Give them 2-4 of these
+    game.warpfac = 5.0
+    game.wfacsq = game.warpfac * game.warpfac
+    for i in range(NDEVICES): 
+       game.damage[i] = 0.0
+    # Set up assorted game parameters
+    game.battle = coord()
+    game.state.date = game.indate = 100.0*int(31.0*random.random()+20.0)
+    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.iscraft = "onship"
+    game.landed = False
+    game.alive = True
+    game.docfac = 0.25
+    for i in range(GALSIZE):
+       for j in range(GALSIZE):
+           quad = game.state.galaxy[i][j]
+           quad.charted = 0
+           quad.planet = None
+           quad.romulans = 0
+           quad.klingons = 0
+           quad.starbase = False
+           quad.supernova = False
+           quad.status = "secure"
+    # Initialize times for extraneous events
+    schedule(FSNOVA, expran(0.5 * game.intime))
+    schedule(FTBEAM, expran(1.5 * (game.intime / game.state.remcom)))
+    schedule(FSNAP, 1.0 + random.random()) # Force an early snapshot
+    schedule(FBATTAK, expran(0.3*game.intime))
+    unschedule(FCDBAS)
+    if game.state.nscrem:
+       schedule(FSCMOVE, 0.2777)
+    else:
+       unschedule(FSCMOVE)
+    unschedule(FSCDBAS)
+    unschedule(FDSPROB)
+    if (game.options & OPTION_WORLDS) and game.skill >= SKILL_GOOD:
+       schedule(FDISTR, expran(1.0 + game.intime))
+    else:
+       unschedule(FDISTR)
+    unschedule(FENSLV)
+    unschedule(FREPRO)
+    # 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 = int(random.random()*9.0 + 1.0)
+           game.instar += k
+           game.state.galaxy[i][j].stars = k
+    # Locate star bases in galaxy
+    for i in range(game.inbase):
+        while True:
+            while True:
+                w = randplace(GALSIZE)
+                if not game.state.galaxy[w.x][w.y].starbase:
+                    break
+           contflag = False
+            # C version: for (j = i-1; j > 0; j--)
+            # so it did them in the opposite order.
+            for j in range(1, i):
+               # Improved placement algorithm to spread out bases
+               distq = w.distance(game.state.baseq[j])
+               if distq < 6.0*(BASEMAX+1-game.inbase) and random.random() < 0.75:
+                   contflag = True
+                   if idebug:
+                       prout("=== Abandoning base #%d at %s" % (i, w))
+                   break
+               elif distq < 6.0 * (BASEMAX+1-game.inbase):
+                   if idebug:
+                       prout("=== Saving base #%d, close to #%d" % (i, j))
+            if not contflag:
+                break
+       game.state.baseq[i] = w
+       game.state.galaxy[w.x][w.y].starbase = True
+       game.state.chart[w.x][w.y].starbase = True
+    # Position ordinary Klingon Battle Cruisers
+    krem = game.inkling
+    klumper = 0.25*game.skill*(9.0-game.length)+1.0
+    if klumper > MAXKLQUAD: 
+       klumper = MAXKLQUAD
+    while True:
+       r = random.random()
+       klump = (1.0 - r*r)*klumper
+       if klump > krem:
+           klump = krem
+       krem -= klump
+        while True:
+            w = randplace(GALSIZE)
+            if not game.state.galaxy[w.x][w.y].supernova and \
+               game.state.galaxy[w.x][w.y].klingons + klump <= MAXKLQUAD:
+                break
+       game.state.galaxy[w.x][w.y].klingons += int(klump)
+        if krem <= 0:
+            break
+    # Position Klingon Commander Ships
+    for i in range(1, game.incom+1):
+        while True:
+            w = randplace(GALSIZE)
+           if (game.state.galaxy[w.x][w.y].klingons or random.random()>=0.75) and \
+                  not game.state.galaxy[w.x][w.y].supernova and \
+                  game.state.galaxy[w.x][w.y].klingons <= MAXKLQUAD-1 and \
+                   not w in game.state.kcmdr[:i]:
+                break
+       game.state.galaxy[w.x][w.y].klingons += 1
+       game.state.kcmdr[i] = w
+    # Locate planets in galaxy
+    for i in range(game.inplan):
+        while True:
+            w = randplace(GALSIZE) 
+            if game.state.galaxy[w.x][w.y].planet == None:
+                break
+        new = planet()
+       new.w = w
+        new.crystals = "absent"
+       if (game.options & OPTION_WORLDS) and i < NINHAB:
+           new.pclass = "M"    # All inhabited planets are class M
+           new.crystals = "absent"
+           new.known = "known"
+            new.name = systnames[i]
+           new.inhabited = True
+       else:
+           new.pclass = ("M", "N", "O")[random.randint(0, 2)]
+            if random.random()*1.5:            # 1 in 3 chance of crystals
+                new.crystals = "present"
+           new.known = "unknown"
+           new.inhabited = False
+       game.state.galaxy[w.x][w.y].planet = new
+        game.state.planets.append(new)
+    # Locate Romulans
+    for i in range(game.state.nromrem):
+       w = randplace(GALSIZE)
+       game.state.galaxy[w.x][w.y].romulans += 1
+    # Locate the Super Commander
+    if game.state.nscrem > 0:
+        while True:
+            w = randplace(GALSIZE)
+            if not game.state.galaxy[w.x][w.y].supernova and game.state.galaxy[w.x][w.y].klingons <= MAXKLQUAD:
+                break
+       game.state.kscmdr = w
+       game.state.galaxy[w.x][w.y].klingons += 1
+    # Place thing (in tournament game, thingx == -1, don't want one!)
+    global thing
+    if thing == None:
+       thing = randplace(GALSIZE)
+    skip(2)
+    game.state.snap = False
+    if game.skill == SKILL_NOVICE:
+       prout(_("It is stardate %d. The Federation is being attacked by") % int(game.state.date))
+       prout(_("a deadly Klingon invasion force. As captain of the United"))
+       prout(_("Starship U.S.S. Enterprise, it is your mission to seek out"))
+       prout(_("and destroy this invasion force of %d battle cruisers.") % ((game.inkling + game.incom + game.inscom)))
+       prout(_("You have an initial allotment of %d stardates to complete") % int(game.intime))
+       prout(_("your mission.  As you proceed you may be given more time."))
+       skip(1)
+       prout(_("You will have %d supporting starbases.") % (game.inbase))
+       proutn(_("Starbase locations-  "))
+    else:
+       prout(_("Stardate %d.") % int(game.state.date))
+       skip(1)
+       prout(_("%d Klingons.") % (game.inkling + game.incom + game.inscom))
+       prout(_("An unknown number of Romulans."))
+       if game.state.nscrem:
+           prout(_("And one (GULP) Super-Commander."))
+       prout(_("%d stardates.") % int(game.intime))
+       proutn(_("%d starbases in ") % game.inbase)
+    for i in range(game.inbase):
+       proutn(`game.state.baseq[i]`)
+       proutn("  ")
+    skip(2)
+    proutn(_("The Enterprise is currently in Quadrant %s") % game.quadrant)
+    proutn(_(" Sector %s") % game.sector)
+    skip(2)
+    prout(_("Good Luck!"))
+    if game.state.nscrem:
+       prout(_("  YOU'LL NEED IT."))
+    waitfor()
+    newqad(False)
+    if game.nenhere - (thing == game.quadrant) - game.ithere:
+       game.shldup = True
+    if game.neutz:     # bad luck to start in a Romulan Neutral Zone
+       attack(False)
+
+def choose(needprompt):
+    # choose your game type
+    global thing
+    while True:
+       game.tourn = 0
+       game.thawed = False
+       game.skill = SKILL_NONE
+       game.length = 0
+       if needprompt: # Can start with command line options 
+           proutn(_("Would you like a regular, tournament, or saved game? "))
+       scan()
+       if len(citem)==0: # Try again
+           continue
+        if isit("tournament"):
+           while scan() == IHEOL:
+               proutn(_("Type in tournament number-"))
+           if aaitem == 0:
+               chew()
+               continue # We don't want a blank entry
+           game.tourn = int(round(aaitem))
+           random.seed(aaitem)
+           break
+        if isit("saved") or isit("frozen"):
+           if thaw():
+               continue
+           chew()
+           if game.passwd == None:
+               continue
+           if not game.alldone:
+               game.thawed = True # No plaque if not finished
+           report()
+           waitfor()
+           return True
+        if isit("regular"):
+           break
+       proutn(_("What is \"%s\"?"), citem)
+       chew()
+    while game.length==0 or game.skill==SKILL_NONE:
+       if scan() == IHALPHA:
+            if isit("short"):
+               game.length = 1
+           elif isit("medium"):
+               game.length = 2
+           elif isit("long"):
+               game.length = 4
+           elif isit("novice"):
+               game.skill = SKILL_NOVICE
+           elif isit("fair"):
+               game.skill = SKILL_FAIR
+           elif isit("good"):
+               game.skill = SKILL_GOOD
+           elif isit("expert"):
+               game.skill = SKILL_EXPERT
+           elif isit("emeritus"):
+               game.skill = SKILL_EMERITUS
+           else:
+               proutn(_("What is \""))
+               proutn(citem)
+               prout("\"?")
+       else:
+           chew()
+           if game.length==0:
+               proutn(_("Would you like a Short, Medium, or Long game? "))
+           elif game.skill == SKILL_NONE:
+               proutn(_("Are you a Novice, Fair, Good, Expert, or Emeritus player? "))
+    # Choose game options -- added by ESR for SST2K
+    if scan() != IHALPHA:
+       chew()
+       proutn(_("Choose your game style (or just press enter): "))
+       scan()
+    if isit("plain"):
+       # Approximates the UT FORTRAN version.
+       game.options &=~ (OPTION_THOLIAN | OPTION_PLANETS | OPTION_THINGY | OPTION_PROBE | OPTION_RAMMING | OPTION_MVBADDY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
+       game.options |= OPTION_PLAIN
+    elif isit("almy"):
+       # Approximates Tom Almy's version.
+       game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
+       game.options |= OPTION_ALMY
+    elif isit("fancy"):
+       pass
+    elif len(citem):
+        proutn(_("What is \"%s\"?") % citem)
+    setpassword()
+    if game.passwd == "debug":
+       idebug = True
+       fputs("=== Debug mode enabled\n", sys.stdout)
+
+    # Use parameters to generate initial values of things
+    game.damfac = 0.5 * game.skill
+    game.state.rembase = random.randint(BASEMIN, BASEMAX)
+    game.inbase = game.state.rembase
+    game.inplan = 0
+    if game.options & OPTION_PLANETS:
+       game.inplan += int((MAXUNINHAB/2) + (MAXUNINHAB/2+1)*random.random())
+    if game.options & OPTION_WORLDS:
+       game.inplan += int(NINHAB)
+    game.state.nromrem = game.inrom = int((2.0+random.random())*game.skill)
+    game.state.nscrem = game.inscom = (game.skill > SKILL_FAIR)
+    game.state.remtime = 7.0 * game.length
+    game.intime = game.state.remtime
+    game.state.remkl = game.inkling = 2.0*game.intime*((game.skill+1 - 2*random.random())*game.skill*0.1+.15)
+    game.incom = int(game.skill + 0.0625*game.inkling*random.random())
+    game.state.remcom = min(10, game.incom)
+    game.incom = game.state.remcom
+    game.state.remres = (game.inkling+4*game.incom)*game.intime
+    game.inresor = game.state.remres
+    if game.inkling > 50:
+        game.state.rembase += 1
+       game.inbase = game.state.rembase
+    return False
+
+def dropin(iquad):
+    # drop a feature on a random dot in the current quadrant 
+    w = coord()
+    while True:
+        w = randplace(QUADSIZE)
+        if game.quad[w.x][w.y] == IHDOT:
+            break
+    game.quad[w.x][w.y] = iquad
+    return w
+
+def newcnd():
+    # update our alert status 
+    game.condition = "green"
+    if game.energy < 1000.0:
+       game.condition = "yellow"
+    if game.state.galaxy[game.quadrant.x][game.quadrant.y].klingons or game.state.galaxy[game.quadrant.x][game.quadrant.y].romulans:
+       game.condition = "red"
+    if not game.alive:
+       game.condition="dead"
+
+def newkling(i):
+    # drop new Klingon into current quadrant 
+    pi = dropin(IHK)
+    game.ks[i] = pi
+    game.kdist[i] = game.kavgd[i] = distance(game.sector, pi)
+    game.kpower[i] = random.random()*150.0 +300.0 +25.0*game.skill
+    return pi
+
+def newqad(shutup):
+    # set up a new state of quadrant, for when we enter or re-enter it 
+    w = coord()
+    game.justin = True
+    game.klhere = 0
+    game.comhere = False
+    game.ishere = False
+    game.irhere = 0
+    game.iplnet = 0
+    game.nenhere = 0
+    game.neutz = False
+    game.inorbit = False
+    game.landed = False
+    game.ientesc = False
+    game.ithere = False
+    global iqengry
+    iqengry = False
+    game.iseenit = False
+    if game.iscate:
+       # Attempt to escape Super-commander, so tbeam back!
+       game.iscate = False
+       game.ientesc = True
+    q = game.state.galaxy[game.quadrant.x][game.quadrant.y]
+    # cope with supernova
+    if q.supernova:
+       return
+    game.klhere = q.klingons
+    game.irhere = q.romulans
+    game.nenhere = game.klhere + game.irhere
+    # Position Starship
+    game.quad[game.sector.x][game.sector.y] = game.ship
+    if q.klingons:
+       w.x = w.y = 0   # quiet a gcc warning 
+       # Position ordinary Klingons
+       for i in range(game.klhere):
+           w = newkling(i)
+       # If we need a commander, promote a Klingon
+       for i in range(game.state.remcom):
+           if game.state.kcmdr[i] == game.quadrant:
+               break
+                       
+       if i <= game.state.remcom:
+           game.quad[w.x][w.y] = IHC
+           game.kpower[game.klhere] = 950.0+400.0*random.random()+50.0*game.skill
+           game.comhere = True
+       # If we need a super-commander, promote a Klingon
+       if same(game.quadrant, game.state.kscmdr):
+           game.quad[game.ks[0].x][game.ks[0].y] = IHS
+           game.kpower[1] = 1175.0 + 400.0*random.random() + 125.0*game.skill
+           game.iscate = (game.state.remkl > 1)
+           game.ishere = True
+    # Put in Romulans if needed
+    for i in range(game.klhere, game.nenhere):
+       w = dropin(IHR)
+       game.ks[i] = w
+       game.kdist[i] = game.kavgd[i] = distance(game.sector, w)
+       game.kpower[i] = random.random()*400.0 + 450.0 + 50.0*game.skill
+    # If quadrant needs a starbase, put it in
+    if q.starbase:
+       game.base = dropin(IHB)
+    # If quadrant needs a planet, put it in
+    if q.planet:
+       game.iplnet = q.planet
+       if not q.planet.inhabited:
+           game.plnet = dropin(IHP)
+       else:
+           game.plnet = dropin(IHW)
+    # Check for condition
+    newcnd()
+    # And finally the stars
+    for i in range(q.stars): 
+       dropin(IHSTAR)
+
+    # Check for RNZ
+    if game.irhere > 0 and game.klhere == 0:
+       game.neutz = True
+       if not damaged(DRADIO):
+           skip(1)
+           prout(_("LT. Uhura- \"Captain, an urgent message."))
+           prout(_("  I'll put it on audio.\"  CLICK"))
+           skip(1)
+           prout(_("INTRUDER! YOU HAVE VIOLATED THE ROMULAN NEUTRAL ZONE."))
+           prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!"))
+    if shutup==0:
+       # Put in THING if needed
+        global thing
+       if thing == game.quadrant:
+           w = dropin(IHQUEST)
+           thing = randplace(GALSIZE)
+           game.nenhere += 1
+           game.ks[game.nenhere] = w
+           game.kdist[game.nenhere] = game.kavgd[game.nenhere] = \
+               distance(game.sector, w)
+           game.kpower[game.nenhere] = random.random()*6000.0 +500.0 +250.0*game.skill
+           if not damaged(DSRSENS):
+               skip(1)
+               prout(_("Mr. Spock- \"Captain, this is most unusual."))
+               prout(_("    Please examine your short-range scan.\""))
+    # Decide if quadrant needs a Tholian; lighten up if skill is low 
+    if game.options & OPTION_THOLIAN:
+       if (game.skill < SKILL_GOOD and random.random() <= 0.02) or \
+           (game.skill == SKILL_GOOD and random.random() <= 0.05) or \
+            (game.skill > SKILL_GOOD and random.random() <= 0.08):
+            while True:
+               game.tholian.x = random.choice((0, QUADSIZE-1))
+               game.tholian.y = random.choice((0, QUADSIZE-1))
+                if game.quad[game.tholian.x][game.tholian.y] == IHDOT:
+                    break
+           game.quad[game.tholian.x][game.tholian.y] = IHT
+           game.ithere = True
+           game.nenhere += 1
+           game.ks[game.nenhere] = game.tholian
+           game.kdist[game.nenhere] = game.kavgd[game.nenhere] = \
+               distance(game.sector, game.tholian)
+           game.kpower[game.nenhere] = random.random()*400.0 +100.0 +25.0*game.skill
+           # Reserve unoccupied corners 
+           if game.quad[0][0]==IHDOT:
+               game.quad[0][0] = 'X'
+           if game.quad[0][QUADSIZE-1]==IHDOT:
+               game.quad[0][QUADSIZE-1] = 'X'
+           if game.quad[QUADSIZE-1][0]==IHDOT:
+               game.quad[QUADSIZE-1][0] = 'X'
+           if game.quad[QUADSIZE-1][QUADSIZE-1]==IHDOT:
+               game.quad[QUADSIZE-1][QUADSIZE-1] = 'X'
+    sortklings()
+    # Put in a few black holes
+    for i in range(1, 3+1):
+       if random.random() > 0.5: 
+           dropin(IHBLANK)
+    # Take out X's in corners if Tholian present
+    if game.ithere:
+       if game.quad[0][0]=='X':
+           game.quad[0][0] = IHDOT
+       if game.quad[0][QUADSIZE-1]=='X':
+           game.quad[0][QUADSIZE-1] = IHDOT
+       if game.quad[QUADSIZE-1][0]=='X':
+           game.quad[QUADSIZE-1][0] = IHDOT
+       if game.quad[QUADSIZE-1][QUADSIZE-1]=='X':
+           game.quad[QUADSIZE-1][QUADSIZE-1] = IHDOT
+
+def sortklings():
+    # sort Klingons by distance from us 
+    # The author liked bubble sort. So we will use it. :-(
+    if game.nenhere-(thing==game.quadrant)-game.ithere < 2:
+       return
+    while True:
+       sw = False
+       for j in range(game.nenhere):
+           if game.kdist[j] > game.kdist[j+1]:
+               sw = True
+               t = game.kdist[j]
+               game.kdist[j] = game.kdist[j+1]
+               game.kdist[j+1] = t
+               t = game.kavgd[j]
+               game.kavgd[j] = game.kavgd[j+1]
+               game.kavgd[j+1] = t
+               k = game.ks[j].x
+               game.ks[j].x = game.ks[j+1].x
+               game.ks[j+1].x = k
+               k = game.ks[j].y
+               game.ks[j].y = game.ks[j+1].y
+               game.ks[j+1].y = k
+               t = game.kpower[j]
+               game.kpower[j] = game.kpower[j+1]
+               game.kpower[j+1] = t
+        if not sw:
+            break
+
+def setpassword():
+    # set the self-destruct password 
+    if game.options & OPTION_PLAIN:
+       while True:
+           chew()
+           proutn(_("Please type in a secret password- "))
+           scan()
+           game.passwd = citem
+           if game.passwd != None:
+               break
+    else:
+        game.passwd = ""
+        for i in range(3):
+           game.passwd += chr(97+int(random.random()*25))
+
+# 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,
+    "SEED":            0,
+    "VISUAL":          0,
+}
+
+def ACCEPT(cmd):       return (not commands[cmd] or (commands[cmd] & game.options))
+
+def listCommands():
+    # generate a list of legal commands 
+    k = 0
+    proutn(_("LEGAL COMMANDS ARE:"))
+    for key in commands:
+       if ACCEPT(key):
+            if k % 5 == 0:
+                skip(1)
+            proutn("%-12s " % key) 
+            k += 1
+    skip(1)
+
+def helpme():
+    # browse on-line help 
+    # Give help on commands 
+    key = scan()
+    while True:
+       if key == IHEOL:
+           setwnd(prompt_window)
+           proutn(_("Help on what command? "))
+           key = scan()
+       setwnd(message_window)
+       if key == IHEOL:
+           return
+        if citem in commands or citem == "ABBREV":
+           break
+       skip(1)
+       listCommands()
+       key = IHEOL
+       chew()
+       skip(1)
+    cmd = citem.upper()
+    try:
+        fp = open(SSTDOC, "r")
+    except IOError:
+        try:
+            fp = open(DOC_NAME, "r")
+        except IOError:
+            prout(_("Spock-  \"Captain, that information is missing from the"))
+            proutn(_("   computer. You need to find "))
+            proutn(DOC_NAME)
+            prout(_(" and put it in the"))
+            proutn(_("   current directory or to "))
+            proutn(SSTDOC)
+            prout(".\"")
+            #
+            # This used to continue: "You need to find SST.DOC and put 
+            # it in the current directory."
+            # 
+            return
+    while True:
+        linebuf = fp.readline()
+       if linebuf == '':
+           prout(_("Spock- \"Captain, there is no information on that command.\""))
+           fp.close()
+           return
+       if linebuf[0] == '%' and linebuf[1] == '%' and linebuf[2] == ' ':
+            linebuf = linebuf[3:].strip()
+            if cmd == linebuf:
+               break
+    skip(1)
+    prout(_("Spock- \"Captain, I've found the following information:\""))
+    skip(1)
+    while linebuf in fp:
+        if "******" in linebuf:
+           break
+       proutn(linebuf)
+    fp.close()
+
+def makemoves():
+    # command-interpretation loop 
+    v = 0
+    clrscr()
+    setwnd(message_window)
+    while True:        # command loop 
+       drawmaps(1)
+        while True:    # get a command 
+           hitme = False
+           game.justin = False
+           game.optime = 0.0
+           chew()
+           setwnd(prompt_window)
+           clrscr()
+           proutn("COMMAND> ")
+           if scan() == IHEOL:
+               if game.options & OPTION_CURSES:
+                   makechart()
+               continue
+           game.ididit = False
+           clrscr()
+           setwnd(message_window)
+           clrscr()
+            candidates = filter(lambda x: x.startswith(citem.upper()),
+                                commands)
+            if len(candidates) == 1:
+                cmd = candidates[0]
+                break
+            elif candidates and not (game.options & OPTION_PLAIN):
+                prout("Commands with that prefix: " + " ".join(candidates))
+            else:
+                listCommands()
+                continue
+       if cmd == "SRSCAN":             # srscan
+           srscan()
+       elif cmd == "STATUS":           # status
+           status()
+       elif cmd == "REQUEST":          # status request 
+           request()
+       elif cmd == "LRSCAN":           # long range scan
+           lrscan()
+       elif cmd == "PHASERS":          # phasers
+           phasers()
+           if game.ididit:
+               hitme = True
+       elif cmd == "TORPEDO":          # photon torpedos
+           photon()
+           if game.ididit:
+               hitme = True
+       elif cmd == "MOVE":             # move under warp
+           warp(False)
+       elif cmd == "SHIELDS":          # shields
+           doshield(False)
+           if game.ididit:
+               hitme = True
+               game.shldchg = False
+       elif cmd == "DOCK":             # dock at starbase
+           dock(True)
+           if game.ididit:
+               attack(False)           
+       elif cmd == "DAMAGES":          # damage reports
+           damagereport()
+       elif cmd == "CHART":            # chart
+           makechart()
+       elif cmd == "IMPULSE":          # impulse
+           impulse()
+       elif cmd == "REST":             # rest
+           os.wait()
+           if game.ididit:
+               hitme = True
+       elif cmd == "WARP":             # warp
+           setwarp()
+       elif cmd == "SCORE":            # score
+           score()
+       elif cmd == "SENSORS":          # sensors
+           sensor()
+       elif cmd == "ORBIT":            # orbit
+           orbit()
+           if game.ididit:
+               hitme = True
+       elif cmd == "TRANSPORT":                # transport "beam"
+           beam()
+       elif cmd == "MINE":             # mine
+           mine()
+           if game.ididit:
+               hitme = True
+       elif cmd == "CRYSTALS":         # crystals
+           usecrystals()
+           if game.ididit:
+               hitme = True
+       elif cmd == "SHUTTLE":          # shuttle
+           shuttle()
+           if game.ididit:
+               hitme = True
+       elif cmd == "PLANETS":          # Planet list
+           survey()
+       elif cmd == "REPORT":           # Game Report 
+           report()
+       elif cmd == "COMPUTER":         # use COMPUTER!
+           eta()
+       elif cmd == "COMMANDS":
+           listCommands()
+       elif cmd == "EMEXIT":           # Emergency exit
+           clrscr()                    # Hide screen
+           freeze(True)                # forced save
+           os.exit(1)                  # And quick exit
+       elif cmd == "PROBE":
+           probe()                     # Launch probe
+           if game.ididit:
+               hitme = True
+       elif cmd == "ABANDON":          # Abandon Ship
+           abandon()
+       elif cmd == "DESTRUCT":         # Self Destruct
+           selfdestruct()
+       elif cmd == "SAVE":             # Save Game
+           freeze(False)
+           clrscr()
+           if game.skill > SKILL_GOOD:
+               prout(_("WARNING--Saved games produce no plaques!"))
+       elif cmd == "DEATHRAY":         # Try a desparation measure
+           deathray()
+           if game.ididit:
+               hitme = True
+       elif cmd == "DEBUGCMD":         # What do we want for debug???
+           debugme()
+       elif cmd == "MAYDAY":           # Call for help
+           mayday()
+           if game.ididit:
+               hitme = True
+       elif cmd == "QUIT":
+           game.alldone = True         # quit the game
+       elif cmd == "HELP":
+           helpme()                    # get help
+       elif cmd == "SEED":             # set random-number seed
+           key = scan()
+           if key == IHREAL:
+               seed = int(round(aaitem))
+#ifdef BSD_BUG_FOR_BUG
+#      elif cmd == "VISUAL":
+#          visual()                    # perform visual scan
+#endif
+       while True:
+           if game.alldone:
+               break           # Game has ended
+           if game.optime != 0.0:
+               events()
+               if game.alldone:
+                   break       # Events did us in
+           if game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova:
+               atover(False)
+               continue
+           if hitme and not game.justin:
+               attack(True)
+               if game.alldone:
+                   break
+               if game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova:
+                   atover(False)
+                   hitme = True
+                   continue
+           break
+       if game.alldone:
+           break
+    if idebug:
+       prout("=== Ending")
+
+def cramen(cmd):
+    # return an enemy 
+    if   cmd == IHR: s = _("Romulan")
+    elif cmd == IHK: s = _("Klingon")
+    elif cmd == IHC: s = _("Commander")
+    elif cmd == IHS: s = _("Super-commander")
+    elif cmd == IHSTAR: s = _("Star")
+    elif cmd == IHP: s = _("Planet")
+    elif cmd == IHB: s = _("Starbase")
+    elif cmd == IHBLANK: s = _("Black hole")
+    elif cmd == IHT: s = _("Tholian")
+    elif cmd == IHWEB: s = _("Tholian web")
+    elif cmd == IHQUEST: s = _("Stranger")
+    elif cmd == IHW: s = _("Inhabited World")
+    else: s = "Unknown??"
+    proutn(s)
+
+def crmena(stars, enemy, loctype, w):
+    # print an enemy and his location 
+    if stars:
+       proutn("***")
+    cramen(enemy)
+    proutn(_(" at "))
+    if loctype == "quadrant":
+       buf = _("Quadrant ")
+    elif loctype == "sector":
+       buf = _("Sector ")
+    proutn(buf + `w`)
+
+def crmshp():
+    # print our ship name 
+    if game.ship == IHE:
+        s = _("Enterprise")
+    elif game.ship == IHF:
+        s = _("Faerie Queene")
+    else:
+        s = "Ship???"
+    proutn(s)
+
+def stars():
+    # print a line of stars 
+    prouts("******************************************************")
+    skip(1)
+
+def expran(avrage):
+    return -avrage*math.log(1e-7 + random.random())
+
+def randplace(size):
+    # choose a random location  
+    w = coord()
+    w.x = random.randint(0, size-1) 
+    w.y = random.randint(0, size-1)
+    return w
+
+def chew():
+    # Demand input for next scan
+    global inqueue
+    inqueue = None
+
+def chew2():
+    # return IHEOL next time 
+    global inqueue
+    inqueue = []
+
+def scan():
+    # Get a token from the user
+    global inqueue, line, citem, aaitem
+    aaitem = 0.0
+    citem = ''
+
+    # Read a line if nothing here
+    if inqueue == None:
+       line = cgetline()
+       if curwnd==prompt_window:
+           clrscr()
+           setwnd(message_window)
+           clrscr()
+        # Skip leading white space
+        line = line.lstrip()
+        if line:
+            inqueue = line.split()
+        else:
+            inqueue = []
+            return IHEOL
+    elif not inqueue:
+        return IHEOL
+    # From here on in it's all looking at the queue
+    citem = inqueue.pop(0)
+    if citem == IHEOL:
+        return IHEOL
+    try:
+        aaitem = float(citem)
+        return IHREAL
+    except ValueError:
+        pass
+    # Treat as alpha
+    citem = citem.lower()
+    return IHALPHA
+
+def ja():
+    # yes-or-no confirmation 
+    chew()
+    while True:
+       scan()
+       chew()
+       if citem == 'y':
+           return True
+       if citem == 'n':
+           return False
+       proutn(_("Please answer with \"y\" or \"n\": "))
+
+def huh():
+    # complain about unparseable input 
+    chew()
+    skip(1)
+    prout(_("Beg your pardon, Captain?"))
+
+def isit(s):
+    # compares s to citem and returns true if it matches to the length of s
+    return s.startswith(citem)
+
+def debugme():
+    # access to the internals for debugging 
+    proutn("Reset levels? ")
+    if ja() == True:
+       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:
+       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:
+           prout("Debug output ON")        
+       else:
+           prout("Debug output OFF")
+    proutn("Cause selective damage? ")
+    if ja() == True:
+       for i in range(NDEVICES):
+           proutn("Kill ")
+           proutn(device[i])
+           proutn("? ")
+           chew()
+           key = scan()
+            if key == IHALPHA and isit("y"):
+               game.damage[i] = 10.0
+    proutn("Examine/change events? ")
+    if ja() == True:
+       ev = event()
+       w = coord()
+        legends = {
+            FSNOVA:  "Supernova       ",
+            FTBEAM:  "T Beam          ",
+            FSNAP:   "Snapshot        ",
+            FBATTAK: "Base Attack     ",
+            FCDBAS:  "Base Destroy    ",
+            FSCMOVE: "SC Move         ",
+            FSCDBAS: "SC Base Destroy ",
+            FDSPROB: "Probe Move      ",
+            FDISTR:  "Distress Call   ",
+            FENSLV:  "Enslavement     ",
+            FREPRO:  "Klingon Build   ",
+        }
+       for i in range(1, NEVENTS):
+            proutn(legends[i])
+           if is_scheduled(i):
+               proutn("%.2f" % (scheduled(i)-game.state.date))
+               if i == FENSLV or i == FREPRO:
+                   ev = findevent(i)
+                   proutn(" in %s" % ev.quadrant)
+           else:
+               proutn("never")
+           proutn("? ")
+           chew()
+           key = scan()
+           if key == 'n':
+               unschedule(i)
+               chew()
+           elif key == IHREAL:
+               ev = schedule(i, aaitem)
+               if i == FENSLV or i == FREPRO:
+                   chew()
+                   proutn("In quadrant- ")
+                   key = scan()
+                   # IHEOL says to leave coordinates as they are 
+                   if key != IHEOL:
+                       if key != IHREAL:
+                           prout("Event %d canceled, no x coordinate." % (i))
+                           unschedule(i)
+                           continue
+                       w.x = int(round(aaitem))
+                       key = scan()
+                       if key != IHREAL:
+                           prout("Event %d canceled, no y coordinate." % (i))
+                           unschedule(i)
+                           continue
+                       w.y = int(round(aaitem))
+                       ev.quadrant = w
+       chew()
+    proutn("Induce supernova here? ")
+    if ja() == True:
+       game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova = True
+       atover(True)
+
+if __name__ == '__main__':
+    global line, thing, game, idebug, iqengry
+    game = citem = aaitem = inqueue = None
+    line = ''
+    thing = coord()
+    iqengry = False
+    game = gamestate()
+    idebug = 0
+    game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_SHOWME | OPTION_PLAIN | OPTION_ALMY)
+    # Disable curses mode until the game logic is working.
+    #    if os.getenv("TERM"):
+    #  game.options |= OPTION_CURSES | OPTION_SHOWME
+    #    else:
+    game.options |= OPTION_TTY
+    seed = time.time()
+    (options, arguments) = getopt.getopt(sys.argv[1:], "r:tx")
+    for (switch, val) in options:
+        if switch == '-r':
+            try:
+                replayfp = open(optarg, "r")
+            except IOError:
+               sys.stderr.write("sst: can't open replay file %s\n" % optarg)
+               os.exit(1)
+            line = replayfp.readline().strip()
+            try:
+                (key, seed) = line.split()
+                seed = int(seed)
+            except ValueError:
+               sys.stderr.write("sst: replay file %s is ill-formed\n"%optarg)
+               os.exit(1)
+           game.options |= OPTION_TTY
+           game.options &=~ OPTION_CURSES
+       elif switch == '-t':
+           game.options |= OPTION_TTY
+           game.options &=~ OPTION_CURSES
+       elif switch == '-x':
+           idebug = True
+       else:
+           sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n")
+           os.exit(0)
+    # where to save the input in case of bugs
+    try:
+        logfp = open("/usr/tmp/sst-input.log", "w")
+    except IOError:
+        sys.stderr.write("sst: warning, can't open logfile\n")
+    if logfp:
+       #setlinebuf(logfp)
+       logfp.write("seed %d\n" % (seed))
+    random.seed(seed)
+    iostart()
+    if arguments:
+        inqueue = arguments
+    else:
+        inqueue = None
+    while True: # Play a game 
+       setwnd(fullscreen_window)
+       clrscr()
+       prelim()
+       setup(needprompt=not inqueue)
+       if game.alldone:
+           score()
+           game.alldone = False
+       else:
+           makemoves()
+       skip(1)
+       stars()
+       skip(1)
+       if game.tourn and game.alldone:
+           proutn(_("Do you want your score recorded?"))
+           if ja() == True:
+               chew2()
+               freeze(False)
+       proutn(_("Do you want to play again? "))
+       if not ja():
+           break
+    skip(1)
+    prout(_("May the Great Bird of the Galaxy roost upon your home planet."))
+    raise SysExit, 0