Drop out the BSD visual-scan code.
[super-star-trek.git] / src / sst.py
index 9093a8085282e65960fa9f7021d1be0ef16e5f6e..e7a54919341fe3d348ff7492a97a2015380e2e94 100644 (file)
@@ -173,7 +173,7 @@ 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, cPickle, random, getopt
+import os,sys,math,curses,time,atexit,readline,cPickle,random,getopt,copy
 
 SSTDOC         = "/usr/share/doc/sst/sst.doc"
 DOC_NAME       = "sst.doc"
@@ -244,7 +244,16 @@ class coord:
     def distance(self, other):
         return math.sqrt((self.x - other.x)**2 + (self.y - other.y)**2)
     def sgn(self):
-        return coord(self.x / abs(x), self.y / abs(y));
+        s = coord()
+        if self.x == 0:
+            s.x = 0
+        else:
+            s.x = self.x / abs(self.x)
+        if self.y == 0:
+            s.y = 0
+        else:
+            s.y = self.y / abs(self.y)
+        return s
     def __hash__(self):
         return hash((x, y))
     def __str__(self):
@@ -423,7 +432,6 @@ class gamestate:
         self.ishere = False    # super-commander in quadrant
         self.iscate = False    # super commander is here
         self.ientesc = False   # attempted escape from supercommander
-        self.ithere = False    # Tholian is here 
         self.resting = False   # rest time
         self.icraft = False    # Kirk in Galileo
         self.landed = False    # party on planet (true), on ship (false)
@@ -1021,9 +1029,8 @@ def supercommander():
 
 def movetholian():
     # move the Tholian 
-    if not game.ithere or game.justin:
+    if not game.tholian or game.justin:
        return
-
     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:
@@ -1036,12 +1043,10 @@ def movetholian():
        # something is wrong! 
        game.ithere = False
        return
-
     # do nothing if we are blocked 
     if game.quad[idx][idy]!= IHDOT and game.quad[idx][idy]!= IHWEB:
        return
     game.quad[game.tholian.x][game.tholian.y] = IHWEB
-
     if game.tholian.x != idx:
        # move in x axis 
        im = math.fabs(idx - game.tholian.x)*1.0/(idx - game.tholian.x)
@@ -1074,7 +1079,7 @@ def movetholian():
     dropin(IHBLANK)
     crmena(True, IHT, "sector", game.tholian)
     prout(_(" completes web."))
-    game.ithere = False
+    game.tholian = None
     game.nenhere -= 1
     return
 
@@ -1260,7 +1265,7 @@ def ram(ibumpd, ienm, w):
     proutn("***")
     crmshp()
     prout(_(" heavily damaged."))
-    icas = 10.0+20.0*random.random()
+    icas = 10 + random.randrange(20)
     prout(_("***Sickbay reports %d casualties"), icas)
     game.casual += icas
     game.state.crew -= icas
@@ -1486,7 +1491,7 @@ def torpedo(course, r, incoming, i, n):
            h1 = math.fabs(h1)
            if h1 >= 600:
                game.quad[w.x][w.y] = IHDOT
-               game.ithere = False
+               game.tholian = None
                deadkl(w, iquad, w)
                return None
            skip(1)
@@ -1496,7 +1501,7 @@ def torpedo(course, r, incoming, i, n):
                return None
            prout(_(" disappears."))
            game.quad[w.x][w.y] = IHWEB
-           game.ithere = False
+           game.tholian = None
            game.nenhere -= 1
            dropin(IHBLANK)
            return None
@@ -1569,7 +1574,7 @@ def attack(torps_ok):
     if idebug:
        prout("=== ATTACK!")
     # Tholian gets to move before attacking 
-    if game.ithere:
+    if game.tholian:
        movetholian()
     # if you have just entered the RNZ, you'll get a warning 
     if game.neutz: # The one chance not to be attacked 
@@ -1721,7 +1726,7 @@ def deadkl(w, type, mv):
        game.state.nromrem -= 1
     elif type == IHT:
        # Killed a Tholian 
-       game.ithere = False
+       game.tholian = None
     elif type == IHQUEST:
        # Killed a Thingy
         global iqengry
@@ -1946,7 +1951,7 @@ def checkshctrl(rpow):
 
 def hittem(hits):
     # register a phaser hit on Klingons and Romulans 
-    nenhr2=game.nenhere; kk=1
+    nenhr2 = game.nenhere; kk=1
     w = coord()
     skip(1)
     for k in range(nenhr2):
