Navigation is finally subsumed by the course object.
[super-star-trek.git] / src / sst.py
index bd01149621a1f10e24d6386883d9e0f3dbab4b13..3cfffb7209734ef84e10a9c94e4cfb597fc63d42 100644 (file)
@@ -250,12 +250,12 @@ class coord:
         return coord(self.i*other, self.j*other)
     def __div__(self, other):
         return coord(self.i/other, self.j/other)
+    def __mod__(self, other):
+        return coord(self.i % other, self.j % other)
     def __rdiv__(self, other):
         return coord(self.i/other, self.j/other)
     def roundtogrid(self):
         return coord(int(round(self.i)), int(round(self.j)))
-    def trunctogrid(self):
-        return coord(int(round(self.i)), int(round(self.j)))
     def distance(self, other=None):
         if not other: other = coord(0, 0)
         return math.sqrt((self.i - other.i)**2 + (self.j - other.j)**2)
@@ -273,13 +273,16 @@ class coord:
         else:
             s.j = self.j / abs(self.j)
         return s
+    def quadrant(self):
+        #print "Location %s -> %s" % (self, (self / QUADSIZE).roundtogrid())
+        return self.roundtogrid() / QUADSIZE
+    def sector(self):
+        return self.roundtogrid() % QUADSIZE
     def scatter(self):
         s = coord()
         s.i = self.i + randrange(-1, 2)
         s.j = self.j + randrange(-1, 2)
         return s
-    def __hash__(self):
-        return hash((x, y))
     def __str__(self):
         if self.i == None or self.j == None:
             return "Nowhere"
@@ -1267,12 +1270,12 @@ def torpedo(origin, bearing, dispersion, number, nburst):
        setwnd(srscan_window)
     else: 
        setwnd(message_window)
-    shoved = False
     ac = bearing + 0.25*dispersion     # dispersion is a random variable
     bullseye = (15.0 - bearing)*0.5235988
     track = course(bearing=ac, distance=QUADSIZE, origin=cartesian(origin)) 
-    jw = coord(0, 0)
+    bumpto = coord(0, 0)
     # Loop to move a single torpedo 
+    setwnd(message_window)
     for step in range(1, QUADSIZE*2):
        track.next()
         w = track.sector()
@@ -1283,16 +1286,14 @@ def torpedo(origin, bearing, dispersion, number, nburst):
        if iquad==IHDOT:
            continue
        # hit something 
-       setwnd(message_window)
-       if damaged(DSRSENS) and not game.condition=="docked":
+       if not damaged(DSRSENS) or game.condition == "docked":
            skip(1);    # start new line after text track 
        if iquad in (IHE, IHF): # Hit our ship 
            skip(1)
            prout(_("Torpedo hits %s.") % crmshp())
            hit = 700.0 + randreal(100) - \
-               1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-angle))
+               1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
            newcnd(); # we're blown out of dock 
-           # We may be displaced. 
            if game.landed or game.condition=="docked":
                return hit # Cheat if on a planet 
            ang = track.angle + 2.5*(randreal()-0.5)
@@ -1301,19 +1302,25 @@ def torpedo(origin, bearing, dispersion, number, nburst):
                temp = math.fabs(math.cos(ang))
            xx = -math.sin(ang)/temp
            yy = math.cos(ang)/temp
-           jw.i = int(w.i+xx+0.5)
-           jw.j = int(w.j+yy+0.5)
-           if not jw.valid_sector():
+           bumpto.i = int(w.i+xx+0.5)
+           bumpto.j = int(w.j+yy+0.5)
+           if not bumpto.valid_sector():
                return hit
-           if game.quad[jw.i][jw.j]==IHBLANK:
+           if game.quad[bumpto.i][bumpto.j]==IHBLANK:
                finish(FHOLE)
                return hit
-           if game.quad[jw.i][jw.j]!=IHDOT:
+           if game.quad[bumpto.i][bumpto.j]!=IHDOT:
                # can't move into object 
                return hit
