Bug fix, keyboard interrupt handling, automatic LRSCAN before CHART.
[super-star-trek.git] / src / sst.py
index aa025c8814d12d0dbbab311df96888e2ee963513..81d70160d8a290204bfbe6ca560db5f5bab67fe5 100644 (file)
@@ -172,6 +172,13 @@ your score.  Docking at a starbase replenishes your crew.
 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).
+
+After these features were added, I translated this into Python and added
+more:
+
+9. A long-range scan is done silently whenever you call CHART; thus
+the LRSCAN command is no longer needed.  (Controlled by OPTION_PLAIN
+and turned off if game type is "plain" or "almy".)
 """
 import os,sys,math,curses,time,atexit,readline,cPickle,random,getopt,copy
 
@@ -575,12 +582,12 @@ import traceback
 
 def withprob(p):
     v = random.random()
-    logfp.write("# withprob(%s) -> %f (%s) at %s\n" % (p, v, v<p, traceback.extract_stack()[-2][1:]))
+    #logfp.write("# withprob(%s) -> %f (%s) at %s\n" % (p, v, v<p, traceback.extract_stack()[-2][1:]))
     return v < p
 
 def randrange(*args):
     v = random.randrange(*args)
-    logfp.write("# randrange%s -> %s at %s\n" % (args, v, traceback.extract_stack()[-2][1:]))
+    #logfp.write("# randrange%s -> %s at %s\n" % (args, v, traceback.extract_stack()[-2][1:]))
     return v
 
 def randreal(*args):
@@ -589,7 +596,7 @@ def randreal(*args):
         v *= args[0]           # returns from [0, a1)
     elif len(args) == 2:
         v = args[0] + v*args[1]        # returns from [a1, a2)
-    logfp.write("# randreal%s -> %s at %s\n" % (args, v, traceback.extract_stack()[-2][1:]))
+    #logfp.write("# randreal%s -> %s at %s\n" % (args, v, traceback.extract_stack()[-2][1:]))
     return v
 
 # Code from ai.c begins here
@@ -748,9 +755,9 @@ def movebaddy(com, loccom, ienm):
                 motion = game.skill
     # calculate preferred number of steps 
     if motion < 0:
-        msteps = -motion
+        nsteps = -motion
     else:
-        msteps = motion
+        nsteps = motion
     if motion > 0 and nsteps > mdist:
        nsteps = mdist; # don't overshoot 
     if nsteps > QUADSIZE:
@@ -1285,7 +1292,7 @@ def ram(ibumpd, ienm, w):
         proutn(_(" rammed by "))
     else:
         proutn(_(" rams "))
-    crmena(False, ienm, sector, w)
+    crmena(False, ienm, "sector", w)
     if ibumpd:
        proutn(_(" (original position)"))
     skip(1)
@@ -1386,7 +1393,7 @@ def torpedo(course, r, incoming, i, n):
            shoved = True
        elif iquad in (IHC, IHS): # Hit a commander 
            if withprob(0.05):
-               crmena(True, iquad, sector, w)
+               crmena(True, iquad, "sector", w)
                prout(_(" uses anti-photon device;"))
                prout(_("   torpedo neutralized."))
                return None
@@ -1449,7 +1456,7 @@ def torpedo(course, r, incoming, i, n):
            newcnd()
            return None
        elif iquad == IHP: # Hit a planet 
-           crmena(True, iquad, sector, w)
+           crmena(True, iquad, "sector", w)
            prout(_(" destroyed."))
            game.state.nplankl += 1
            game.state.galaxy[game.quadrant.x][game.quadrant.y].planet = None
@@ -1462,7 +1469,7 @@ def torpedo(course, r, incoming, i, n):
                finish(FDPLANET)
            return None
        elif iquad == IHW: # Hit an inhabited world -- very bad! 
-           crmena(True, iquad, sector, w)
+           crmena(True, iquad, "sector", w)
            prout(_(" destroyed."))
            game.state.nworldkl += 1
            game.state.galaxy[game.quadrant.x][game.quadrant.y].planet = None
@@ -1480,7 +1487,7 @@ def torpedo(course, r, incoming, i, n):
            if withprob(0.9):
                nova(w)
             else:
-                crmena(True, IHSTAR, sector, w)
+                crmena(True, IHSTAR, "sector", w)
                 prout(_(" unaffected by photon blast."))
            return None
        elif iquad == IHQUEST: # Hit a thingy 
@@ -1506,7 +1513,7 @@ def torpedo(course, r, incoming, i, n):
            return None
        elif iquad == IHBLANK: # Black hole 
            skip(1)
-           crmena(True, IHBLANK, sector, w)
+           crmena(True, IHBLANK, "sector", w)
            prout(_(" swallows torpedo."))
            return None
        elif iquad == IHWEB: # hit the web 
@@ -1523,7 +1530,7 @@ def torpedo(course, r, incoming, i, n):
                deadkl(w, iquad, w)
                return None
            skip(1)
-           crmena(True, IHT, sector, w)
+           crmena(True, IHT, "sector", w)
            if withprob(0.05):
                prout(_(" survives photon blast."))
                return None
@@ -1536,7 +1543,7 @@ def torpedo(course, r, incoming, i, n):
         else: # Problem!
            skip(1)
            proutn("Don't know how to handle torpedo collision with ")
-           crmena(True, iquad, sector, w)
+           crmena(True, iquad, "sector", w)
            skip(1)
            return None
        break
@@ -1745,7 +1752,7 @@ 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)
+    crmena(True, type, "sector", mv)
     # Decide what kind of enemy it is and update appropriately 
     if type == IHR:
        # chalk up a Romulan 
@@ -2215,7 +2222,7 @@ def phasers():
                    proutn("??")
                proutn(")  ")
                proutn(_("units to fire at "))
-               crmena(False, ienm, sector, aim)
+               crmena(False, ienm, "sector", aim)
                proutn("-  ")
                key = scan()
            if key == IHALPHA and isit("no"):
@@ -2794,7 +2801,7 @@ def nova(nov):
        return
     # handle initial nova 
     game.quad[nov.x][nov.y] = IHDOT
-    crmena(False, IHSTAR, sector, nov)
+    crmena(False, IHSTAR, "sector", nov)
     prout(_(" novas."))
     game.state.galaxy[game.quadrant.x][game.quadrant.y].stars -= 1
     game.state.starkl += 1
@@ -2829,13 +2836,13 @@ def nova(nov):
                        hits[top2][2]=scratch.y
                        game.state.galaxy[game.quadrant.x][game.quadrant.y].stars -= 1
                        game.state.starkl += 1
-                       crmena(True, IHSTAR, sector, scratch)
+                       crmena(True, IHSTAR, "sector", scratch)
                        prout(_(" novas."))
                        game.quad[scratch.x][scratch.y] = IHDOT
                    elif iquad == IHP: # Destroy planet 
                        game.state.galaxy[game.quadrant.x][game.quadrant.y].planet = None
                        game.state.nplankl += 1
-                       crmena(True, IHP, sector, scratch)
+                       crmena(True, IHP, "sector", scratch)
                        prout(_(" destroyed."))
                        game.iplnet.pclass = "destroyed"
                        game.iplnet = None
@@ -2854,7 +2861,7 @@ def nova(nov):
                        invalidate(game.base)
                        game.state.basekl += 1
                        newcnd()
-                       crmena(True, IHB, sector, scratch)
+                       crmena(True, IHB, "sector", scratch)
                        prout(_(" destroyed."))
                        game.quad[scratch.x][scratch.y] = IHDOT
                    elif iquad in (IHE, IHF): # Buffet ship 
@@ -2890,7 +2897,7 @@ def nova(nov):
                            break
                        newc.x = scratch.x + scratch.x - hits[mm][1]
                        newc.y = scratch.y + scratch.y - hits[mm][2]
-                       crmena(True, iquad, sector, scratch)
+                       crmena(True, iquad, "sector", scratch)
                        proutn(_(" damaged"))
                        if not VALID_SECTOR(newc.x, newc.y):
                            # can't leave quadrant 
@@ -2899,7 +2906,7 @@ def nova(nov):
                        iquad1 = game.quad[newc.x][newc.y]
                        if iquad1 == IHBLANK:
                            proutn(_(", blasted into "))
-                           crmena(False, IHBLANK, sector, newc)
+                           crmena(False, IHBLANK, "sector", newc)
                            skip(1)
                            deadkl(scratch, iquad, newc)
                            break
@@ -3655,7 +3662,7 @@ def cgetline():
                 elif line[0] != "#":
                     break
        else:
-           line = raw_input("COMMAND> ")
+           line = raw_input()
     if logfp:
        logfp.write(line + "\n")
     return line
@@ -3748,7 +3755,7 @@ def drawmaps(mode):
            setwnd(lrscan_window)
            lrscan_window.clear()
            lrscan_window.move(0, 0)
-           lrscan()
+           lrscan(silent=False)
 
 def put_srscan_sym(w, sym):
     "Emit symbol for short-range scan."
@@ -5363,30 +5370,34 @@ def report():
                   (i, (_("s"), "")[i==1]))
     skip(1)
        
-def lrscan():
+def lrscan(silent):
     # long-range sensor scan 
     if damaged(DLRSENS):
        # Now allow base's sensors if docked 
        if game.condition != "docked":
-           prout(_("LONG-RANGE SENSORS DAMAGED."))
+            if not silent:
+                prout(_("LONG-RANGE SENSORS DAMAGED."))
            return
-       prout(_("Starbase's long-range scan"))
-    else:
+        if not silent:
+            prout(_("Starbase's long-range scan"))
+    elif not silent:
        prout(_("Long-range scan"))
     for x in range(game.quadrant.x-1, game.quadrant.x+2):
-        proutn(" ")
+        if not silent:
+            proutn(" ")
         for y in range(game.quadrant.y-1, game.quadrant.y+2):
            if not VALID_QUADRANT(x, y):
-               proutn("  -1")
+                if not silent:
+                    proutn("  -1")
            else:
                if not damaged(DRADIO):
                    game.state.galaxy[x][y].charted = True
                game.state.chart[x][y].klingons = game.state.galaxy[x][y].klingons
                game.state.chart[x][y].starbase = game.state.galaxy[x][y].starbase
                game.state.chart[x][y].stars = game.state.galaxy[x][y].stars
-               if game.state.galaxy[x][y].supernova: 
+               if not silent and game.state.galaxy[x][y].supernova: 
                    proutn(" ***")
-               else:
+               elif not silent:
                    proutn(" %3d" % (game.state.chart[x][y].klingons*100 + game.state.chart[x][y].starbase * 10 + game.state.chart[x][y].stars))
        prout(" ")
 
@@ -5420,6 +5431,8 @@ def rechart():
 def chart():
     # display the star chart  
     chew()
+    if not (game.options & (OPTION_PLAIN | OPTION_ALMY)):
+        lrscan(silent=True)
     if not damaged(DRADIO):
        rechart()
     if game.lastchart < game.state.date and game.condition == "docked":
@@ -6475,6 +6488,7 @@ def makemoves():
            chew()
            setwnd(prompt_window)
            clrscr()
+           proutn("COMMAND> ")
            if scan() == IHEOL:
                if game.options & OPTION_CURSES:
                    makechart()
@@ -6500,7 +6514,7 @@ def makemoves():
        elif cmd == "REQUEST":          # status request 
            request()
        elif cmd == "LRSCAN":           # long range scan
-           lrscan()
+           lrscan(silent=False)
        elif cmd == "PHASERS":          # phasers
            phasers()
            if game.ididit:
@@ -6829,81 +6843,89 @@ def debugme():
        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(val, "r")
-            except IOError:
-               sys.stderr.write("sst: can't open replay file %s\n" % val)
-               raise SystemExit, 1
-            line = replayfp.readline().strip()
-            try:
-                (leader, key, seed) = line.split()
-                seed = eval(seed)
-                sys.stderr.write("sst2k: seed set to %s\n" % seed)
-            except ValueError:
-               sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
-               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:
-       logfp.write("# seed %s\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)
-        chew()
-       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 SystemExit, 0
+        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_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 = int(time.time())
+        (options, arguments) = getopt.getopt(sys.argv[1:], "r:tx")
+        for (switch, val) in options:
+            if switch == '-r':
+                try:
+                    replayfp = open(val, "r")
+                except IOError:
+                    sys.stderr.write("sst: can't open replay file %s\n" % val)
+                    raise SystemExit, 1
+                try:
+                    line = replayfp.readline().strip()
+                    (leader, key, seed) = line.split()
+                    seed = eval(seed)
+                    sys.stderr.write("sst2k: seed set to %s\n" % seed)
+                    line = replayfp.readline().strip()
+                    arguments += line.split()[2:]
+                except ValueError:
+                    sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
+                    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:
+            logfp.write("# seed %s\n" % seed)
+            logfp.write("# options %s\n" % " ".join(arguments))
+        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)
+            chew()
+            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 SystemExit, 0
+    except KeyboardInterrupt:
+        print""
+        pass
+