@@ -1987,7 +1992,7 @@ def hittem(hits):
        else: # decide whether or not to emasculate klingon 
            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(_("***Mr. Spock-  \"Captain, the vessel at Sector %s") % w)
                prout(_("   has just lost its firepower.\""))
                game.kpower[kk] = -kpow
         kk += 1
@@ -1995,9 +2000,9 @@ def hittem(hits):
 
 def phasers():
     # fire phasers 
-    hits = []; rpow=0
+    hits = []
     kz = 0; k = 1; irec=0 # Cheating inhibitor 
-    ifast = False; no = False; itarg = True; msgflag = True
+    ifast = False; no = False; itarg = True; msgflag = True; rpow=0
     automode = "NOTSET"
     key=0
     skip(1)
@@ -2066,7 +2071,8 @@ def phasers():
            elif not itarg:
                automode = "FORCEMAN"
            else: 
-               proutn(_("Manual or automatic? "))                      
+               proutn(_("Manual or automatic? "))
+                chew()
     avail = game.energy
     if ifast:
         avail -= 200.0
@@ -2114,7 +2120,7 @@ def phasers():
            extra = 0.0
            powrem = rpow
            for i in range(game.nenhere):
-               hits[i] = 0.0
+               hits.append(0.0)
                if powrem <= 0:
                    continue
                hits[i] = math.fabs(game.kpower[i])/(PHASEFAC*math.pow(0.90,game.kdist[i]))
@@ -2131,7 +2137,7 @@ def phasers():
            hittem(hits)
            game.ididit = True
        if extra > 0 and not game.alldone:
-           if game.ithere:
+           if game.tholian:
                proutn(_("*** Tholian web absorbs "))
                if game.nenhere>0:
                    proutn(_("excess "))
@@ -2288,9 +2294,8 @@ def events():
     w = coord(); hold = coord()
     ev = event(); ev2 = event()
 
-    def tractorbeam():
+    def tractorbeam(yank):
         # tractor beaming cases merge here 
-        yank = math.sqrt(yank)
         announce()
         game.optime = (10.0/(7.5*7.5))*yank # 7.5 is yank rate (warp 7.5) 
         skip(1)
@@ -2314,7 +2319,7 @@ def events():
                 game.iscraft = "removed"
             else:
                 prout(_("Galileo, left on the planet surface, is well hidden."))
-        if evcode==0:
+        if evcode == FSPY:
             game.quadrant = game.state.kscmdr
         else:
             game.quadrant = game.state.kcmdr[i]
@@ -2327,8 +2332,8 @@ def events():
             game.resting = False
         if not game.shldup:
             if not damaged(DSHIELD) and game.shield > 0:
-                doshield(True) # raise shields 
-                game.shldchg=False
+                doshield(shraise=True) # raise shields 
+                game.shldchg = False
             else:
                 prout(_("(Shields not currently useable.)"))
         newqad(False)
@@ -2469,27 +2474,25 @@ def events():
                 (game.energy < 2500 or damaged(DPHASER)) and \
                  (game.torps < 5 or damaged(DPHOTON))):
                # Tractor-beam her! 
-               istract = True
-               yank = distance(game.state.kscmdr, game.quadrant)
-                ictbeam = True
-                tractorbeam()
+               istract = ictbeam = True
+                tractorbeam(distance(game.state.kscmdr, game.quadrant))
            else:
                return
        elif evcode == FTBEAM: # Tractor beam 
             if game.state.remcom == 0:
                 unschedule(FTBEAM)
                 continue
-            i = random.random()*game.state.remcom+1.0
-            yank = square(game.state.kcmdr[i].x-game.quadrant.x) + square(game.state.kcmdr[i].y-game.quadrant.y)
+            i = random.randrange(game.state.remcom)
+            yank = distance(game.state.kcmdr[i], game.quadrant)
             if istract or game.condition == "docked" or yank == 0:
                 # Drats! Have to reschedule 
                 schedule(FTBEAM, 
                          game.optime + expran(1.5*game.intime/game.state.remcom))
                 continue
             ictbeam = True
-            tractorbeam()
+            tractorbeam(yank)
        elif evcode == FSNAP: # Snapshot of the universe (for time warp) 
-           game.snapsht = game.state
+           game.snapsht = copy.deepcopy(game.state)
            game.state.snap = True
            schedule(FSNAP, expran(0.5 * game.intime))
        elif evcode == FBATTAK: # Commander attacks starbase 
@@ -2610,7 +2613,7 @@ def events():
                q = game.state.galaxy[w.x][w.y]
                 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):
+                     q.supernova or q.status!="secure" or q.klingons<=0):
                     break
             else:
                # can't seem to find one; ignore this call 
@@ -2902,7 +2905,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
        