-           game.sector = jw
+           game.sector = bumpto
            proutn(crmshp())
-           shoved = True
+            game.quad[w.i][w.j]=IHDOT
+            game.quad[bumpto.i][bumpto.j]=iquad
+            prout(_(" displaced by blast to Sector %s ") % bumpto)
+            for enemy in game.enemies:
+                enemy.kdist = enemy.kavgd = (game.sector-enemy.kloc).distance()
+            game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
+            return None
        elif iquad in (IHC, IHS, IHR, IHK): # Hit a regular enemy 
            # find the enemy 
            if iquad in (IHC, IHS) and withprob(0.05):
@@ -1344,23 +1351,25 @@ def torpedo(origin, bearing, dispersion, number, nburst):
                temp = math.fabs(math.cos(ang))
            xx = -math.sin(ang)/temp
            yy = math.cos(ang)/temp
-           jw.i = int(w.i+xx+0.5)
-           jw.j = int(w.j+yy+0.5)
-            if not jw.valid_sector():
+           bumpto.i = int(w.i+xx+0.5)
+           bumpto.j = int(w.j+yy+0.5)
+            if not bumpto.valid_sector():
                prout(_(" damaged but not destroyed."))
                return
-           if game.quad[jw.i][jw.j]==IHBLANK:
+           if game.quad[bumpto.i][bumpto.j] == IHBLANK:
                prout(_(" buffeted into black hole."))
-               deadkl(w, iquad, jw)
-               return None
-           if game.quad[jw.i][jw.j]!=IHDOT:
-               # can't move into object 
+               deadkl(w, iquad, bumpto)
+           if game.quad[bumpto.i][bumpto.j] != IHDOT:
                prout(_(" damaged but not destroyed."))
-               return None
-           proutn(_(" damaged--"))
-           enemy.kloc = jw
-           shoved = True
-           break
+            else:
+                prout(_(" damaged-- displaced by blast to Sector %s ")%bumpto)
+                enemy.kloc = bumpto
+                game.quad[w.i][w.j]=IHDOT
+                game.quad[bumpto.i][bumpto.j]=iquad
+                for enemy in game.enemies:
+                    enemy.kdist = enemy.kavgd = (game.sector-enemy.kloc).distance()
+                game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
+            return None
        elif iquad == IHB: # Hit a base 
            skip(1)
            prout(_("***STARBASE DESTROYED.."))
@@ -1456,16 +1465,6 @@ def torpedo(origin, bearing, dispersion, number, nburst):
            skip(1)
            return None
        break
-    if curwnd!=message_window:
-       setwnd(message_window)
-    if shoved:
-       game.quad[w.i][w.j]=IHDOT
-       game.quad[jw.i][jw.j]=iquad
-       prout(_(" displaced by blast to Sector %s ") % jw)
-       for ll in range(len(game.enemies)):
-           game.enemies[ll].kdist = game.enemies[ll].kavgd = (game.sector-game.enemies[ll].kloc).distance()
-        game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
-       return None
     skip(1)
     prout(_("Torpedo missed."))
     return None;
@@ -2134,7 +2133,7 @@ def phasers():
     if ifast:
        skip(1)
        if no == 0:
-           if withprob(0.99):
+           if withprob(0.01):
                prout(_("Sulu-  \"Sir, the high-speed shield control has malfunctioned . . ."))
                prouts(_("         CLICK   CLICK   POP  . . ."))
                prout(_(" No response, sir!"))
@@ -3525,7 +3524,7 @@ def tracktorpedo(origin, w, step, i, n, iquad):
        if step == 1:
            if n != 1:
                skip(1)
-               proutn(_("Track for %s torpedo number %d-  ") % (game.quad[origin.i][origin.j],i+1))
+               proutn(_("Track for torpedo number %d-  ") % (i+1))
            else:
                skip(1)
                proutn(_("Torpedo track- "))
