Drop out the BSD visual-scan code.
[super-star-trek.git] / src / sst.py
index aa22fe10418a10d26f86d952bd3a65b574e164df..e7a54919341fe3d348ff7492a97a2015380e2e94 100644 (file)
@@ -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
 
@@ -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,10 +2474,8 @@ 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 
@@ -2480,16 +2483,16 @@ def events():
                 unschedule(FTBEAM)
                 continue
             i = random.randrange(game.state.remcom)
-            yank = square(game.state.kcmdr[i].x-game.quadrant.x) + square(game.state.kcmdr[i].y-game.quadrant.y)
+            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 
@@ -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:
@@ -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):
@@ -3922,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
@@ -4974,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."))
@@ -5648,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():
@@ -5718,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 
@@ -6039,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)
@@ -6197,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
@@ -6229,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)
@@ -6286,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] = \
@@ -6313,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':
@@ -6326,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
@@ -6497,7 +6444,6 @@ def makemoves():
            chew()
            setwnd(prompt_window)
            clrscr()
-           proutn("COMMAND> ")
            if scan() == IHEOL:
                if game.options & OPTION_CURSES:
                    makechart()
@@ -6535,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
@@ -6588,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:
@@ -6616,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(round(aaitem))
-#ifdef BSD_BUG_FOR_BUG
-#      elif cmd == "VISUAL":
-#          visual()                    # perform visual scan
-#endif
        while True:
            if game.alldone:
                break           # Game has ended
@@ -6671,6 +6609,7 @@ def crmena(stars, enemy, loctype, w):
        proutn("***")
     cramen(enemy)
     proutn(_(" at "))
+    buf = ""
     if loctype == "quadrant":
        buf = _("Quadrant ")
     elif loctype == "sector":
@@ -6877,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
@@ -6930,6 +6870,7 @@ if __name__ == '__main__':
            if ja() == True:
                chew2()
                freeze(False)
+        chew()
        proutn(_("Do you want to play again? "))
        if not ja():
            break