@@ -2922,7 +2925,7 @@ def supernova(induced, w=None):
                stars += game.state.galaxy[nq.x][nq.y].stars
        if stars == 0:
            return # nothing to supernova exists 
-       num = random.random()*stars + 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
@@ -2943,7 +2946,7 @@ def supernova(induced, w=None):
     else:
        ns = coord()
        # we are in the quadrant! 
-       num = random.random()* game.state.galaxy[nq.x][nq.y].stars + 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:
@@ -3086,7 +3089,13 @@ def kaboom():
                                
 def killrate():
     "Compute our rate of kils over time."
-    return ((game.inkling + game.incom + game.inscom) - (game.state.remkl + game.state.remcom + game.state.nscrem))/(game.state.date-game.indate)
+    elapsed = game.state.date - game.indate
+    if elapsed == 0:   # Avoid divide-by-zero error if calculated on turn 0
+        return 0
+    else:
+        starting = (game.inkling + game.incom + game.inscom)
+        remaining = (game.state.remkl + game.state.remcom + game.state.nscrem)
+        return (starting - remaining)/elapsed
 
 def badpoints():
     "Compute demerits."
@@ -3487,7 +3496,7 @@ def iostart():
     #textdomain(PACKAGE)
     if atexit.register(outro):
        sys.stderr.write("Unable to register outro(), exiting...\n")
-       os.exit(1)
+       raise SysExit,1
     if not (game.options & OPTION_CURSES):
        ln_env = os.getenv("LINES")
         if ln_env:
@@ -3595,13 +3604,13 @@ 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():
     "Get a line of input."
@@ -3611,10 +3620,13 @@ def cgetline():
     else:
        if replayfp and not replayfp.closed:
            line = replayfp.readline()
+            if line == '':
+                prout("*** Replay finished")
+                replayfp.close()
        else:
-           line = raw_input()
+           line = raw_input("COMMAND> ")
     if logfp:
-       logfp.write(line)
+       logfp.write(line + "\n")
     return line
 
 def setwnd(wnd):
@@ -3721,7 +3733,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])
@@ -3757,18 +3769,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)
@@ -3806,7 +3818,7 @@ 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(game.nenhere):
@@ -3821,12 +3833,10 @@ def imove(novapush):
         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)
@@ -3834,10 +3844,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
@@ -3848,14 +3856,13 @@ 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 
@@ -3874,31 +3881,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:
@@ -3912,10 +3918,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
@@ -3928,7 +3934,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, IHC, IHS, IHR, IHQUEST):
                    game.sector = w
                    ram(False, iquad, game.sector)
                    final = game.sector
@@ -4018,23 +4024,19 @@ def dock(verbose):
 # 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:
@@ -4051,7 +4053,6 @@ def getcd(isprobe, akey):
            akey = -1
        else: 
            key = scan()
-
        if key == IHEOL:
            proutn(_("Manual or automatic- "))
            iprompt = True
@@ -4068,7 +4069,7 @@ def getcd(isprobe, akey):
            else:
                huh()
                chew()
-               return
+               return False
        else: # numeric 
            if isprobe:
                prout(_("(Manual navigation assumed.)"))
@@ -4076,7 +4077,6 @@ def getcd(isprobe, akey):
                prout(_("(Manual movement assumed.)"))
            navmode = "manual"
            break
-
     if navmode == "automatic":
        while key == IHEOL:
            if isprobe:
@@ -4086,52 +4086,53 @@ def getcd(isprobe, akey):
            chew()
            iprompt = True
            key = scan()
-
        if key != IHREAL:
            huh()
-           return
-       xi = int(aaitem-0.05)
+           return False
+       xi = int(round(aaitem))-1
        key = scan()
        if key != IHREAL:
            huh()
-           return
-       xj = int(aaitem-0.5)
+           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- "))
@@ -4141,26 +4142,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 
@@ -4171,8 +4173,7 @@ 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:
@@ -4199,7 +4200,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
@@ -4227,8 +4228,7 @@ def warp(timewarp):
            prout(_("  is repaired, I can only give you warp 4.\""))
            return
                # Read in course and distance 
-       getcd(False, 0)
-       if game.direc == -1.0:
+        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)
@@ -4307,7 +4307,7 @@ def warp(timewarp):
                    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)
@@ -4543,8 +4543,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)
@@ -4864,13 +4863,14 @@ def sensor():
        if game.iplnet.known=="shuttle_down": 
            prout(_("         Sensors show Galileo still on surface."))
        proutn(_("         Readings indicate"))