@@ -3600,19 +3599,10 @@ def imove(course=None, novapush=False):
         newcnd()
         drawmaps(0)
         setwnd(message_window)
-    w.i = w.j = 0
+
     if game.inorbit:
        prout(_("Helmsman Sulu- \"Leaving standard orbit.\""))
        game.inorbit = False
-    angle = ((15.0 - course.bearing) * 0.5235988)
-    deltax = -math.sin(angle)
-    deltay = math.cos(angle)
-    if math.fabs(deltax) > math.fabs(deltay):
-       bigger = math.fabs(deltax)
-    else:
-       bigger = math.fabs(deltay)
-    deltay /= bigger
-    deltax /= bigger
     # If tractor beam is to occur, don't move full distance 
     if game.state.date+game.optime >= scheduled(FTBEAM):
        trbeam = True
@@ -3621,132 +3611,115 @@ def imove(course=None, novapush=False):
        game.optime = scheduled(FTBEAM) - game.state.date + 1e-5
     # Move within the quadrant 
     game.quad[game.sector.i][game.sector.j] = IHDOT
-    x = game.sector.i
-    y = game.sector.j
-    n = int(10.0*course.distance*bigger+0.5)
-    if n > 0:
-       for m in range(1, n+1):
-            x += deltax
-            y += deltay
-           w.i = int(round(x))
-           w.j = int(round(y))
-           if not w.valid_sector():
-               # Leaving quadrant -- allow final enemy attack 
-               # Don't do it if being pushed by Nova 
-               if len(game.enemies) != 0 and not novapush:
-                   newcnd()
-                   for enemy in game.enemies:
-                       finald = (w - enemy.kloc).distance()
-                       enemy.kavgd = 0.5 * (finald + enemy.kdist)
-                   #
-                   # Stas Sergeev added the condition
-                   # that attacks only happen if Klingons
-                   # are present and your skill is good.
-                   # 
-                   if game.skill > SKILL_GOOD and game.klhere > 0 and not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
-                       attack(torps_ok=False)
-                   if game.alldone:
-                       return
-               # compute final position -- new quadrant and sector 
-               x = (QUADSIZE*game.quadrant.i)+game.sector.i
-               y = (QUADSIZE*game.quadrant.j)+game.sector.j
-               w.i = int(round(x+QUADSIZE*course.distance*bigger*deltax))
-               w.j = int(round(y+QUADSIZE*course.distance*bigger*deltay))
-               # check for edge of galaxy 
-               kinks = 0
-                while True:
-                   kink = False
-                   if w.i < 0:
-                       w.i = -w.i
-                       kink = True
-                   if w.j < 0:
-                       w.j = -w.j
-                       kink = True
-                   if w.i >= GALSIZE*QUADSIZE:
-                       w.i = (GALSIZE*QUADSIZE*2) - w.i
-                       kink = True
-                   if w.j >= GALSIZE*QUADSIZE:
-                       w.j = (GALSIZE*QUADSIZE*2) - w.j
-                       kink = True
-                   if kink:
-                       kinks += 1
-                    else:
+    for m in range(course.moves):
+        course.next()
+        w = course.sector()
+        if course.origin.quadrant() != course.location.quadrant():
+            # Leaving quadrant -- allow final enemy attack 
+            # Don't do it if being pushed by Nova 
+            if len(game.enemies) != 0 and not novapush:
+                newcnd()
+                for enemy in game.enemies:
+                    finald = (w - enemy.kloc).distance()
+                    enemy.kavgd = 0.5 * (finald + enemy.kdist)
+                # Stas Sergeev added the condition
+                # that attacks only happen if Klingons
+                # are present and your skill is good.
+                if game.skill > SKILL_GOOD and game.klhere > 0 and not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
+                    attack(torps_ok=False)
+                if game.alldone:
+                    return
+            # check for edge of galaxy 
+            kinks = 0
+            while True:
+                kink = False
+                if course.final.i < 0:
+                    course.final.i = -course.final.i
+                    kink = True
+                if course.final.j < 0:
+                    course.final.j = -course.final.j
+                    kink = True
+                if course.final.i >= GALSIZE*QUADSIZE:
+                    course.final.i = (GALSIZE*QUADSIZE*2) - course.final.i
+                    kink = True
+                if course.final.j >= GALSIZE*QUADSIZE:
+                    course.final.j = (GALSIZE*QUADSIZE*2) - course.final.j
+                    kink = True
+                if kink:
+                    kinks += 1
+                else:
+                    break
+            if kinks:
+                game.nkinks += 1
+                if game.nkinks == 3:
+                    # Three strikes -- you're out! 
+                    finish(FNEG3)
+                    return
+                skip(1)
+                prout(_("YOU HAVE ATTEMPTED TO CROSS THE NEGATIVE ENERGY BARRIER"))
+                prout(_("AT THE EDGE OF THE GALAXY.  THE THIRD TIME YOU TRY THIS,"))
+                prout(_("YOU WILL BE DESTROYED."))
+            # Compute final position in new quadrant 
+            if trbeam: # Don't bother if we are to be beamed 
+                return
+            game.quadrant = course.final.quadrant()
+            game.sector = course.final.sector()
+            skip(1)
+            prout(_("Entering Quadrant %s.") % game.quadrant)
+            game.quad[game.sector.i][game.sector.j] = game.ship
+            newqad()
+            if game.skill>SKILL_NOVICE:
+                attack(torps_ok=False)  
+            return
+        iquad = game.quad[w.i][w.j]
+        if iquad != IHDOT:
+            # object encountered in flight path 
+            stopegy = 50.0*course.distance/game.optime
+            course.distance = (game.sector - w).distance() / (QUADSIZE * 1.0)
+            game.sector = w
+            if iquad in (IHT, IHK, IHC, IHS, IHR, IHQUEST):
+                for enemy in game.enemies:
+                    if enemy.kloc == game.sector:
                         break
