Refactor choose parsing so modifying it won't be horrible.
[super-star-trek.git] / sst
diff --git a/sst b/sst
index b105bde25d5ff79aca0443e5a4ed702a39fdf737..b02bc037a83e14762e74c8aca61c81c7d35db0bb 100755 (executable)
--- a/sst
+++ b/sst
@@ -1282,7 +1282,7 @@ def torpedo(origin, bearing, dispersion, number, nburst):
     # Loop to move a single torpedo
     setwnd(message_window)
     for step in range(1, QUADSIZE*2):
-        if not track.nexttok():
+        if not track.nextstep():
             break
         w = track.sector()
         if not w.valid_sector():
@@ -1306,7 +1306,7 @@ def torpedo(origin, bearing, dispersion, number, nburst):
             # In the C/FORTRAN version, dispersion was 2.5 radians, which
             # is 143 degrees, which is almost exactly 4.8 clockface units
             displacement = course(track.bearing+rnd.real(-2.4, 2.4), distance=2**0.5)
-            displacement.nexttok()
+            displacement.nextstep()
             bumpto = displacement.sector()
             if not bumpto.valid_sector():
                 return hit
@@ -1348,7 +1348,7 @@ def torpedo(origin, bearing, dispersion, number, nburst):
                         return None
                     proutn(crmena(True, iquad, "sector", w))
                     displacement = course(track.bearing+rnd.real(-2.4, 2.4), distance=2**0.5, origin=w)
-                    displacement.nexttok()
+                    displacement.nextstep()
                     bumpto = displacement.sector()
                     if game.quad[bumpto.i][bumpto.j] == ' ':
                         prout(_(" buffeted into black hole."))
@@ -2550,7 +2550,7 @@ def events():
                 supercommander()
         elif evcode == FDSPROB: # Move deep space probe
             schedule(FDSPROB, 0.01)
-            if not game.probe.nexttok():
+            if not game.probe.nextstep():
                 if not game.probe.quadrant().valid_quadrant() or \
                     game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j].supernova:
                     # Left galaxy or ran into supernova
@@ -3887,7 +3887,7 @@ def imove(icourse=None, noattack=False):
     # Move out
     game.quad[game.sector.i][game.sector.j] = '.'
     for _m in range(icourse.moves):
-        icourse.nexttok()
+        icourse.nextstep()
         w = icourse.sector()
         if icourse.origin.quadrant() != icourse.location.quadrant():
             newquadrant(noattack)
@@ -4118,7 +4118,7 @@ class course:
         self.step = 0
     def arrived(self):
         return self.location.roundtogrid() == self.final
-    def nexttok(self):
+    def nextstep(self):
         "Next step on course."
         self.step += 1
         self.nextlocation = self.location + self.increment
@@ -4184,7 +4184,7 @@ def impulse():
     return
 
 def warp(wcourse, involuntary):
-    "ove under warp drive."
+    "Move under warp drive."
     blooey = False; twarp = False
     if not involuntary: # Not WARPX entry
         game.ididit = False
@@ -4267,7 +4267,7 @@ def warp(wcourse, involuntary):
             look = wcourse.moves
             while look > 0:
                 look -= 1
-                wcourse.nexttok()
+                wcourse.nextstep()
                 w = wcourse.sector()
                 if not w.valid_sector():
                     break
@@ -5080,8 +5080,10 @@ def deathray():
     prouts(_("WHIRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"))
     skip(1)
     dprob = 0.30
-    # FIX-ME: This test looks inverted
-    if not (game.options & OPTION_ALMY):
+    # Ugh. This test (For Tom Almy's death-ray upgrade) was inverted for a long time.
+    # Furthermore, somebody (ESR or Stas?) changed Tom Almy's 0.7 upgraded chance of
+    # working to 0.5.
+    if game.options & OPTION_ALMY:
         dprob = 0.5
     r = rnd.real()
     if r > dprob:
@@ -5979,28 +5981,45 @@ def setup():
 
 def choose():
     "Choose your game type."