-       if game.iplnet.crystals != present:
+       if game.iplnet.crystals != "present":
            proutn(_(" no"))
        prout(_(" dilithium crystals present.\""))
        if game.iplnet.known == "unknown":
            game.iplnet.known = "known"
     elif game.iplnet.inhabited:
-        prout(_("Spock-  \"The inhabited planet %s is located at Sector %s, Captain.\"") % (game.iplnet.name, game.plnet))
+        prout(_("Spock-  \"The inhabited planet %s ") % game.iplnet.name)
+        prout(_("        is located at Sector %s, Captain.\"") % game.plnet)
 
 def beam():
     # use the transporter 
@@ -4986,7 +4986,7 @@ def mine():
        skip(1)
        prout(_("there's no reason to mine more at this time."))
        return
-    game.optime = (0.1+0.2*random.random())*game.iplnet.pclass
+    game.optime = (0.1+0.2*random.random())*(ord(game.iplnet.pclass)-ord("M"))
     if consumeTime():
        return
     prout(_("Mining operation complete."))
@@ -5144,7 +5144,6 @@ def shuttle():
 def deathray():
     # use the big zapper 
     r = random.random()
-       
     game.ididit = False
     skip(1)
     chew()
@@ -5403,7 +5402,7 @@ def chart():
        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(GALSIZE):
-       proutn("%d |" % (i))
+       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("<")
@@ -5532,7 +5531,7 @@ def srscan():
     if game.condition != "docked":
        newcnd()
     for i in range(QUADSIZE):
-       proutn("%2d  " % (i))
+       proutn("%2d  " % (i+1))
        for j in range(QUADSIZE):
            sectscan(goodScan, i, j)
        skip(1)
@@ -5661,69 +5660,6 @@ def eta():
            return
                        
 
-#ifdef BSD_BUG_FOR_BUG
-# A visual scan is made in a particular direction of three sectors
-# in the general direction specified.  This takes time, and
-# Klingons can attack you, so it should be done only when sensors
-# are out.  Code swiped from BSD-Trek.  Not presently used, as we
-# automatically display all adjacent sectors on the short-range
-# scan even when short-range sensors are out.
-
-# This struct[] has the delta x, delta y for particular directions
-
-visdelta = (
-    (-1,-1),
-    (-1, 0),
-    (-1, 1),
-    (0,         1),
-    (1,         1),
-    (1,         0),
-    (1,        -1),
-    (0,        -1),
-    (-1,-1),
-    (-1, 0),
-    (-1, 1),
-)
-
-def visual():
-    v = coord()
-    if scan() != IHREAL:
-       chew()
-       proutn(_("Direction? "))
-       if scan()!=IHREAL:
-           huh()
-           return
-    if aaitem < 0.0 or aaitem > 360.0:
-       return
-    co = (aaitem + 22) / 45
-    v = visdelta[co]
-    ix = game.sector.x + v.x
-    iy = game.sector.y + v.y
-    if ix < 0 or ix >= QUADSIZE or iy < 0 or iy >= QUADSIZE:
-       co = '?'
-    else:
-       co = game.quad[ix][iy]
-    printf("%d,%d %c " % (ix+1, iy+1, co))
-    v += 1
-    ix = game.sector.x + v.x
-    iy = game.sector.y + v.y
-    if ix < 0 or ix >= QUADSIZE or iy < 0 or iy >= QUADSIZE:
-       co = '?'
-    else:
-       co = game.quad[ix][iy]
-    printf("%c " % (co))
-    v += 1
-    ix = game.sector.x + v.x
-    iy = game.sector.y + v.y
-    if ix < 0 or ix >= QUADSIZE or iy < 0 or iy >= QUADSIZE:
-       co = '?'
-    else:
-       co = game.quad[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():
@@ -5731,10 +5667,9 @@ def prelim():
     skip(2)
     prout(_("-SUPER- STAR TREK"))
     skip(1)
-#ifdef __HISTORICAL__
+# From the FORTRAN original
 #    prout(_("Latest update-21 Sept 78"))
 #    skip(1)
-#endif __HISTORICAL__ 
 
 def freeze(boss):
     # save game 
@@ -6052,7 +5987,7 @@ def setup(needprompt):
        prout(_("  YOU'LL NEED IT."))
     waitfor()
     newqad(False)
-    if game.nenhere - (thing == game.quadrant) - game.ithere:
+    if game.nenhere - (thing == game.quadrant) - (game.tholian != None):
        game.shldup = True
     if game.neutz:     # bad luck to start in a Romulan Neutral Zone
        attack(False)
@@ -6076,7 +6011,7 @@ def choose(needprompt):
            if aaitem == 0:
                chew()
                continue # We don't want a blank entry
-           game.tourn = int(aaitem)
+           game.tourn = int(round(aaitem))
            random.seed(aaitem)
            break
         if isit("saved") or isit("frozen"):
@@ -6210,7 +6145,6 @@ def newqad(shutup):
     game.inorbit = False
     game.landed = False
     game.ientesc = False
-    game.ithere = False
     global iqengry
     iqengry = False
     game.iseenit = False
@@ -6242,7 +6176,7 @@ def newqad(shutup):
            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):
