Add color. Turns out SCORE was implemented already.
[super-star-trek.git] / sst.py
diff --git a/sst.py b/sst.py
index d3c8606665ca02e8f8aa2ace2d9f6c6daf221300..df431649e1c0a0579f0f336a4d4b6ce1aa819130 100755 (executable)
--- a/sst.py
+++ b/sst.py
@@ -12,6 +12,7 @@ See the doc/HACKING file in the distribution for designers notes and advice
 on how to modify (and how not to modify!) this code.
 """
 import os, sys, math, curses, time, pickle, random, copy, gettext, getpass
+import getopt, socket, locale
 
 # This import only works on Unixes.  The intention is to enable
 # Ctrl-P, Ctrl-N, and friends in Cmd.
@@ -22,7 +23,7 @@ except ImportError:
 
 version = "2.1"
 
-docpath        = (".", "../doc", "/usr/share/doc/sst")
+docpath        = (".", "doc/", "/usr/share/doc/sst/")
 
 def _(st):
     return gettext.gettext(st)
@@ -211,22 +212,22 @@ class Event:
 # game options
 OPTION_ALL        = 0xffffffff
 OPTION_TTY        = 0x00000001        # old interface
-OPTION_CURSES        = 0x00000002        # new interface
-OPTION_IOMODES        = 0x00000003        # cover both interfaces
-OPTION_PLANETS        = 0x00000004        # planets and mining
-OPTION_THOLIAN        = 0x00000008        # Tholians and their webs (UT 1979 version)
-OPTION_THINGY        = 0x00000010        # Space Thingy can shoot back (Stas, 2005)
-OPTION_PROBE        = 0x00000020        # deep-space probes (DECUS version, 1980)
-OPTION_SHOWME        = 0x00000040        # bracket Enterprise in chart
-OPTION_RAMMING        = 0x00000080        # enemies may ram Enterprise (Almy)
-OPTION_MVBADDY        = 0x00000100        # more enemies can move (Almy)
-OPTION_BLKHOLE        = 0x00000200        # black hole may timewarp you (Stas, 2005)
-OPTION_BASE        = 0x00000400        # bases have good shields (Stas, 2005)
-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)
+OPTION_CURSES     = 0x00000002        # new interface
+OPTION_IOMODES    = 0x00000003        # cover both interfaces
+OPTION_PLANETS    = 0x00000004        # planets and mining
+OPTION_THOLIAN    = 0x00000008        # Tholians and their webs (UT 1979 version)
+OPTION_THINGY     = 0x00000010        # Space Thingy can shoot back (Stas, 2005)
+OPTION_PROBE      = 0x00000020        # deep-space probes (DECUS version, 1980)
+OPTION_SHOWME     = 0x00000040        # bracket Enterprise in chart
+OPTION_RAMMING    = 0x00000080        # enemies may ram Enterprise (Almy)
+OPTION_MVBADDY    = 0x00000100        # more enemies can move (Almy)
+OPTION_BLKHOLE    = 0x00000200        # black hole may timewarp you (Stas, 2005)
+OPTION_BASE       = 0x00000400        # bases have good shields (Stas, 2005)
+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 (ESR, 2010)
 
 # Define devices
 DSRSENS         = 0
@@ -2234,16 +2235,16 @@ def events():
                 unschedule(FBATTAK)
                 unschedule(FCDBAS)
                 continue
+            ibq = None # Force battle location to persist past loop
             try:
                 for ibq in game.state.baseq:
                     for cmdr in game.state.kcmdr:
                         if ibq == cmdr and ibq != game.quadrant and ibq != game.state.kscmdr:
                             raise JumpOut
-                else:
-                    # no match found -- try later
-                    schedule(FBATTAK, expran(0.3*game.intime))
-                    unschedule(FCDBAS)
-                    continue
+                # no match found -- try later
+                schedule(FBATTAK, expran(0.3*game.intime))
+                unschedule(FCDBAS)
+                continue
             except JumpOut:
                 pass
             # commander + starbase combination found -- launch attack
@@ -2398,8 +2399,8 @@ def events():
                             if q.klingons >= MAXKLQUAD or q.supernova:
                                 continue
                             raise JumpOut
-                    else:
-                        continue        # search for eligible quadrant failed
+                    # search for eligible quadrant failed
+                    continue
                 except JumpOut:
                     w = m
             # deliver the child
@@ -2558,33 +2559,37 @@ def nova(nov):
                 elif iquad == 'K': # kill klingon
                     deadkl(neighbor, iquad, neighbor)
                 elif iquad in ('C','S','R'): # Damage/destroy big enemies
+                    target = None
                     for ll in range(len(game.enemies)):
                         if game.enemies[ll].location == neighbor:
+                            target = game.enemies[ll]
                             break
-                    game.enemies[ll].power -= 800.0 # If firepower is lost, die
-                    if game.enemies[ll].power <= 0.0:
-                        deadkl(neighbor, iquad, neighbor)
-                        break
-                    newc = neighbor + neighbor - hits[-1]
-                    proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged"))
-                    if not newc.valid_sector():
-                        # can't leave quadrant
-                        skip(1)
-                        break
-                    iquad1 = game.quad[newc.i][newc.j]
-                    if iquad1 == ' ':
-                        proutn(_(", blasted into ") + crmena(False, ' ', "sector", newc))
-                        skip(1)
-                        deadkl(neighbor, iquad, newc)
-                        break
-                    if iquad1 != '.':
-                        # can't move into something else
-                        skip(1)
-                        break
-                    proutn(_(", buffeted to Sector %s") % newc)
-                    game.quad[neighbor.i][neighbor.j] = '.'
-                    game.quad[newc.i][newc.j] = iquad
-                    game.enemies[ll].move(newc)
+                    if target is not None:
+                        target.power -= 800.0 # If firepower is lost, die
+                        if target.power <= 0.0:
+                            deadkl(neighbor, iquad, neighbor)
+                            continue   # neighbor loop
+                        # Else enemy gets flung by the blast wave
+                        newc = neighbor + neighbor - hits[-1]
+                        proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged"))
+                        if not newc.valid_sector():
+                            # can't leave quadrant
+                            skip(1)
+                            continue
+                        iquad1 = game.quad[newc.i][newc.j]
+                        if iquad1 == ' ':
+                            proutn(_(", blasted into ") + crmena(False, ' ', "sector", newc))
+                            skip(1)
+                            deadkl(neighbor, iquad, newc)
+                            continue
+                        if iquad1 != '.':
+                            # can't move into something else
+                            skip(1)
+                            continue
+                        proutn(_(", buffeted to Sector %s") % newc)
+                        game.quad[neighbor.i][neighbor.j] = '.'
+                        game.quad[newc.i][newc.j] = iquad
+                        target.move(newc)
     # Starship affected by nova -- kick it away.
     dist = kount*0.1
     direc = ncourse[3*(bump.i+1)+bump.j+2]
@@ -3135,7 +3140,6 @@ def iostart():
     # for the older ones we probably need to set C locale, and python3
     # has no problems at all
     if sys.version_info[0] < 3:
-        import locale
         locale.setlocale(locale.LC_ALL, "")
     gettext.bindtextdomain("sst", "/usr/local/share/locale")
     gettext.textdomain("sst")
@@ -3515,6 +3519,8 @@ def imove(icourse=None, noattack=False):
         # check for edge of galaxy
         kinks = 0
         while True:
+
+
             kink = False
             if icourse.final.i < 0:
                 icourse.final.i = -icourse.final.i
@@ -3562,9 +3568,11 @@ def imove(icourse=None, noattack=False):
             if iquad in ('T', 'K', 'C', 'S', 'R', '?'):
                 for enemy in game.enemies:
                     if enemy.location == game.sector:
-                        break
-                collision(rammed=False, enemy=enemy)
-                return True
+                        collision(rammed=False, enemy=enemy)
+                        return True
+                # This should not happen
+                prout(_("Which way did he go?"))
+                return False
             elif iquad == ' ':
                 skip(1)
                 prouts(_("***RED ALERT!  RED ALERT!"))
@@ -3653,7 +3661,7 @@ def dock(verbose):
         prout(crmshp() + _(" not adjacent to base."))
         return
     game.condition = "docked"
-    if "verbose":
+    if verbose:
         prout(_("Docked."))
     game.ididit = True
     if game.energy < game.inenrg:
@@ -3679,7 +3687,7 @@ def cartesian(loc1=None, loc2=None):
 
 def getcourse(isprobe):
     "Get a course and distance from the user."
-    key = 0
+    key = ""
     dquad = copy.copy(game.quadrant)
     navmode = "unspecified"
     itemp = "curt"
@@ -3821,16 +3829,14 @@ class course:
         if self.bearing < 0.0:
             self.bearing += 12.0
         self.angle = ((15.0 - self.bearing) * 0.5235988)
-        if origin is None:
-            self.origin = cartesian(game.quadrant, game.sector)
-        else:
-            self.origin = cartesian(game.quadrant, origin)
         self.increment = Coord(-math.sin(self.angle), math.cos(self.angle))
         bigger = max(abs(self.increment.i), abs(self.increment.j))
         self.increment /= bigger
         self.moves = int(round(10*self.distance*bigger))
         self.reset()
         self.final = (self.location + self.moves*self.increment).roundtogrid()
+        self.location = self.origin
+        self.nextlocation = None
     def reset(self):
         self.location = self.origin
         self.step = 0
@@ -4367,12 +4373,13 @@ def abandon():
         while True:
             # position next to base by trial and error
             game.quad[game.sector.i][game.sector.j] = '.'
+            l = QUADSIZE
             for l in range(QUADSIZE):
                 game.sector = game.base.scatter()
                 if game.sector.valid_sector() and \
                        game.quad[game.sector.i][game.sector.j] == '.':
                     break
-            if l < QUADSIZE+1:
+            if l < QUADSIZE:
                 break # found a spot
             game.sector.i=QUADSIZE/2
             game.sector.j=QUADSIZE/2
@@ -4934,7 +4941,7 @@ def report():
             proutn(_("An armed deep space probe is in "))
         else:
             proutn(_("A deep space probe is in "))
-        prout("Quadrant %s." % game.probec)
+        prout("Quadrant %s." % game.probe.quadrant())
     if game.icrystl:
         if game.cryprob <= .05:
             prout(_("Dilithium crystals aboard ship... not yet used."))
@@ -5047,13 +5054,20 @@ 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()
+        if game.quad[i][j] in ('E', 'F'):
+            textcolor({"green":GREEN,
+                       "yellow":YELLOW,
+                       "red":RED,
+                       "docked":CYAN,
+                       "dead":BROWN}[game.condition])
+        else:
+            textcolor({'?':LIGHTMAGENTA,
+                       'K':LIGHTRED,
+                       'S':LIGHTRED,
+                       'C':LIGHTRED,
+                       'R':LIGHTRED,
+                       'T':LIGHTRED,
+                       }.get(game.quad[i][j], DEFAULT))
         proutn("%c " % game.quad[i][j])
         textcolor(DEFAULT)
     else:
@@ -5684,17 +5698,16 @@ def choose():
         scanner.nexttok()
     if scanner.sees("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_THOLIAN | OPTION_PLANETS | OPTION_THINGY | OPTION_PROBE | OPTION_RAMMING | OPTION_MVBADDY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS | OPTION_COLOR)
         game.options |= OPTION_PLAIN
     elif scanner.sees("almy"):
         # Approximates Tom Almy's version.
-        game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
+        game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS | OPTION_COLOR)
         game.options |= OPTION_ALMY
     elif scanner.sees("fancy") or scanner.sees("\n"):
         pass
     elif len(scanner.token):
         proutn(_("What is \"%s\"?") % scanner.token)
-    game.options &=~ OPTION_COLOR
     setpassword()
     if game.passwd == "debug":
         game.idebug = True
@@ -5893,7 +5906,6 @@ commands = [
     ("IMPULSE",          0),
     ("REST",             0),
     ("WARP",             0),
-    ("SCORE",            0),
     ("SENSORS",          OPTION_PLANETS),
     ("ORBIT",            OPTION_PLANETS),
     ("TRANSPORT",        OPTION_PLANETS),
@@ -5917,6 +5929,7 @@ commands = [
     ("CALL",             0),        # Synonym for MAYDAY
     ("QUIT",             0),
     ("HELP",             0),
+    ("SCORE",            OPTION_ALMY),
     ("",                 0),
 ]
 
@@ -6063,8 +6076,6 @@ def makemoves():
                 hitme = True
         elif cmd == "WARP":                # warp
             setwarp()
-        elif cmd == "SCORE":                # score
-            score()
         elif cmd == "SENSORS":                # sensors
             sensor()
         elif cmd == "ORBIT":                # orbit
@@ -6124,6 +6135,8 @@ def makemoves():
             game.alldone = True                # quit the game
         elif cmd == "HELP":
             helpme()                        # get help
+        elif cmd == "SCORE":
+            score()                         # see current score
         while True:
             if game.alldone:
                 break                # Game has ended
@@ -6373,7 +6386,6 @@ def debugme():
         atover(True)
 
 if __name__ == '__main__':
-    import getopt, socket
     try:
         #global line, thing, game
         game = None