-               if kinks:
-                   game.nkinks += 1
-                   if game.nkinks == 3:
-                       # Three strikes -- you're out! 
-                       finish(FNEG3)
-                       return
-                   skip(1)
-                   prout(_("YOU HAVE ATTEMPTED TO CROSS THE NEGATIVE ENERGY BARRIER"))
-                   prout(_("AT THE EDGE OF THE GALAXY.  THE THIRD TIME YOU TRY THIS,"))
-                   prout(_("YOU WILL BE DESTROYED."))
-               # Compute final position in new quadrant 
-               if trbeam: # Don't bother if we are to be beamed 
-                   return
-               game.quadrant.i = w.i/QUADSIZE
-               game.quadrant.j = w.j/QUADSIZE
-               game.sector.i = w.i - (QUADSIZE*game.quadrant.i)
-               game.sector.j = w.j - (QUADSIZE*game.quadrant.j)
-               skip(1)
-               prout(_("Entering Quadrant %s.") % game.quadrant)
-               game.quad[game.sector.i][game.sector.j] = game.ship
-               newqad()
-               if game.skill>SKILL_NOVICE:
-                   attack(torps_ok=False)  
-               return
-           iquad = game.quad[w.i][w.j]
-           if iquad != IHDOT:
-               # object encountered in flight path 
-               stopegy = 50.0*course.dist/game.optime
-               course.distance = (game.sector - w).distance() / (QUADSIZE * 1.0)
-                if iquad in (IHT, IHK, IHC, IHS, IHR, IHQUEST):
-                   game.sector = w
-                    for enemy in game.enemies:
-                        if enemy.kloc == game.sector:
-                            break
-                   collision(rammed=False, enemy=enemy)
-                   final = game.sector
-               elif iquad == IHBLANK:
-                   skip(1)
-                   prouts(_("***RED ALERT!  RED ALERT!"))
-                   skip(1)
-                   proutn("***" + crmshp())
-                   proutn(_(" pulled into black hole at Sector %s") % w)
-                   # Getting pulled into a black hole was certain
-                   # death in Almy's original.  Stas Sergeev added a
-                   # possibility that you'll get timewarped instead.
-                   n=0
-                   for m in range(NDEVICES):
-                       if game.damage[m]>0: 
-                           n += 1
-                   probf=math.pow(1.4,(game.energy+game.shield)/5000.0-1.0)*math.pow(1.3,1.0/(n+1)-1.0)
-                   if (game.options & OPTION_BLKHOLE) and withprob(1-probf): 
-                       timwrp()
-                   else: 
-                       finish(FHOLE)
-                   return
-               else:
-                   # something else 
-                   skip(1)
-                   proutn(crmshp())
-                   if iquad == IHWEB:
-                       prout(_(" encounters Tholian web at %s;") % w)
-                   else:
-                       prout(_(" blocked by object at %s;") % w)
-                   proutn(_("Emergency stop required "))
-                   prout(_("%2d units of energy.") % int(stopegy))
-                   game.energy -= stopegy
-                   final.i = int(round(deltax))
-                   final.j = int(round(deltay))
-                   game.sector = final
-                   if game.energy <= 0:
-                       finish(FNRG)
-                       return
-                # We're here!
-               no_quad_change()
+                collision(rammed=False, enemy=enemy)
+                final = game.sector
+            elif iquad == IHBLANK:
+                skip(1)
+                prouts(_("***RED ALERT!  RED ALERT!"))
+                skip(1)
+                proutn("***" + crmshp())
+                proutn(_(" pulled into black hole at Sector %s") % w)
+                # Getting pulled into a black hole was certain
+                # death in Almy's original.  Stas Sergeev added a
+                # possibility that you'll get timewarped instead.
+                n=0
+                for m in range(NDEVICES):
+                    if game.damage[m]>0: 
+                        n += 1
+                probf=math.pow(1.4,(game.energy+game.shield)/5000.0-1.0)*math.pow(1.3,1.0/(n+1)-1.0)
+                if (game.options & OPTION_BLKHOLE) and withprob(1-probf): 
+                    timwrp()
+                else: 
+                    finish(FHOLE)
                 return