-    while True:
-        game.tourn = None
-        game.length = 0
-        game.thawed = False
-        game.skill = SKILL_NONE
-        # Do not chew here, we want to use command-line tokens
-        if not scanner.inqueue: # Can start with command line options
-            proutn(_("Would you like a regular, tournament, or saved game? "))
+    game.tourn = None
+    game.length = 0
+    game.thawed = False
+    game.skill = SKILL_NONE
+    gametype = None
+    mode = None
+    while gametype is None or game.length == 0 or game.skill == SKILL_NONE or mode is None:
+        eol_is_fancy = False
+        if not scanner.inqueue or scanner.token == "IHEOL": # Can start with command line options
+            if gametype is None:
+                proutn(_("Would you like a regular, tournament, or saved game? "))
+            elif 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? "))
+            elif mode is None:
+                proutn(_("Choose your game style (plain, almy, fancy or just press enter): "))
+                eol_is_fancy = True
         scanner.nexttok()
-        if scanner.sees("tournament"):
+        if game.idebug:
+            prout("-- Token: %s=%s" % (scanner.type, repr(scanner.token)))
+        if scanner.token == "":
+            raise SystemExit(0)        # Early end of replay
+        if scanner.token.startswith("r"):      # regular
+            gametype = "regular"
+        elif scanner.token.startswith("t"):
+            gametype = "tournament"
+            proutn(_("Type in tournament number-"))
             game.tourn = 0
             while scanner.nexttok() == "IHEOL":
-                proutn(_("Type in tournament number-"))
-            if scanner.real == 0:
-                scanner.chew()
-                continue # We don't want a blank entry
+                if scanner.real == 0:
+                    scanner.chew()
+                    continue # We don't want a blank entry
             game.tourn = int(round(scanner.real))
             rnd.seed(scanner.real)
             if logfp:
                 logfp.write("# rnd.seed(%d)\n" % scanner.real)
-            break
-        if scanner.sees("saved") or scanner.sees("frozen"):
+        elif scanner.token.startswith("sa") or scanner.token.startswith("fr"): # saved or frozen
+            gametype = "saved"
             if thaw():
                 continue
             scanner.chew()
@@ -6011,57 +6030,47 @@ def choose():
             report()
             waitfor()
             return True
-        if scanner.sees("regular"):
-            break
-        proutn(_("What is \"%s\"? ") % scanner.token)
-        scanner.chew()
-    while game.length==0 or game.skill==SKILL_NONE:
-        if scanner.nexttok() == "IHALPHA":
-            if scanner.sees("short"):
-                game.length = 1
-            elif scanner.sees("medium"):
-                game.length = 2
-            elif scanner.sees("long"):
-                game.length = 4
-            elif scanner.sees("novice"):
-                game.skill = SKILL_NOVICE
-            elif scanner.sees("fair"):
-                game.skill = SKILL_FAIR
-            elif scanner.sees("good"):
-                game.skill = SKILL_GOOD
-            elif scanner.sees("expert"):
-                game.skill = SKILL_EXPERT
-            elif scanner.sees("emeritus"):
-                game.skill = SKILL_EMERITUS
-            else:
-                proutn(_("What is \""))
-                proutn(scanner.token)
-                prout("\"?")
+        elif scanner.token.startswith("s"):            # short
+            game.length = 1
+        elif scanner.token.startswith("m"):            # medium
+            game.length = 2
+        elif scanner.token.startswith("l"):            # long
+            game.length = 4
+        elif scanner.token.startswith("n"):            # novice
+            game.skill = SKILL_NOVICE
+        elif (game.skill is None) and scanner.token.startswith("f"):           # fair
+            game.skill = SKILL_FAIR
+        elif scanner.token.startswith("g"):            # good
+            game.skill = SKILL_GOOD
+        elif scanner.token.startswith("e"):            # expert
+            game.skill = SKILL_EXPERT
+        elif scanner.token.startswith("em"):   # emeritus
+            game.skill = SKILL_EMERITUS
+        elif scanner.token.startswith("p"):            # plain
+            # Approximates the UT FORTRAN version.
+            game.options &=~ (OPTION_THOLIAN | OPTION_PLANETS | OPTION_PROBE | OPTION_RAMMING | OPTION_MVBADDY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS | OPTION_COLOR | OPTION_CAPTURE | OPTION_CLOAK | OPTION_ALMY | OPTION_AUTOPASS | OPTION_DOTFILL | OPTION_ALPHAMERIC)
+            mode = "plain"
+        elif scanner.token.startswith("almy"): # almy
+            # Approximates Tom Almy's version.
+            mode = "almy"
+            game.options &=~ (OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS | OPTION_COLOR | OPTION_DOTFILL | OPTION_ALPHAMERIC)
+        elif scanner.token.startswith("f"):            # fancy
+            mode = "fancy"
+        elif (eol_is_fancy and scanner.token.startswith("\n")):
+            mode = "fancy"
+        elif scanner.token.startswith("\n"):
+            continue
+        elif scanner.token.startswith("idebug"):
+            game.idebug = True
         else:
