Silence some compile warnings.
[super-star-trek.git] / src / sst.py
index 920fbd13b66c5d24165a92a3d415f69bb3a0315e..a3455bfbf20e076b7c6439e1ecf5422cefadd0ec 100644 (file)
@@ -13,8 +13,7 @@ ion how to modify (and how not to modify!) this code.
 """
 import os, sys, math, curses, time, readline, cPickle, random, copy, gettext, getpass
 
-SSTDOC         = "/usr/share/doc/sst/sst.doc"
-DOC_NAME       = "sst.doc"
+docpath        = (".", "../doc", "/usr/share/doc/sst")
 
 def _(str): return gettext.gettext(str)
 
@@ -33,6 +32,24 @@ MINCMDR      = 10            # Minimum number of Klingon commanders
 DOCKFAC                = 0.25          # Repair faster when docked
 PHASEFAC       = 2.0           # Unclear what this is, it was in the C version
 
+DEFAULT      = -1
+BLACK        = 0
+BLUE         = 1
+GREEN        = 2
+CYAN         = 3
+RED          = 4
+MAGENTA      = 5
+BROWN        = 6
+LIGHTGRAY    = 7
+DARKGRAY     = 8
+LIGHTBLUE    = 9
+LIGHTGREEN   = 10
+LIGHTCYAN    = 11
+LIGHTRED     = 12
+LIGHTMAGENTA = 13
+YELLOW       = 14
+WHITE        = 15
+
 class TrekError:
     pass
 
@@ -183,6 +200,7 @@ OPTION_WORLDS       = 0x00000800    # logic for inhabited worlds (ESR, 2006)
 OPTION_AUTOSCAN        = 0x00001000    # automatic LRSCAN before CHART (ESR, 2006)
 OPTION_PLAIN   = 0x01000000    # user chose plain game 
 OPTION_ALMY    = 0x02000000    # user chose Almy variant 
+OPTION_COLOR    = 0x04000000   # enable color display (experimental, ESR, 2010)
 
 # Define devices 
 DSRSENS        = 0
@@ -319,7 +337,7 @@ class gamestate:
         self.iplnet = None     # planet # in quadrant
         self.inplan = 0                # initial planets
         self.irhere = 0                # Romulans in quadrant
-        self.isatb = 0         # =1 if super commander is attacking base
+        self.isatb = 0         # =2 if super commander is attacking base
         self.tourn = None      # tournament number
         self.nprobes = 0       # number of probes available
         self.inresor = 0.0     # initial resources
@@ -649,7 +667,7 @@ def movescom(iq, avoid):
     game.state.kscmdr = iq
     game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons += 1
     if game.state.kscmdr==game.quadrant:
-       # SC has scooted, Remove him from current quadrant 
+       # SC has scooted, remove him from current quadrant 
        game.iscate=False
        game.isatb=0
        game.ientesc = False
@@ -870,7 +888,6 @@ def doshield(shraise):
        if action=="NONE":
            proutn(_("Do you wish to change shield energy? "))
            if ja() == True:
-               proutn(_("Energy to transfer to shields- "))
                action = "NRG"
            elif damaged(DSHIELD):
                prout(_("Shields damaged and down."))
@@ -918,21 +935,22 @@ def doshield(shraise):
        while scanner.next() != "IHREAL":
            scanner.chew()
            proutn(_("Energy to transfer to shields- "))
+        nrg = scanner.real
        scanner.chew()
-       if scanner.real == 0:
+       if nrg == 0:
            return
-       if scanner.real > game.energy:
+       if nrg > game.energy:
            prout(_("Insufficient ship energy."))
            return
        game.ididit = True
-       if game.shield+scanner.real >= game.inshld:
+       if game.shield+nrg >= game.inshld:
            prout(_("Shield energy maximized."))
-           if game.shield+scanner.real > game.inshld:
+           if game.shield+nrg > game.inshld:
                prout(_("Excess energy requested returned to ship energy"))
            game.energy -= game.inshld-game.shield
            game.shield = game.inshld
            return
-       if scanner.real < 0.0 and game.energy-scanner.real > game.inenrg:
+       if nrg < 0.0 and game.energy-nrg > game.inenrg:
            # Prevent shield drain loophole 
            skip(1)
            prout(_("Engineering to bridge--"))
@@ -940,18 +958,18 @@ def doshield(shraise):
            prout(_("  I can't drain the shields."))
            game.ididit = False
            return
-       if game.shield+scanner.real < 0:
+       if game.shield+nrg < 0:
            prout(_("All shield energy transferred to ship."))
            game.energy += game.shield
            game.shield = 0.0
            return
        proutn(_("Scotty- \""))
-       if scanner.real > 0:
+       if nrg > 0:
            prout(_("Transferring energy to shields.\""))
        else:
            prout(_("Draining energy from shields.\""))
-       game.shield += scanner.real
-       game.energy -= scanner.real
+       game.shield += nrg
+       game.energy -= nrg
        return
 
 def randdevice():
@@ -970,11 +988,12 @@ def randdevice():
        15,     # DCOMPTR: computer                      1.5% 
        20,     # NAVCOMP: navigation system             2.0% 
        75,     # DTRANSP: transporter                   7.5% 
-       20,     # DSHCTRL: high-speed shield controller 2.0% 
+       20,     # DSHCTRL: high-speed shield controller  2.0% 
        10,     # DDRAY: death ray                       1.0% 
        30,     # DDSP: deep-space probes                3.0% 
     )
-    idx = randrange(1000)      # weights must sum to 1000 
+    assert(sum(weights) == 1000)
+    idx = randrange(1000)
     sum = 0
     for (i, w) in enumerate(weights):
        sum += w
@@ -1463,8 +1482,8 @@ def targetcheck(w):
        return None
     return delta.bearing()
 
-def photon():
-    "Launch photon torpedo."
+def torps():
+    "Launch photon torpedo salvo."
     course = []
     game.ididit = False
     if damaged(DPHOTON):
@@ -2326,7 +2345,7 @@ def events():
                else:
                    prout(_("Uhura- Starfleet reports increased Klingon activity"))
                    if q.planet != None:
-                       proutn(_("near %s") % q.planet)
+                       proutn(_("near %s ") % q.planet)
                    prout(_("in Quadrant %s.") % w)
                                
 def wait():
@@ -2904,8 +2923,6 @@ def score():
        klship = 1
     else:
        klship = 2
-    if not game.gamewon:
-       game.state.nromrem = 0 # None captured if no win
     iscore = 10*(game.inkling - game.state.remkl) \
              + 50*(game.incom - len(game.state.kcmdr)) \
              + ithperd + iwon \
@@ -2920,7 +2937,7 @@ def score():
     if game.inrom - game.state.nromrem:
        prout(_("%6d Romulans destroyed                 %5d") %
              (game.inrom - game.state.nromrem, 20*(game.inrom - game.state.nromrem)))
-    if game.state.nromrem:
+    if game.state.nromrem and game.gamewon:
        prout(_("%6d Romulans captured                  %5d") %
              (game.state.nromrem, game.state.nromrem))
     if game.inkling - game.state.remkl:
@@ -2943,7 +2960,7 @@ def score():
              (game.state.nplankl, -10*game.state.nplankl))
     if (game.options & OPTION_WORLDS) and game.state.nworldkl:
        prout(_("%6d inhabited planets destroyed by your action   %5d") %
-             (game.state.nplankl, -300*game.state.nworldkl))
+             (game.state.nworldkl, -300*game.state.nworldkl))
     if game.state.basekl:
        prout(_("%6d bases destroyed by your action     %5d") %
              (game.state.basekl, -100*game.state.basekl))
@@ -3059,6 +3076,17 @@ def iostart():
        stdscr.keypad(True)
        curses.nonl()
        curses.cbreak()
+        if game.options & OPTION_COLOR:
+            curses.start_color();
+            curses.use_default_colors()
+            curses.init_pair(curses.COLOR_BLACK,   curses.COLOR_BLACK, -1);
+            curses.init_pair(curses.COLOR_GREEN,   curses.COLOR_GREEN, -1);
+            curses.init_pair(curses.COLOR_RED,     curses.COLOR_RED, -1);
+            curses.init_pair(curses.COLOR_CYAN,    curses.COLOR_CYAN, -1);
+            curses.init_pair(curses.COLOR_WHITE,   curses.COLOR_WHITE, -1);
+            curses.init_pair(curses.COLOR_MAGENTA, curses.COLOR_MAGENTA, -1);
+            curses.init_pair(curses.COLOR_BLUE,    curses.COLOR_BLUE, -1);
+            curses.init_pair(curses.COLOR_YELLOW,  curses.COLOR_YELLOW, -1);
         global fullscreen_window, srscan_window, report_window, status_window
         global lrscan_window, message_window, prompt_window
         (rows, columns)   = stdscr.getmaxyx()
@@ -3205,7 +3233,48 @@ def clrscr():
        curwnd.move(0, 0)
        curwnd.refresh()
     linecount = 0
-    
+
+def textcolor(color=DEFAULT):
+    if game.options & OPTION_COLOR:
+       if color == DEFAULT: 
+           curwnd.attrset(0);
+       elif color ==  BLACK: 
+           curwnd.attron(curses.color_pair(curses.COLOR_BLACK));
+       elif color ==  BLUE: 
+           curwnd.attron(curses.color_pair(curses.COLOR_BLUE));
+       elif color ==  GREEN: 
+           curwnd.attron(curses.color_pair(curses.COLOR_GREEN));
+       elif color ==  CYAN: 
+           curwnd.attron(curses.color_pair(curses.COLOR_CYAN));
+       elif color ==  RED: 
+           curwnd.attron(curses.color_pair(curses.COLOR_RED));
+       elif color ==  MAGENTA: 
+           curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA));
+       elif color ==  BROWN: 
+           curwnd.attron(curses.color_pair(curses.COLOR_YELLOW));
+       elif color ==  LIGHTGRAY: 
+           curwnd.attron(curses.color_pair(curses.COLOR_WHITE));
+       elif color ==  DARKGRAY: 
+           curwnd.attron(curses.color_pair(curses.COLOR_BLACK) | curses.A_BOLD);
+       elif color ==  LIGHTBLUE: 
+           curwnd.attron(curses.color_pair(curses.COLOR_BLUE) | curses.A_BOLD);
+       elif color ==  LIGHTGREEN: 
+           curwnd.attron(curses.color_pair(curses.COLOR_GREEN) | curses.A_BOLD);
+       elif color ==  LIGHTCYAN: 
+           curwnd.attron(curses.color_pair(curses.COLOR_CYAN) | curses.A_BOLD);
+       elif color ==  LIGHTRED: 
+           curwnd.attron(curses.color_pair(curses.COLOR_RED) | curses.A_BOLD);
+       elif color ==  LIGHTMAGENTA: 
+           curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA) | curses.A_BOLD);
+       elif color ==  YELLOW: 
+           curwnd.attron(curses.color_pair(curses.COLOR_YELLOW) | curses.A_BOLD);
+       elif color ==  WHITE:
+           curwnd.attron(curses.color_pair(curses.COLOR_WHITE) | curses.A_BOLD);
+
+def highvideo():
+    if game.options & OPTION_COLOR:
+        curwnd.attron(curses.A_REVERSE)
+
 #
 # Things past this point have policy implications.
 # 
@@ -4108,10 +4177,12 @@ def mayday():
        elif m == 3: proutn(_("3rd"))
        proutn(_(" attempt to re-materialize ") + crmshp())
        game.quad[ix][iy]=('-','o','O')[m-1]
+        textcolor(RED)
        warble()
        if randreal() > probf:
            break
        prout(_("fails."))
+        textcolor(DEFAULT)
        curses.delay_output(500)
     if m > 3:
        game.quad[ix][iy]='?'
@@ -4121,7 +4192,9 @@ def mayday():
        finish(FMATERIALIZE)
        return
     game.quad[ix][iy]=game.ship
+    textcolor(GREEN);
     prout(_("succeeds."))
+    textcolor(DEFAULT);
     dock(False)
     skip(1)
     prout(_("Lt. Uhura-  \"Captain, we made it!\""))
@@ -4460,7 +4533,7 @@ def usecrystals():
     skip(1)
     prouts(_("Scotty-  \"Keep your fingers crossed, Sir!\""))
     skip(1)
-    if with(game.cryprob):
+    if withprob(game.cryprob):
        prouts(_("  \"Activating now! - - No good!  It's***"))
        skip(2)
        prouts(_("***RED ALERT!  RED A*L********************************"))
@@ -4869,7 +4942,15 @@ def chart():
 def sectscan(goodScan, i, j):
     "Light up an individual dot in a sector."
     if goodScan or (abs(i-game.sector.i)<= 1 and abs(j-game.sector.j) <= 1):
+        textcolor({"green":GREEN,
+                   "yellow":YELLOW,
+                   "red":RED,
+                   "docked":CYAN,
+                   "dead":BROWN}[game.condition]) 
+        if game.quad[i][j] != game.ship: 
+            highvideo();
        proutn("%c " % game.quad[i][j])
+        textcolor(DEFAULT)
     else:
        proutn("- ")
 
@@ -5473,7 +5554,7 @@ def choose():
     # Choose game options -- added by ESR for SST2K
     if scanner.next() != "IHALPHA":
        scanner.chew()
-       proutn(_("Choose your game style (or just press enter): "))
+       proutn(_("Choose your game style (plain, almy, fancy or just press enter): "))
        scanner.next()
     if scanner.sees("plain"):
        # Approximates the UT FORTRAN version.
@@ -5487,6 +5568,7 @@ def choose():
        pass
     elif len(scanner.token):
         proutn(_("What is \"%s\"?") % scanner.token)
+    game.options &=~ OPTION_COLOR
     setpassword()
     if game.passwd == "debug":
        idebug = True
@@ -5729,7 +5811,7 @@ def helpme():
        setwnd(message_window)
        if key == "IHEOL":
            return
-        if scanner.token in commands or scanner.token == "ABBREV":
+        if scanner.token.upper() in commands or scanner.token == "ABBREV":
            break
        skip(1)
        listCommands()
@@ -5737,22 +5819,20 @@ def helpme():
        scanner.chew()
        skip(1)
     cmd = scanner.token.upper()
-    try:
-        fp = open(SSTDOC, "r")
-    except IOError:
+    for directory in docpath:
         try:
-            fp = open(DOC_NAME, "r")
+            fp = open(os.path.join(directory, "sst.doc"), "r")
+            break
         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
+            pass
+    else:
+        prout(_("Spock-  \"Captain, that information is missing from the"))
+        prout(_("   computer. You need to find sst.doc and put it somewhere"))
+        proutn(_("   in these directories: %s") % ":".join(docpath))
+        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 == '':
@@ -5761,12 +5841,13 @@ def helpme():
            return
        if linebuf[0] == '%' and linebuf[1] == '%' and linebuf[2] == ' ':
             linebuf = linebuf[3:].strip()
-            if cmd == linebuf:
+            if cmd.upper() == linebuf:
                break
     skip(1)
     prout(_("Spock- \"Captain, I've found the following information:\""))
     skip(1)
-    while linebuf in fp:
+    while True:
+        linebuf = fp.readline()
         if "******" in linebuf:
            break
        proutn(linebuf)
@@ -5817,8 +5898,8 @@ def makemoves():
            phasers()
            if game.ididit:
                hitme = True
-       elif cmd == "TORPEDO":          # photon torpedos
-           photon()
+       elif cmd in ("TORPEDO", "PHOTONS"):     # photon torpedos
+           torps()
            if game.ididit:
                hitme = True
        elif cmd == "MOVE":             # move under warp
@@ -6199,8 +6280,12 @@ if __name__ == '__main__':
                 sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n")
                 raise SystemExit, 1
         # where to save the input in case of bugs
+        if "TMPDIR" in os.environ:
+            tmpdir = os.environ['TMPDIR']
+        else:
+            tmpdir = "/tmp"
         try:
-            logfp = open("/tmp/sst-input.log", "w")
+            logfp = open(os.path.join(tmpdir, "sst-input.log"), "w")
         except IOError:
             sys.stderr.write("sst: warning, can't open logfile\n")
             sys.exit(1)