+            else:
+                # something else 
+                skip(1)
+                proutn(crmshp())
+                if iquad == IHWEB:
+                    prout(_(" encounters Tholian web at %s;") % w)
+                else:
+                    prout(_(" blocked by object at %s;") % w)
+                proutn(_("Emergency stop required "))
+                prout(_("%2d units of energy.") % int(stopegy))
+                game.energy -= stopegy
+                game.sector = w
+                if game.energy <= 0:
+                    finish(FNRG)
+                    return
+            # We're here!
+            no_quad_change()
+            return
        course.distance = (game.sector - w).distance() / (QUADSIZE * 1.0)
        game.sector = w
     final = game.sector
@@ -3933,6 +3906,10 @@ class course:
     def __init__(self, bearing, distance, origin=None): 
         self.distance = distance
         self.bearing = bearing
+        if origin is None:
+            self.origin = cartesian(game.quadrant, game.sector)
+        else:
+            self.origin = origin
         # The bearing() code we inherited from FORTRAN is actually computing
         # clockface directions!
         if self.bearing < 0.0:
@@ -3945,7 +3922,8 @@ class course:
         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 = 10*self.distance*bigger +0.5
+        self.moves = int(round(10*self.distance*bigger))
+        self.final = (self.location + self.moves*self.increment).roundtogrid()
     def next(self, grain=1):
         "Next step on course."
         self.moves -=1
@@ -3958,9 +3936,9 @@ class course:
         else:
             return False
     def quadrant(self):
-        return (self.location / QUADSIZE).roundtogrid()
+        return self.location.quadrant()
     def sector(self):
-        return coord(int(round(self.location.i)) % QUADSIZE, int(round(self.location.j)) % QUADSIZE)
+        return self.location.sector()
     def power(self, warp):
        return self.distance*(warp**3)*(game.shldup+1)
     def time(self, warp):