fix array index overrun
[super-star-trek.git] / sst.py
diff --git a/sst.py b/sst.py
index fe04293f10fbbc7c98c28d1292e12016727ee91e..4b3fdfa8a44aadc33df2243abc2cfc38b201da06 100755 (executable)
--- a/sst.py
+++ b/sst.py
@@ -363,6 +363,8 @@ class Gamestate:
         self.cryprob = 0.0     # probability that crystal will work
         self.probe = None      # object holding probe course info
         self.height = 0.0      # height of orbit around planet
+        self.score = 0.0       # overall score
+        self.perdate = 0.0     # rate of kills
         self.idebug = False    # Debugging instrumentation enabled?
     def recompute(self):
         # Stas thinks this should be (C expression): 
@@ -414,7 +416,7 @@ def randreal(*args):
 
 def welcoming(iq):
     "Would this quadrant welcome another Klingon?"
-    return iq.valid_Quadrant() and \
+    return iq.valid_quadrant() and \
        not game.state.galaxy[iq.i][iq.j].supernova and \
        game.state.galaxy[iq.i][iq.j].klingons < MAXKLQUAD
 
@@ -661,7 +663,7 @@ def moveklings():
         for enemy in game.enemies:
             if enemy.type in ('K', 'R'):
                movebaddy(enemy)
-    game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
+    sortenemies()
 
 def movescom(iq, avoid):
     "Commander movement helper." 
@@ -687,7 +689,7 @@ def movescom(iq, avoid):
        game.klhere -= 1
        if game.condition != "docked":
            newcnd()
-        game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
+        sortenemies()
     # check for a helpful planet 
     for i in range(game.inplan):
        if game.state.planets[i].quadrant == game.state.kscmdr and \
@@ -726,7 +728,7 @@ def supercommander():
            unschedule(FSCMOVE)
            return
        sc = game.state.kscmdr
-        for base in game.state.baseq:
+        for (i, base) in enumerate(game.state.baseq):
            basetbl.append((i, (base - sc).distance()))
        if game.state.baseq > 1:
             basetbl.sort(lambda x, y: cmp(x[1], y[1]))
@@ -1071,7 +1073,7 @@ def torpedo(origin, bearing, dispersion, number, nburst):
        if not w.valid_sector():
            break
        iquad=game.quad[w.i][w.j]
-       tracktorpedo(origin, w, step, number, nburst, iquad)
+       tracktorpedo(w, step, number, nburst, iquad)
        if iquad=='.':
            continue
        # hit something 
@@ -1105,7 +1107,7 @@ def torpedo(origin, bearing, dispersion, number, nburst):
             prout(_(" displaced by blast to Sector %s ") % bumpto)
             for enemy in game.enemies:
                 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
-            game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
+            sortenemies()
             return None
        elif iquad in ('C', 'S', 'R', 'K'): # Hit a regular enemy 
            # find the enemy 
@@ -1148,7 +1150,7 @@ def torpedo(origin, bearing, dispersion, number, nburst):
                 game.quad[bumpto.i][bumpto.j]=iquad
                 for enemy in game.enemies:
                     enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
-                game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
+                sortenemies()
             return None
        elif iquad == 'B': # Hit a base 
            skip(1)
@@ -1219,7 +1221,7 @@ def torpedo(origin, bearing, dispersion, number, nburst):
            return None
        elif iquad == 'T':  # Hit a Tholian 
            h1 = 700.0 + randrange(100) - \
-               1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-angle))
+               1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
            h1 = math.fabs(h1)
            if h1 >= 600:
                game.quad[w.i][w.j] = '.'
@@ -1421,7 +1423,7 @@ def attack(torps_ok):
     # After attack, reset average distance to enemies 
     for enemy in game.enemies:
        enemy.kavgd = enemy.kdist
-    game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
+    sortenemies()
     return
                
 def deadkl(w, type, mv):
@@ -2175,13 +2177,13 @@ def events():
                 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 ibq
+                           raise JumpOut
                 else:
                     # no match found -- try later 
                     schedule(FBATTAK, expran(0.3*game.intime))
                     unschedule(FCDBAS)
                     continue
-            except Coord:
+            except JumpOut:
                 pass
            # commander + starbase combination found -- launch attack 
            game.battle = ibq
@@ -2491,7 +2493,7 @@ def nova(nov):
                         finish(FNOVA)
                         return
                     # add in course nova contributes to kicking starship
-                    bump += (game.sector-hits[mm]).sgn()
+                    bump += (game.sector-hits[-1]).sgn()
                 elif iquad == 'K': # kill klingon 
                     deadkl(neighbor, iquad, neighbor)
                 elif iquad in ('C','S','R'): # Damage/destroy big enemies 
@@ -2502,7 +2504,7 @@ def nova(nov):
                     if game.enemies[ll].power <= 0.0:
                         deadkl(neighbor, iquad, neighbor)
                         break
-                    newc = neighbor + neighbor - hits[mm]
+                    newc = neighbor + neighbor - hits[-1]
                     proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged"))
                     if not newc.valid_sector():
                         # can't leave quadrant 
@@ -2690,11 +2692,9 @@ def kaboom():
     skip(1)
     if len(game.enemies) != 0:
        whammo = 25.0 * game.energy
-       l=1
-       while l <= len(game.enemies):
+       for l in range(len(game.enemies)):
            if game.enemies[l].power*game.enemies[l].kdist <= whammo: 
                deadkl(game.enemies[l].location, game.quad[game.enemies[l].location.i][game.enemies[l].location.j], game.enemies[l].location)
-           l += 1
     finish(FDILITHIUM)
                                
 def killrate():
@@ -2918,11 +2918,10 @@ def finish(ifin):
 def score():
     "Compute player's score."
     timused = game.state.date - game.indate
-    iskill = game.skill
     if (timused == 0 or (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0) and timused < 5.0:
        timused = 5.0
-    perdate = killrate()
-    ithperd = 500*perdate + 0.5
+    game.perdate = killrate()
+    ithperd = 500*game.perdate + 0.5
     iwon = 0
     if game.gamewon:
        iwon = 100*game.skill
@@ -2932,7 +2931,7 @@ def score():
        klship = 1
     else:
        klship = 2
-    iscore = 10*(game.inkling - game.state.remkl) \
+    game.score = 10*(game.inkling - game.state.remkl) \
              + 50*(game.incom - len(game.state.kcmdr)) \
              + ithperd + iwon \
              + 20*(game.inrom - game.state.nromrem) \
@@ -2940,7 +2939,7 @@ def score():
             - game.state.nromrem \
              - badpoints()
     if not game.alive:
-       iscore -= 200
+       game.score -= 200
     skip(2)
     prout(_("Your score --"))
     if game.inrom - game.state.nromrem:
@@ -2960,7 +2959,7 @@ def score():
              (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem)))
     if ithperd:
        prout(_("%6.2f Klingons per stardate              %5d") %
-             (perdate, ithperd))
+             (game.perdate, ithperd))
     if game.state.starkl:
        prout(_("%6d stars destroyed by your action     %5d") %
              (game.state.starkl, -5*game.state.starkl))
@@ -2996,7 +2995,7 @@ def score():
        elif game.skill ==  SKILL_EMERITUS:     proutn(_("Emeritus game"))
        prout("           %5d" % iwon)
     skip(1)
-    prout(_("TOTAL SCORE                               %5d") % iscore)
+    prout(_("TOTAL SCORE                               %5d") % game.score)
 
 def plaque():
     "Emit winner's commemmorative plaque." 
@@ -3052,8 +3051,8 @@ def plaque():
     timestring = time.ctime()
     fp.write(_("                                                 This day of %.6s %.4s, %.8s\n\n") %
                     (timestring+4, timestring+20, timestring+11))
-    fp.write(_("                                                        Your score:  %d\n\n") % iscore)
-    fp.write(_("                                                    Klingons per stardate:  %.2f\n") % perdate)
+    fp.write(_("                                                        Your score:  %d\n\n") % game.score)
+    fp.write(_("                                                    Klingons per stardate:  %.2f\n") % game.perdate)
     fp.close()
 
 # Code from io.c begins here
@@ -3160,16 +3159,11 @@ def skip(i):
     "Skip i lines.  Pause game if this would cause a scrolling event."
     for dummy in range(i):
        if game.options & OPTION_CURSES:
-            (y, x) = curwnd.getyx()
-            (my, mx) = curwnd.getmaxyx()
-           if curwnd == message_window and y >= my - 2:
-               pause_game()
-               clrscr()
-           else:
-                try:
-                    curwnd.move(y+1, 0)
-                except curses.error:
-                    pass
+           (y, x) = curwnd.getyx()
+           try:
+               curwnd.move(y+1, 0)
+           except curses.error:
+               pass
        else:
             global linecount
            linecount += 1
@@ -3181,6 +3175,11 @@ def skip(i):
 def proutn(line):
     "Utter a line with no following line feed."
     if game.options & OPTION_CURSES:
+       (y, x) = curwnd.getyx()
+       (my, mx) = curwnd.getmaxyx()
+       if curwnd == message_window and y >= my - 2:
+           pause_game()
+           clrscr()
        curwnd.addstr(line)
        curwnd.refresh()
     else:
@@ -3347,7 +3346,7 @@ def warble():
        #nosound()
         pass
 
-def tracktorpedo(origin, w, step, i, n, iquad):
+def tracktorpedo(w, step, i, n, iquad):
     "Torpedo-track animation." 
     if not game.options & OPTION_CURSES:
        if step == 1:
@@ -3544,7 +3543,7 @@ def imove(icourse=None, noattack=False):
             finald = (w-enemy.location).distance()
             enemy.kavgd = 0.5 * (finald + enemy.kdist)
             enemy.kdist = finald
-        game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
+        sortenemies()
         if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
             attack(torps_ok=False)
         for enemy in game.enemies:
@@ -3890,8 +3889,10 @@ def warp(wcourse, involuntary):
                twarp = True
        if blooey or twarp:
            # If time warp or engine damage, check path 
-           # If it is obstructed, don't do warp or damage 
-            for m_unused in range(wcourse.moves):
+           # If it is obstructed, don't do warp or damage
+            look = wcourse.moves
+            while look > 0:
+                look -= 1
                 wcourse.next()
                 w = wcourse.sector()
                 if not w.valid_sector():
@@ -4189,7 +4190,7 @@ def mayday():
        elif m == 2: proutn(_("2nd"))
        elif m == 3: proutn(_("3rd"))
        proutn(_(" attempt to re-materialize ") + crmshp())
-       game.quad[ix][iy]=('-','o','O')[m-1]
+       game.quad[game.sector.i][game.sector.j]=('-','o','O')[m-1]
         textcolor(RED)
        warble()
        if randreal() > probf:
@@ -4198,13 +4199,13 @@ def mayday():
         textcolor(DEFAULT)
        curses.delay_output(500)
     if m > 3:
-       game.quad[ix][iy]='?'
+       game.quad[game.sector.i][game.sector.j]='?'
        game.alive = False
        drawmaps(1)
        setwnd(message_window)
        finish(FMATERIALIZE)
        return
-    game.quad[ix][iy]=game.ship
+    game.quad[game.sector.i][game.sector.j]=game.ship
     textcolor(GREEN);
     prout(_("succeeds."))
     textcolor(DEFAULT);
@@ -4789,7 +4790,7 @@ def attackreport(curt):
 def report():
     # report on general game status 
     scanner.chew()
-    s1 = "" and game.thawed and _("thawed ")
+    s1 = (game.thawed and _("thawed ")) or ""
     s2 = {1:"short", 2:"medium", 4:"long"}[game.length]
     s3 = (None, _("novice"), _("fair"),
           _("good"), _("expert"), _("emeritus"))[game.skill]
@@ -5216,6 +5217,7 @@ def freeze(boss):
 
 def thaw():
     "Retrieve saved game."
+    global game
     game.passwd[0] = '\0'
     key = scanner.next()
     if key == "IHEOL":
@@ -5630,6 +5632,10 @@ def newkling():
     "Drop new Klingon into current quadrant."
     return Enemy('K', loc=dropin(), power=randreal(300,450)+25.0*game.skill)
 
+def sortenemies():
+    "Sort enemies by distance so 'nearest' is meaningful."
+    game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
+
 def newqad():
     "Set up a new state of quadrant, for when we enter or re-enter it."
     game.justin = True
@@ -5723,7 +5729,7 @@ def newqad():
                game.quad[QUADSIZE-1][0] = 'X'
            if game.quad[QUADSIZE-1][QUADSIZE-1]=='.':
                game.quad[QUADSIZE-1][QUADSIZE-1] = 'X'
-    game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
+    sortenemies()
     # And finally the stars
     for i in range(q.stars):
        dropin('*')