+       if 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)
@@ -6299,13 +6233,13 @@ def newqad(shutup):
        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):
+            game.tholian = coord()
             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] = \
@@ -6326,7 +6260,7 @@ def newqad(shutup):
        if random.random() > 0.5: 
            dropin(IHBLANK)
     # Take out X's in corners if Tholian present
-    if game.ithere:
+    if game.tholian:
        if game.quad[0][0]=='X':
            game.quad[0][0] = IHDOT
        if game.quad[0][QUADSIZE-1]=='X':
@@ -6339,7 +6273,7 @@ def newqad(shutup):
 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:
+    if game.nenhere-(thing==game.quadrant)-(game.tholian!=None) < 2:
        return
     while True:
        sw = False
@@ -6510,7 +6444,6 @@ def makemoves():
            chew()
            setwnd(prompt_window)
            clrscr()
-           proutn("COMMAND> ")
            if scan() == IHEOL:
                if game.options & OPTION_CURSES:
                    makechart()
@@ -6548,7 +6481,7 @@ def makemoves():
        elif cmd == "MOVE":             # move under warp
            warp(False)
        elif cmd == "SHIELDS":          # shields
-           doshield(False)
+           doshield(shraise=False)
            if game.ididit:
                hitme = True
                game.shldchg = False
@@ -6601,7 +6534,7 @@ def makemoves():
        elif cmd == "EMEXIT":           # Emergency exit
            clrscr()                    # Hide screen
            freeze(True)                # forced save
-           os.exit(1)                  # And quick exit
+           raise SysExit,1                     # And quick exit
        elif cmd == "PROBE":
            probe()                     # Launch probe
            if game.ididit:
@@ -6629,14 +6562,6 @@ def makemoves():
            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(aaitem)
-#ifdef BSD_BUG_FOR_BUG
-#      elif cmd == "VISUAL":
-#          visual()                    # perform visual scan
-#endif
        while True:
            if game.alldone:
                break           # Game has ended
@@ -6684,6 +6609,7 @@ def crmena(stars, enemy, loctype, w):
        proutn("***")
     cramen(enemy)
     proutn(_(" at "))
+    buf = ""
     if loctype == "quadrant":
        buf = _("Quadrant ")
     elif loctype == "sector":
@@ -6727,7 +6653,7 @@ def chew2():
 
 def scan():
     # Get a token from the user
-    global inqueue, line, citem
+    global inqueue, line, citem, aaitem
     aaitem = 0.0
     citem = ''
 
@@ -6857,13 +6783,13 @@ def debugme():
                            prout("Event %d canceled, no x coordinate." % (i))
                            unschedule(i)
                            continue
-                       w.x = int(aaitem)
+                       w.x = int(round(aaitem))
                        key = scan()
                        if key != IHREAL:
                            prout("Event %d canceled, no y coordinate." % (i))
                            unschedule(i)
                            continue
-                       w.y = int(aaitem)
+                       w.y = int(round(aaitem))
                        ev.quadrant = w
        chew()
     proutn("Induce supernova here? ")
@@ -6890,16 +6816,17 @@ if __name__ == '__main__':
     for (switch, val) in options:
         if switch == '-r':
             try:
-                replayfp = open(optarg, "r")
+                replayfp = open(val, "r")
             except IOError:
-               sys.stderr.write("sst: can't open replay file %s\n" % optarg)
-               os.exit(1)
+               sys.stderr.write("sst: can't open replay file %s\n" % val)
+               raise SysExit, 1
             line = replayfp.readline().strip()
             try:
                 (key, seed) = line.split()
                 seed = int(seed)
+                sys.stderr.write("sst2k: seed set to %d\n" % seed)
             except ValueError:
-               sys.stderr.write("sst: replay file %s is ill-formed\n"%optarg)
+               sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
                os.exit(1)
            game.options |= OPTION_TTY
            game.options &=~ OPTION_CURSES
@@ -6943,6 +6870,7 @@ if __name__ == '__main__':
            if ja() == True:
                chew2()
                freeze(False)
+        chew()
        proutn(_("Do you want to play again? "))
        if not ja():
            break