-            scanner.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 scanner.nexttok() != "IHALPHA":
-        scanner.chew()
-        proutn(_("Choose your game style (plain, almy, fancy or just press enter): "))
-        scanner.nexttok()
-    if scanner.sees("plain"):
-        # Approximates the UT FORTRAN version.
-        game.options &=~ (OPTION_THOLIAN | OPTION_PLANETS | OPTION_PROBE | OPTION_RAMMING | OPTION_MVBADDY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS | OPTION_COLOR | OPTION_CAPTURE | OPTION_CLOAK | OPTION_ALMY | OPTION_AUTOPASS | OPTION_DOTFILL | OPTION_ALPHAMERIC)
-    elif scanner.sees("almy"):
-        # Approximates Tom Almy's version.
-        game.options &=~ (OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS | OPTION_COLOR | OPTION_DOTFILL | OPTION_ALPHAMERIC)
-    elif scanner.sees("fancy") or scanner.sees("\n"):
-        pass
-    elif len(scanner.token):
-        proutn(_("What is \"%s\"?") % scanner.token)
+            # Unrecognized token
+            prout(_("Can't interpret %s") % repr(scanner.token))
     setpassword()
     if game.passwd == "debug":                # pragma: no cover
         game.idebug = True
         prout("=== Debug mode enabled.")
+    if game.idebug:
+        prout("--- Setup: type=%s length=%s skill=%s mode=%s" % (gametype, game.length, game.skill, mode))
     # Use parameters to generate initial values of things
     game.damfac = 0.5 * game.skill
     game.inbase = rnd.integer(BASEMIN, BASEMAX+1)
@@ -6800,12 +6809,17 @@ if __name__ == '__main__':
                         raise SystemExit(1)
                     # pylint: disable=raise-missing-from
                     try:
-                        line = replayfp.readline().strip()
-                        (leader, __, seed) = line.split()
-                        # pylint: disable=eval-used
-                        seed = eval(seed)
-                        line = replayfp.readline().strip()
-                        arguments += line.split()[2:]
+                        while True:
+                            line = replayfp.readline().strip()
+                            print(line)
+                            if line == "#":
+                                break
+                            if line.startswith("# seed"):
+                                (__, __, seed) = line.split()
+                                # pylint: disable=eval-used
+                                seed = eval(seed)
+                            elif line.startswith("# arguments"):
+                                arguments += line.split()[2:]
                     except ValueError:                # pragma: no cover
                         sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
                         raise SystemExit(1)
@@ -6845,6 +6859,7 @@ if __name__ == '__main__':
             logfp.write("# SST2K version %s\n" % version)
             logfp.write("# recorded by %s@%s on %s\n" % \
                     (getpass.getuser(),socket.getfqdn(),time.ctime()))
+            logfp.write("#\n")
         rnd.seed(seed)
         scanner = sstscanner()
         for arg in arguments: