Various minor port fixes.
[super-star-trek.git] / src / sst.py
index d1dc4db021083bbbdf4ffcfe697ba35076b43891..7eb5c938da4879ef6dda8ec2f86da88b6f4089ac 100644 (file)
@@ -206,11 +206,6 @@ MAXBURST   = 3
 def VALID_QUADRANT(x, y):      return ((x)>=0 and (x)<GALSIZE and (y)>=0 and (y)<GALSIZE)
 def VALID_SECTOR(x, y):        return ((x)>=0 and (x)<QUADSIZE and (y)>=0 and (y)<QUADSIZE)
 
-def square(i):         return ((i)*(i))
-def distance(c1, c2):  return math.sqrt(square(c1.x - c2.x) + square(c1.y - c2.y))
-def invalidate(w):     w.x = w.y = 0
-def is_valid(w):       return (w.x != 0 and w.y != 0)
-
 # How to represent features
 IHR = 'R',
 IHK = 'K',
@@ -248,8 +243,13 @@ class coord:
     def __add__(self, other):
         return coord(self.x+self.x, self.y+self.y)
     def __sub__(self, other):
-        return coord(self.x-self.x, self.y-self.y)
-    def distance(self, other):
+        return coord(self.x-other.x, self.y-other.y)
+    def __mul__(self, other):
+        return coord(self.x*other, self.y*other)
+    def __rmul__(self, other):
+        return coord(self.x*other, self.y*other)
+    def distance(self, other=None):
+        if not other: other = coord(0, 0)
         return math.sqrt((self.x - other.x)**2 + (self.y - other.y)**2)
     def sgn(self):
         s = coord()
@@ -262,6 +262,8 @@ class coord:
         else:
             s.y = self.y / abs(self.y)
         return s
+    def course(self):
+        return 1.90985*math.atan2(self.y, self.x)
     def scatter(self):
         s = coord()
         s.x = self.x + randrange(-1, 2)
@@ -427,13 +429,17 @@ class enemy:
     def move(self, loc):
         motion = (loc != self.kloc)
         if self.kloc.x is not None and self.kloc.y is not None:
-            game.quad[self.kloc.x][self.kloc.y] = IHDOT
+            if motion:
+                if self.type == IHT:
+                    game.quad[self.kloc.x][self.kloc.y] = IHWEB
+                else:
+                    game.quad[self.kloc.x][self.kloc.y] = IHDOT
         if loc:
-            self.kloc = loc
+            self.kloc = copy.copy(loc)
             game.quad[self.kloc.x][self.kloc.y] = self.type
-            self.kdist = self.kavgd = distance(game.sector, loc)
+            self.kdist = self.kavgd = (game.sector - loc).distance()
         else:
-            self.kloc = coord()        # enemy sector location
+            self.kloc = coord()
             self.kdist = self.kavgd = None
             game.enemies.remove(self)
         return motion
@@ -445,7 +451,7 @@ class gamestate:
         self.options = None    # Game options
         self.state = snapshot()        # A snapshot structure
         self.snapsht = snapshot()      # Last snapshot taken for time-travel purposes
-        self.quad = fill2d(QUADSIZE, lambda i, j: IHDOT)       # contents of our quadrant
+        self.quad = None       # contents of our quadrant
         self.damage = [0.0] * NDEVICES # damage encountered
         self.future = []               # future events
         for i in range(NEVENTS):
@@ -598,9 +604,9 @@ def randrange(*args):
 def randreal(*args):
     v = random.random()
     if len(args) == 1:
-        v *= args[0]           # returns from [0, a1)
+        v *= args[0]           # returns from [0, args[0])
     elif len(args) == 2:
-        v = args[0] + v*args[1]        # returns from [a1, a2)
+        v = args[0] + v*(args[1]-args[0])      # returns from [args[0], args[1])
     #logfp.write("# randreal%s -> %s at %s\n" % (args, v, traceback.extract_stack()[-2][1:]))
     return v
 
@@ -737,9 +743,9 @@ def movebaddy(enemy):
            motion = ((forces + randreal(200))/150.0) - 5.0
        else:
             if forces > 1000.0: # Very strong -- move in for kill 
-               motion = (1.0-square(randreal()))*dist1 + 1.0
+               motion = (1.0 - randreal())**2 * dist1 + 1.0
            if game.condition=="docked" and (game.options & OPTION_BASE): # protected by base -- back off ! 
-               motion -= game.skill*(2.0-square(randreal()))
+               motion -= game.skill*(2.0-randreal()**2)
        if idebug:
            proutn("=== MOTION = %d, FORCES = %1.2f, " % (motion, forces))
        # don't move if no motion 
@@ -943,7 +949,7 @@ def supercommander():
            return
        sc = game.state.kscmdr
        for i in range(game.state.rembase):
-           basetbl.append((i, distance(game.state.baseq[i], sc)))
+           basetbl.append((i, (game.state.baseq[i] - sc).distance()))
        if game.state.rembase > 1:
             basetbl.sort(lambda x, y: cmp(x[1]. y[1]))
        # look for nearest base without a commander, no Enterprise, and
@@ -1043,41 +1049,40 @@ def supercommander():
     return
 
 def movetholian():
-    # move the Tholian 
+    # move the Tholian
     if not game.tholian or game.justin:
        return
+    id = coord()
     if game.tholian.kloc.x == 0 and game.tholian.kloc.y == 0:
-       idx = 0; idy = QUADSIZE-1
+       id.x = 0; id.y = QUADSIZE-1
     elif game.tholian.kloc.x == 0 and game.tholian.kloc.y == QUADSIZE-1:
-       idx = QUADSIZE-1; idy = QUADSIZE-1
+       id.x = QUADSIZE-1; id.y = QUADSIZE-1
     elif game.tholian.kloc.x == QUADSIZE-1 and game.tholian.kloc.y == QUADSIZE-1:
-       idx = QUADSIZE-1; idy = 0
+       id.x = QUADSIZE-1; id.y = 0
     elif game.tholian.kloc.x == QUADSIZE-1 and game.tholian.kloc.y == 0:
-       idx = 0; idy = 0
+       id.x = 0; id.y = 0
     else:
        # something is wrong! 
-       game.tholian = None
+       game.tholian.move(None)
+        prout("***Internal error: Tholian in a bad spot.")
        return
     # do nothing if we are blocked 
-    if game.quad[idx][idy]!= IHDOT and game.quad[idx][idy]!= IHWEB:
+    if game.quad[id.x][id.y] not in (IHDOT, IHWEB):
        return
-    game.quad[game.tholian.kloc.x][game.tholian.kloc.y] = IHWEB
-    if game.tholian.kloc.x != idx:
-       # move in x axis 
-       im = math.fabs(idx - game.tholian.kloc.x)*1.0/(idx - game.tholian.kloc.x)
-       while game.tholian.kloc.x != idx:
-           game.tholian.kloc.x += im
-           if game.quad[game.tholian.kloc.x][game.tholian.kloc.y]==IHDOT:
-               game.quad[game.tholian.kloc.x][game.tholian.kloc.y] = IHWEB
-    elif game.tholian.kloc.y != idy:
-       # move in y axis 
-       im = math.fabs(idy - game.tholian.kloc.y)*1.0/(idy - game.tholian.kloc.y)
-       while game.tholian.kloc.y != idy:
-           game.tholian.kloc.y += im
-           if game.quad[game.tholian.kloc.x][game.tholian.kloc.y]==IHDOT:
-               game.quad[game.tholian.kloc.x][game.tholian.kloc.y] = IHWEB
-    game.quad[game.tholian.kloc.x][game.tholian.kloc.y] = IHT
-    #game.enemies[-1].kloc = game.tholian      #FIXME
+    here = copy.copy(game.tholian.kloc)
+    delta = (id - game.tholian.kloc).sgn()
+    # move in x axis 
+    while here.x != id.x:
+        #print "Moving in X", delta
+        here.x += delta.x
+        if game.quad[here.x][here.y]==IHDOT:
+            game.tholian.move(here)
+    # move in y axis 
+    while here.y != id.y:
+        #print "Moving in Y", delta
+        here.y += delta.y
+        if game.quad[here.x][here.y]==IHDOT:
+            game.tholian.move(here)
     # check to see if all holes plugged 
     for i in range(QUADSIZE):
        if game.quad[0][i]!=IHWEB and game.quad[0][i]!=IHT:
@@ -1094,6 +1099,7 @@ def movetholian():
     crmena(True, IHT, "sector", game.tholian)
     prout(_(" completes web."))
     game.tholian.move(None)
+    print "Tholian movement ends"
     return
 
 # Code from battle.c begins here
@@ -1105,18 +1111,17 @@ def doshield(shraise):
     if shraise:
        action = "SHUP"
     else:
-       key = scan()
+       key = scanner.next()
        if key == IHALPHA:
-           if isit("transfer"):
+           if scanner.sees("transfer"):
                action = "NRG"
            else:
-               chew()
                if damaged(DSHIELD):
                    prout(_("Shields damaged and down."))
                    return
-               if isit("up"):
+               if scanner.sees("up"):
                    action = "SHUP"
-               elif isit("down"):
+               elif scanner.sees("down"):
                    action = "SHDN"
        if action=="NONE":
            proutn(_("Do you wish to change shield energy? "))
@@ -1131,14 +1136,14 @@ def doshield(shraise):
                if ja() == True:
                    action = "SHDN"
                else:
-                   chew()
+                   scanner.chew()
                    return
            else:
                proutn(_("Shields are down. Do you want them up? "))
                if ja() == True:
                    action = "SHUP"
                else:
-                   chew()
+                   scanner.chew()
                    return    
     if action == "SHUP": # raise shields 
        if game.shldup:
@@ -1166,24 +1171,24 @@ def doshield(shraise):
        game.ididit = True
        return
     elif action == "NRG":
-       while scan() != IHREAL:
-           chew()
+       while scanner.next() != IHREAL:
+           scanner.chew()
            proutn(_("Energy to transfer to shields- "))
-       chew()
-       if aaitem == 0:
+       scanner.chew()
+       if scanner.real == 0:
            return
-       if aaitem > game.energy:
+       if scanner.real > game.energy:
            prout(_("Insufficient ship energy."))
            return
        game.ididit = True
-       if game.shield+aaitem >= game.inshld:
+       if game.shield+scanner.real >= game.inshld:
            prout(_("Shield energy maximized."))
-           if game.shield+aaitem > game.inshld:
+           if game.shield+scanner.real > game.inshld:
                prout(_("Excess energy requested returned to ship energy"))
            game.energy -= game.inshld-game.shield
            game.shield = game.inshld
            return
-       if aaitem < 0.0 and game.energy-aaitem > game.inenrg:
+       if scanner.real < 0.0 and game.energy-scanner.real > game.inenrg:
            # Prevent shield drain loophole 
            skip(1)
            prout(_("Engineering to bridge--"))
@@ -1191,18 +1196,18 @@ def doshield(shraise):
            prout(_("  I can't drain the shields."))
            game.ididit = False
            return
-       if game.shield+aaitem < 0:
+       if game.shield+scanner.real < 0:
            prout(_("All shield energy transferred to ship."))
            game.energy += game.shield
            game.shield = 0.0
            return
        proutn(_("Scotty- \""))
-       if aaitem > 0:
+       if scanner.real > 0:
            prout(_("Transferring energy to shields.\""))
        else:
            prout(_("Draining energy from shields.\""))
-       game.shield += aaitem
-       game.energy -= aaitem
+       game.shield += scanner.real
+       game.energy -= scanner.real
        return
 
 def randdevice():
@@ -1332,7 +1337,7 @@ def torpedo(course, dispersion, origin, number, nburst):
        if not VALID_SECTOR(w.x, w.y):
            break
        iquad=game.quad[w.x][w.y]
-       tracktorpedo(w, step, number, nburst, iquad)
+       tracktorpedo(origin, w, step, number, nburst, iquad)
        if iquad==IHDOT:
            continue
        # hit something 
@@ -1345,7 +1350,7 @@ def torpedo(course, dispersion, origin, number, nburst):
            crmshp()
            prout(".")
            hit = 700.0 + randreal(100) - \
-               1000.0 * distance(w, origin) * math.fabs(math.sin(bullseye-angle))
+               1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-angle))
            newcnd(); # we're blown out of dock 
            # We may be displaced. 
            if game.landed or game.condition=="docked":
@@ -1382,7 +1387,7 @@ def torpedo(course, dispersion, origin, number, nburst):
                    break
            kp = math.fabs(e.kpower)
            h1 = 700.0 + randrange(100) - \
-               1000.0 * distance(w, origin) * math.fabs(math.sin(bullseye-angle))
+               1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-angle))
            h1 = math.fabs(h1)
            if kp < h1:
                h1 = kp
@@ -1440,7 +1445,7 @@ def torpedo(course, dispersion, origin, number, nburst):
            game.state.galaxy[game.quadrant.x][game.quadrant.y].planet = None
            game.iplnet.pclass = "destroyed"
            game.iplnet = None
-           invalidate(game.plnet)
+           game.plnet.invalidate()
            game.quad[w.x][w.y] = IHDOT
            if game.landed:
                # captain perishes on planet 
@@ -1453,7 +1458,7 @@ def torpedo(course, dispersion, origin, number, nburst):
            game.state.galaxy[game.quadrant.x][game.quadrant.y].planet = None
            game.iplnet.pclass = "destroyed"
            game.iplnet = None
-           invalidate(game.plnet)
+           game.plnet.invalidate()
            game.quad[w.x][w.y] = IHDOT
            if game.landed:
                # captain perishes on planet 
@@ -1499,7 +1504,7 @@ def torpedo(course, dispersion, origin, number, nburst):
            return None
        elif iquad == IHT:  # Hit a Tholian 
            h1 = 700.0 + randrange(100) - \
-               1000.0 * distance(w, origin) * math.fabs(math.sin(bullseye-angle))
+               1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-angle))
            h1 = math.fabs(h1)
            if h1 >= 600:
                game.quad[w.x][w.y] = IHDOT
@@ -1530,7 +1535,7 @@ def torpedo(course, dispersion, origin, number, nburst):
        game.quad[jw.x][jw.y]=iquad
        prout(_(" displaced by blast to Sector %s ") % jw)
        for ll in range(len(game.enemies)):
-           game.enemies[ll].kdist = game.enemies[ll].kavgd = distance(game.sector,game.enemies[ll].kloc)
+           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)
@@ -1558,7 +1563,7 @@ def fry(hit):
     for (i, j) in enumerate(cdam):
        proutn(device[j])
         if skipcount % 3 == 2 and i < len(cdam)-1:
-            skip()
+            skip(1)
         skipcount += 1
         if i < len(cdam)-1:
             proutn(_(" and "))
@@ -1622,7 +1627,7 @@ def attack(torps_ok):
            if game.condition == "docked":
                continue; # Don't waste the effort! 
            attempt = True; # Attempt to attack 
-           dustfac = 0.8 + randreal(0.5)
+           dustfac = randreal(0.8, 0.85)
            hit = enemy.kpower*math.pow(dustfac,enemy.kavgd)
            enemy.kpower *= 0.75
        else: # Enemy uses photon torpedo 
@@ -1783,50 +1788,51 @@ def targetcheck(w):
        prout(_("Spock-  \"Bridge to sickbay.  Dr. McCoy,"))
        prout(_("  I recommend an immediate review of"))
        prout(_("  the Captain's psychological profile.\""))
-       chew()
+       scanner.chew()
        return None
     return 1.90985932*math.atan2(deltx, delty)
 
 def photon():
-    # launch photon torpedo 
+    # launch photon torpedo
+    course = [0.0] * MAXBURST
     game.ididit = False
     if damaged(DPHOTON):
        prout(_("Photon tubes damaged."))
-       chew()
+       scanner.chew()
        return
     if game.torps == 0:
        prout(_("No torpedoes left."))
-       chew()
+       scanner.chew()
        return
-    key = scan()
+    key = scanner.next()
     while True:
        if key == IHALPHA:
            huh()
            return
        elif key == IHEOL:
            prout(_("%d torpedoes left.") % game.torps)
-            chew()
+            scanner.chew()
            proutn(_("Number of torpedoes to fire- "))
-           key = scan()
-       else: # key == IHREAL  {
-           n = aaitem + 0.5
+           key = scanner.next()
+       else: # key == IHREAL
+           n = scanner.int()
            if n <= 0: # abort command 
-               chew()
+               scanner.chew()
                return
            if n > MAXBURST:
-               chew()
+               scanner.chew()
                prout(_("Maximum of %d torpedoes per burst.") % MAXBURST)
                key = IHEOL
                return
            if n <= game.torps:
                break
-           chew()
+           scanner.chew()
            key = IHEOL
     targ = []
     for i in range(MAXBURST):
         targ.append(coord())
     for i in range(n):
-       key = scan()
+       key = scanner.next()
        if i==0 and key == IHEOL:
            break;      # we will try prompting 
        if i==1 and key == IHEOL:
@@ -1839,31 +1845,31 @@ def photon():
        if key != IHREAL:
            huh()
            return
-       targ[i].x = aaitem
-       key = scan()
+       targ[i].x = scanner.int()
+       key = scanner.next()
        if key != IHREAL:
            huh()
            return
-       targ[i].y = aaitem
+       targ[i].y = scanner.int()
        course[i] = targetcheck(targ[i])
         if course[i] == None:
            return
-    chew()
-    if i == 1 and key == IHEOL:
+    scanner.chew()
+    if i == 0 and key == IHEOL:
        # prompt for each one 
        for i in range(n):
            proutn(_("Target sector for torpedo number %d- ") % (i+1))
-           key = scan()
+           key = scanner.next()
            if key != IHREAL:
                huh()
                return
-           targ[i].x = int(aaitem-0.5)
-           key = scan()
+           targ[i].x = scanner.int()
+           key = scanner.next()
            if key != IHREAL:
                huh()
                return
-           targ[i].y = int(aaitem-0.5)
-           chew()
+           targ[i].y = scanner.int()
+           scanner.chew()
             course[i] = targetcheck(targ[i])
             if course[i] == None:
                 return
@@ -1941,9 +1947,10 @@ def checkshctrl(rpow):
 
 def hittem(hits):
     # register a phaser hit on Klingons and Romulans
-    nenhr2 = game.nenhere; kk=0
+    nenhr2 = len(game.enemies); kk=0
     w = coord()
     skip(1)
+    print "Hits are:", hits
     for (k, wham) in enumerate(hits):
        if wham==0:
            continue
@@ -1994,57 +2001,57 @@ def phasers():
     automode = "NOTSET"
     key=0
     skip(1)
-    # SR sensors and Computer are needed fopr automode 
+    # SR sensors and Computer are needed for automode 
     if damaged(DSRSENS) or damaged(DCOMPTR):
        itarg = False
     if game.condition == "docked":
        prout(_("Phasers can't be fired through base shields."))
-       chew()
+       scanner.chew()
        return
     if damaged(DPHASER):
        prout(_("Phaser control damaged."))
-       chew()
+       scanner.chew()
        return
     if game.shldup:
        if damaged(DSHCTRL):
            prout(_("High speed shield control damaged."))
-           chew()
+           scanner.chew()
            return
        if game.energy <= 200.0:
            prout(_("Insufficient energy to activate high-speed shield control."))
-           chew()
+           scanner.chew()
            return
        prout(_("Weapons Officer Sulu-  \"High-speed shield control enabled, sir.\""))
        ifast = True
     # Original code so convoluted, I re-did it all
     # (That was Tom Almy talking about the C code, I think -- ESR)
     while automode=="NOTSET":
-       key=scan()
+       key=scanner.next()
        if key == IHALPHA:
-           if isit("manual"):
-               if game.nenhere==0:
+           if scanner.sees("manual"):
+               if len(game.enemies)==0:
                    prout(_("There is no enemy present to select."))
-                   chew()
+                   scanner.chew()
                    key = IHEOL
                    automode="AUTOMATIC"
                else:
                    automode = "MANUAL"
-                   key = scan()
-           elif isit("automatic"):
-               if (not itarg) and game.nenhere != 0:
+                   key = scanner.next()
+           elif scanner.sees("automatic"):
+               if (not itarg) and len(game.enemies) != 0:
                    automode = "FORCEMAN"
                else:
-                   if game.nenhere==0:
+                   if len(game.enemies)==0:
                        prout(_("Energy will be expended into space."))
                    automode = "AUTOMATIC"
-                   key = scan()
-           elif isit("no"):
+                   key = scanner.next()
+           elif scanner.sees("no"):
                no = True
            else:
                huh()
                return
        elif key == IHREAL:
-           if game.nenhere==0:
+           if len(game.enemies)==0:
                prout(_("Energy will be expended into space."))
                automode = "AUTOMATIC"
            elif not itarg:
@@ -2053,37 +2060,37 @@ def phasers():
                automode = "AUTOMATIC"
        else:
            # IHEOL 
-           if game.nenhere==0:
+           if len(game.enemies)==0:
                prout(_("Energy will be expended into space."))
                automode = "AUTOMATIC"
            elif not itarg:
                automode = "FORCEMAN"
            else: 
                proutn(_("Manual or automatic? "))
-                chew()
+                scanner.chew()
     avail = game.energy
     if ifast:
         avail -= 200.0
     if automode == "AUTOMATIC":
-       if key == IHALPHA and isit("no"):
+       if key == IHALPHA and scanner.sees("no"):
            no = True
-           key = scan()
-       if key != IHREAL and game.nenhere != 0:
+           key = scanner.next()
+       if key != IHREAL and len(game.enemies) != 0:
            prout(_("Phasers locked on target. Energy available: %.2f")%avail)
        irec=0
         while True:
-           chew()
+           scanner.chew()
            if not kz:
-               for i in range(game.nenhere):
+               for i in range(len(game.enemies)):
                    irec += math.fabs(game.enemies[i].kpower)/(PHASEFAC*math.pow(0.90,game.enemies[i].kdist))*randreal(1.01, 1.06) + 1.0
            kz=1
            proutn(_("%d units required. ") % irec)
-           chew()
+           scanner.chew()
            proutn(_("Units to fire= "))
-           key = scan()
+           key = scanner.next()
            if key!=IHREAL:
                return
-           rpow = aaitem
+           rpow = scanner.real
            if rpow > avail:
                proutn(_("Energy available= %.2f") % avail)
                skip(1)
@@ -2092,22 +2099,22 @@ def phasers():
                 break
        if rpow<=0:
            # chicken out 
-           chew()
+           scanner.chew()
            return
-        key=scan()
-       if key == IHALPHA and isit("no"):
+        key=scanner.next()
+       if key == IHALPHA and scanner.sees("no"):
            no = True
        if ifast:
            game.energy -= 200; # Go and do it! 
            if checkshctrl(rpow):
                return
-       chew()
+       scanner.chew()
        game.energy -= rpow
        extra = rpow
-       if game.nenhere:
+       if len(game.enemies):
            extra = 0.0
            powrem = rpow
-           for i in range(game.nenhere):
+           for i in range(len(game.enemies)):
                hits.append(0.0)
                if powrem <= 0:
                    continue
@@ -2127,13 +2134,13 @@ def phasers():
        if extra > 0 and not game.alldone:
            if game.tholian:
                proutn(_("*** Tholian web absorbs "))
-               if game.nenhere>0:
+               if len(game.enemies)>0:
                    proutn(_("excess "))
                prout(_("phaser energy."))
            else:
                prout(_("%d expended on empty space.") % int(extra))
     elif automode == "FORCEMAN":
-       chew()
+       scanner.chew()
        key = IHEOL
        if damaged(DCOMPTR):
            prout(_("Battle computer damaged, manual fire only."))
@@ -2147,7 +2154,7 @@ def phasers():
            skip(1)
     elif automode == "MANUAL":
        rpow = 0.0
-        for k in range(game.nenhere):
+        for k in range(len(game.enemies)):
            aim = game.enemies[k].kloc
            ienm = game.quad[aim.x][aim.y]
            if msgflag:
@@ -2155,17 +2162,17 @@ def phasers():
                skip(1)
                msgflag = False
                rpow = 0.0
-           if damaged(DSRSENS) and not (abs(game.sector.x-aim.x) < 2 and abs(game.sector.y-aim.y) < 2) and \
-               (ienm == IHC or ienm == IHS):
+           if damaged(DSRSENS) and \
+               not game.sector.distance(aim)<2**0.5 and ienm in (IHC, IHS):
                cramen(ienm)
                prout(_(" can't be located without short range scan."))
-               chew()
+               scanner.chew()
                key = IHEOL
                hits[k] = 0; # prevent overflow -- thanks to Alexei Voitenko 
                k += 1
                continue
            if key == IHEOL:
-               chew()
+               scanner.chew()
                if itarg and k > kz:
                    irec=(abs(game.enemies[k].kpower)/(PHASEFAC*math.pow(0.9,game.enemies[k].kdist))) * randreal(1.01, 1.06) + 1.0
                kz = k
@@ -2178,10 +2185,10 @@ def phasers():
                proutn(_("units to fire at "))
                crmena(False, ienm, "sector", aim)
                proutn("-  ")
-               key = scan()
-           if key == IHALPHA and isit("no"):
+               key = scanner.next()
+           if key == IHALPHA and scanner.sees("no"):
                no = True
-               key = scan()
+               key = scanner.next()
                continue
            if key == IHALPHA:
                huh()
@@ -2190,27 +2197,27 @@ def phasers():
                if k==1: # Let me say I'm baffled by this 
                    msgflag = True
                continue
-           if aaitem < 0:
+           if scanner.real < 0:
                # abort out 
-               chew()
+               scanner.chew()
                return
-           hits[k] = aaitem
-           rpow += aaitem
+           hits[k] = scanner.real
+           rpow += scanner.real
            # If total requested is too much, inform and start over 
             if rpow > avail:
                prout(_("Available energy exceeded -- try again."))
-               chew()
+               scanner.chew()
                return
-           key = scan(); # scan for next value 
+           key = scanner.next(); # scan for next value 
            k += 1
        if rpow == 0.0:
            # zero energy -- abort 
-           chew()
+           scanner.chew()
            return
-       if key == IHALPHA and isit("no"):
+       if key == IHALPHA and scanner.sees("no"):
            no = True
        game.energy -= rpow
-       chew()
+       scanner.chew()
        if ifast:
            game.energy -= 200.0
            if checkshctrl(rpow):
@@ -2366,7 +2373,7 @@ def events():
             game.battle = hold
             game.isatb = 0
         else:
-            invalidate(game.battle)
+            game.battle.invalidate()
 
     if idebug:
        prout("=== EVENTS from %.2f to %.2f:" % (game.state.date, fintim))
@@ -2463,7 +2470,7 @@ def events():
                  (game.torps < 5 or damaged(DPHOTON))):
                # Tractor-beam her! 
                istract = ictbeam = True
-                tractorbeam(distance(game.state.kscmdr, game.quadrant))
+                tractorbeam((game.state.kscmdr-game.quadrant).distance())
            else:
                return
        elif evcode == FTBEAM: # Tractor beam 
@@ -2471,7 +2478,7 @@ def events():
                 unschedule(FTBEAM)
                 continue
             i = randrange(game.state.remcom)
-            yank = distance(game.state.kcmdr[i], game.quadrant)
+            yank = (game.state.kcmdr[i]-game.quadrant).distance()
             if istract or game.condition == "docked" or yank == 0:
                 # Drats! Have to reschedule 
                 schedule(FTBEAM, 
@@ -2538,7 +2545,7 @@ def events():
                if i > game.state.remcom or game.state.rembase == 0 or \
                    not game.state.galaxy[game.battle.x][game.battle.y].starbase:
                    # No action to take after all 
-                   invalidate(game.battle)
+                   game.battle.invalidate()
                    continue
             destroybase()
        elif evcode == FSCMOVE: # Supercommander moves 
@@ -2690,18 +2697,18 @@ def wait():
     # wait on events 
     game.ididit = False
     while True:
-       key = scan()
+       key = scanner.next()
        if key  != IHEOL:
            break
        proutn(_("How long? "))
-    chew()
+    scanner.chew()
     if key != IHREAL:
        huh()
        return
-    origTime = delay = aaitem
+    origTime = delay = scanner.real
     if delay <= 0.0:
        return
-    if delay >= game.state.remtime or game.nenhere != 0:
+    if delay >= game.state.remtime or len(game.enemies) != 0:
        proutn(_("Are you sure? "))
        if ja() == False:
            return
@@ -2714,7 +2721,7 @@ def wait():
            prout(_("%d stardates left.") % int(game.state.remtime))
            return
        temp = game.optime = delay
-       if game.nenhere:
+       if len(game.enemies):
            rtime = randreal(1.0, 2.0)
            if rtime < temp:
                temp = rtime
@@ -2798,7 +2805,7 @@ def nova(nov):
                     prout(_(" destroyed."))
                     game.iplnet.pclass = "destroyed"
                     game.iplnet = None
-                    invalidate(game.plnet)
+                    game.plnet.invalidate()
                     if game.landed:
                         finish(FPNOVA)
                         return
@@ -2810,7 +2817,7 @@ def nova(nov):
                             break
                     game.state.baseq[i] = game.state.baseq[game.state.rembase]
                     game.state.rembase -= 1
-                    invalidate(game.base)
+                    game.base.invalidate()
                     game.state.basekl += 1
                     newcnd()
                     crmena(True, IHB, "sector", neighbor)
@@ -2838,7 +2845,7 @@ def nova(nov):
                 elif iquad == IHK: # kill klingon 
                     deadkl(neighbor, iquad, neighbor)
                 elif iquad in (IHC,IHS,IHR): # Damage/destroy big enemies 
-                    for ll in range(game.nenhere):
+                    for ll in range(len(game.enemies)):
                         if game.enemies[ll].kloc == neighbor:
                             break
                     game.enemies[ll].kpower -= 800.0 # If firepower is lost, die 
@@ -2931,13 +2938,12 @@ def supernova(induced, w=None):
        prouts(_("***RED ALERT!  RED ALERT!"))
        skip(1)
        prout(_("***Incipient supernova detected at Sector %s") % ns)
-       if square(ns.x-game.sector.x) + square(ns.y-game.sector.y) <= 2.1:
+       if (ns.x-game.sector.x)**2 + (ns.y-game.sector.y)**2 <= 2.1:
            proutn(_("Emergency override attempts t"))
            prouts("***************")
            skip(1)
            stars()
            game.alldone = True
-
     # destroy any Klingons in supernovaed quadrant 
     kldead = game.state.galaxy[nq.x][nq.y].klingons
     game.state.galaxy[nq.x][nq.y].klingons = 0
@@ -2947,17 +2953,13 @@ def supernova(induced, w=None):
        game.iscate = False
        unschedule(FSCMOVE)
        unschedule(FSCDBAS)
-    if game.state.remcom:
-       maxloop = game.state.remcom
-       for l in range(maxloop):
-           if game.state.kcmdr[l] == nq:
-               game.state.kcmdr[l] = game.state.kcmdr[game.state.remcom]
-               invalidate(game.state.kcmdr[game.state.remcom])
-               game.state.remcom -= 1
-               kldead -= 1
-               if game.state.remcom==0:
-                   unschedule(FTBEAM)
-               break
+    survivors = filter(lambda w: w != nq, game.state.kcmdr)
+    comkills = len(game.state.kcmdr) - len(survivors)
+    game.state.kcmdr = survivors
+    kldead -= comkills
+    game.state.remcom -= comkills
+    if game.state.remcom==0:
+        unschedule(FTBEAM)
     game.state.remkl -= kldead
     # destroy Romulans and planets in supernovaed quadrant 
     nrmdead = game.state.galaxy[nq.x][nq.y].romulans
@@ -2968,15 +2970,9 @@ def supernova(induced, w=None):
        if game.state.planets[loop].w == nq:
            game.state.planets[loop].pclass = "destroyed"
            npdead += 1
-    # Destroy any base in supernovaed quadrant 
-    if game.state.rembase:
-       maxloop = game.state.rembase
-       for loop in range(maxloop):
-           if game.state.baseq[loop] == nq:
-               game.state.baseq[loop] = game.state.baseq[game.state.rembase]
-               invalidate(game.state.baseq[game.state.rembase])
-               game.state.rembase -= 1
-               break
+    # Destroy any base in supernovaed quadrant
+    game.state.baseq = filter(lambda x: x != nq, game.state.baseq)
+    game.state.rembase = len(game.state.baseq)
     # If starship caused supernova, tally up destruction 
     if induced:
        game.state.starkl += game.state.galaxy[nq.x][nq.y].stars
@@ -3003,7 +2999,7 @@ def supernova(induced, w=None):
 def selfdestruct():
     # self-destruct maneuver 
     # Finish with a BANG! 
-    chew()
+    scanner.chew()
     if damaged(DCOMPTR):
        prout(_("Computer damaged; cannot execute destruct sequence."))
        return
@@ -3021,9 +3017,9 @@ def selfdestruct():
     skip(1)
     prout(_("SELF-DESTRUCT-SEQUENCE-WILL-BE-ABORTED"))
     skip(1)
-    scan()
-    chew()
-    if game.passwd != citem:
+    scanner.next()
+    scanner.chew()
+    if game.passwd != scanner.token:
        prouts(_("PASSWORD-REJECTED;"))
        skip(1)
        prouts(_("CONTINUITY-EFFECTED"))
@@ -3050,10 +3046,10 @@ def kaboom():
     skip(1)
     stars()
     skip(1)
-    if game.nenhere != 0:
+    if len(game.enemies) != 0:
        whammo = 25.0 * game.energy
        l=1
-       while l <= game.nenhere:
+       while l <= len(game.enemies):
            if game.enemies[l].kpower*game.enemies[l].kdist <= whammo: 
                deadkl(game.enemies[l].kloc, game.quad[game.enemies[l].kloc.x][game.enemies[l].kloc.y], game.enemies[l].kloc)
            l += 1
@@ -3141,7 +3137,7 @@ def finish(ifin):
                        prout(_("You cannot get a citation, so..."))
                    else:
                        proutn(_("Do you want your Commodore Emeritus Citation printed? "))
-                       chew()
+                       scanner.chew()
                        if ja() == True:
                            igotit = True
            # Only grant long life if alive (original didn't!)
@@ -3702,13 +3698,13 @@ def warble():
        #nosound()
         pass
 
-def tracktorpedo(w, step, i, n, iquad):
+def tracktorpedo(origin, w, step, i, n, iquad):
     "Torpedo-track animation." 
     if not game.options & OPTION_CURSES:
        if step == 1:
            if n != 1:
                skip(1)
-               proutn(_("Track for torpedo number %d-  ") % i)
+               proutn(_("Track for %s torpedo number %d-  ") % (game.quad[origin.x][origin.y],i+1))
            else:
                skip(1)
                proutn(_("Torpedo track- "))
@@ -3770,16 +3766,16 @@ def imove(novapush):
     def no_quad_change():
         # No quadrant change -- compute new average enemy distances 
         game.quad[game.sector.x][game.sector.y] = game.ship
-        if game.nenhere:
-            for m in range(game.nenhere):
-                finald = distance(w, game.enemies[m].kloc)
-                game.enemies[m].kavgd = 0.5 * (finald+game.enemies[m].kdist)
-                game.enemies[m].kdist = finald
+        if game.enemies:
+            for enemy in game.enemies:
+                finald = (w-game.enemy.kloc).distance()
+                enemy.kavgd = 0.5 * (finald + ememy.kdist)
+                enemy.kdist = finald
             game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
             if not game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova:
                 attack(torps_ok=False)
-            for m in range(game.nenhere):
-                game.enemies[m].kavgd = game.enemies[m].kdist
+            for enemy in game.enemies:
+                enemy.kavgd = enemy.kdist
         newcnd()
         drawmaps(0)
         setwnd(message_window)
@@ -3816,11 +3812,11 @@ def imove(novapush):
            if not VALID_SECTOR(w.x, w.y):
                # Leaving quadrant -- allow final enemy attack 
                # Don't do it if being pushed by Nova 
-               if game.nenhere != 0 and not novapush:
+               if len(game.enemies) != 0 and not novapush:
                    newcnd()
-                   for m in range(game.nenhere):
-                       finald = distance(w, game.enemies[m].kloc)
-                       game.enemies[m].kavgd = 0.5 * (finald + game.enemies[m].kdist)
+                   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
@@ -3883,7 +3879,7 @@ def imove(novapush):
            if iquad != IHDOT:
                # object encountered in flight path 
                stopegy = 50.0*game.dist/game.optime
-               game.dist = distance(game.sector, w) / (QUADSIZE * 1.0)
+               game.dist = (game.sector - w).distance() / (QUADSIZE * 1.0)
                 if iquad in (IHT, IHK, IHC, IHS, IHR, IHQUEST):
                    game.sector = w
                     for enemy in game.enemies:
@@ -3933,7 +3929,7 @@ def imove(novapush):
                 # We're here!
                no_quad_change()
                 return
-       game.dist = distance(game.sector, w) / (QUADSIZE * 1.0)
+       game.dist = (game.sector - w).distance() / (QUADSIZE * 1.0)
        game.sector = w
     final = game.sector
     no_quad_change()
@@ -3941,14 +3937,14 @@ def imove(novapush):
 
 def dock(verbose):
     # dock our ship at a starbase 
-    chew()
+    scanner.chew()
     if game.condition == "docked" and verbose:
        prout(_("Already docked."))
        return
     if game.inorbit:
        prout(_("You must first leave standard orbit."))
        return
-    if not is_valid(game.base) or abs(game.sector.x-game.base.x) > 1 or abs(game.sector.y-game.base.y) > 1:
+    if not game.base.is_valid() or abs(game.sector.x-game.base.x) > 1 or abs(game.sector.y-game.base.y) > 1:
        crmshp()
        prout(_(" not adjacent to base."))
        return
@@ -3988,7 +3984,7 @@ def getcourse(isprobe, akey):
     if game.landed and not isprobe:
        prout(_("Dummy! You can't leave standard orbit until you"))
        proutn(_("are back aboard the ship."))
-       chew()
+       scanner.chew()
        return False
     while navmode == "unspecified":
        if damaged(DNAVSYS):
@@ -3996,7 +3992,7 @@ def getcourse(isprobe, akey):
                prout(_("Computer damaged; manual navigation only"))
            else:
                prout(_("Computer damaged; manual movement only"))
-           chew()
+           scanner.chew()
            navmode = "manual"
            key = IHEOL
            break
@@ -4005,23 +4001,23 @@ def getcourse(isprobe, akey):
            key = akey
            akey = -1
        else: 
-           key = scan()
+           key = scanner.next()
        if key == IHEOL:
            proutn(_("Manual or automatic- "))
            iprompt = True
-           chew()
+           scanner.chew()
        elif key == IHALPHA:
-            if isit("manual"):
+            if scanner.sees("manual"):
                navmode = "manual"
-               key = scan()
+               key = scanner.next()
                break
-            elif isit("automatic"):
+            elif scanner.sees("automatic"):
                navmode = "automatic"
-               key = scan()
+               key = scanner.next()
                break
            else:
                huh()
-               chew()
+               scanner.chew()
                return False
        else: # numeric 
            if isprobe:
@@ -4036,27 +4032,27 @@ def getcourse(isprobe, akey):
                proutn(_("Target quadrant or quadrant&sector- "))
            else:
                proutn(_("Destination sector or quadrant&sector- "))
-           chew()
+           scanner.chew()
            iprompt = True
-           key = scan()
+           key = scanner.next()
        if key != IHREAL:
            huh()
            return False
-       xi = int(round(aaitem))-1
-       key = scan()
+       xi = int(round(scanner.real))-1
+       key = scanner.next()
        if key != IHREAL:
            huh()
            return False
-       xj = int(round(aaitem))-1
-       key = scan()
+       xj = int(round(scanner.real))-1
+       key = scanner.next()
        if key == IHREAL:
            # both quadrant and sector specified 
-           xk = int(round(aaitem))-1
-           key = scan()
+           xk = int(round(scanner.real))-1
+           key = scanner.next()
            if key != IHREAL:
                huh()
                return False
-           xl = int(round(aaitem))-1
+           xl = int(round(scanner.real))-1
            dquad.x = xi
            dquad.y = xj
            dsect.y = xk
@@ -4089,22 +4085,22 @@ def getcourse(isprobe, akey):
     else: # manual 
        while key == IHEOL:
            proutn(_("X and Y displacements- "))
-           chew()
+           scanner.chew()
            iprompt = True
-           key = scan()
+           key = scanner.next()
        itemp = "verbose"
        if key != IHREAL:
            huh()
            return False
-       deltax = aaitem
-       key = scan()
+       deltax = scanner.real
+       key = scanner.next()
        if key != IHREAL:
            huh()
            return False
-       deltay = aaitem
+       deltay = scanner.real
     # Check for zero movement 
     if deltax == 0 and deltay == 0:
-       chew()
+       scanner.chew()
        return False
     if itemp == "verbose" and not isprobe:
        skip(1)
@@ -4114,14 +4110,14 @@ def getcourse(isprobe, akey):
     game.direc = math.atan2(deltax, deltay)*1.90985932
     if game.direc < 0.0:
        game.direc += 12.0
-    chew()
+    scanner.chew()
     return True
 
 def impulse():
     # move under impulse power 
     game.ididit = False
     if damaged(DIMPULS):
-       chew()
+       scanner.chew()
        skip(1)
        prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
        return
@@ -4142,7 +4138,7 @@ def impulse():
            prout(_(" quadrants.\""))
        else:
            prout(_("quadrant.  They are, therefore, useless.\""))
-       chew()
+       scanner.chew()
        return
     # Make sure enough time is left for the trip 
     game.optime = game.dist/0.095
@@ -4170,12 +4166,12 @@ def warp(timewarp):
     if not timewarp: # Not WARPX entry 
        game.ididit = False
        if game.damage[DWARPEN] > 10.0:
-           chew()
+           scanner.chew()
            skip(1)
            prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
            return
        if damaged(DWARPEN) and game.warpfac > 4.0:
-           chew()
+           scanner.chew()
            skip(1)
            prout(_("Engineer Scott- \"Sorry, Captain. Until this damage"))
            prout(_("  is repaired, I can only give you warp 4.\""))
@@ -4222,7 +4218,7 @@ def warp(timewarp):
     if game.warpfac > 6.0:
        # Decide if engine damage will occur
         # ESR: Seems wrong. Probability of damage goes *down* with distance? 
-       prob = game.dist*square(6.0-game.warpfac)/66.666666666
+       prob = game.dist*(6.0-game.warpfac)**2/66.666666666
        if prob > randreal():
            blooey = True
            game.dist = randreal(game.dist)
@@ -4282,30 +4278,30 @@ def warp(timewarp):
 def setwarp():
     # change the warp factor   
     while True:
-        key=scan()
+        key=scanner.next()
         if key != IHEOL:
             break
-       chew()
+       scanner.chew()
        proutn(_("Warp factor- "))
-    chew()
+    scanner.chew()
     if key != IHREAL:
        huh()
        return
     if game.damage[DWARPEN] > 10.0:
        prout(_("Warp engines inoperative."))
        return
-    if damaged(DWARPEN) and aaitem > 4.0:
+    if damaged(DWARPEN) and scanner.real > 4.0:
        prout(_("Engineer Scott- \"I'm doing my best, Captain,"))
        prout(_("  but right now we can only go warp 4.\""))
        return
-    if aaitem > 10.0:
+    if scanner.real > 10.0:
        prout(_("Helmsman Sulu- \"Our top speed is warp 10, Captain.\""))
        return
-    if aaitem < 1.0:
+    if scanner.real < 1.0:
        prout(_("Helmsman Sulu- \"We can't go below warp 1, Captain.\""))
        return
     oldfac = game.warpfac
-    game.warpfac = aaitem
+    game.warpfac = scanner.real
     game.wfacsq=game.warpfac*game.warpfac
     if game.warpfac <= oldfac or game.warpfac <= 6.0:
        prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\"") %
@@ -4322,7 +4318,7 @@ def setwarp():
 
 def atover(igrab):
     # cope with being tossed out of quadrant by supernova or yanked by beam 
-    chew()
+    scanner.chew()
     # is captain on planet? 
     if game.landed:
        if damaged(DTRANSP):
@@ -4424,7 +4420,7 @@ def timwrp():
        game.isatb = 0
        unschedule(FCDBAS)
        unschedule(FSCDBAS)
-       invalidate(game.battle)
+       game.battle.invalidate()
 
        # Make sure Galileo is consistant -- Snapshot may have been taken
         # when on planet, which would give us two Galileos! 
@@ -4459,7 +4455,7 @@ def probe():
     # launch deep-space probe 
     # New code to launch a deep space probe 
     if game.nprobes == 0:
-       chew()
+       scanner.chew()
        skip(1)
        if game.ship == IHE: 
            prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\""))
@@ -4467,12 +4463,12 @@ def probe():
            prout(_("Ye Faerie Queene has no deep space probes."))
        return
     if damaged(DDSP):
-       chew()
+       scanner.chew()
        skip(1)
        prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\""))
        return
     if is_scheduled(FDSPROB):
-       chew()
+       scanner.chew()
        skip(1)
        if damaged(DRADIO) and game.condition != "docked":
            prout(_("Spock-  \"Records show the previous probe has not yet"))
@@ -4480,7 +4476,7 @@ def probe():
        else:
            prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""))
        return
-    key = scan()
+    key = scanner.next()
     if key == IHEOL:
        # slow mode, so let Kirk know how many probes there are left
         if game.nprobes == 1:
@@ -4491,9 +4487,9 @@ def probe():
        if ja() == False:
            return
     game.isarmed = False
-    if key == IHALPHA and citem == "armed":
+    if key == IHALPHA and scanner.token == "armed":
        game.isarmed = True
-       key = scan()
+       key = scanner.next()
     elif key == IHEOL:
        proutn(_("Arm NOVAMAX warhead? "))
        game.isarmed = ja()
@@ -4539,7 +4535,7 @@ def mayday():
     # yell for help from nearest starbase 
     # There's more than one way to move in this game! 
     line = 0
-    chew()
+    scanner.chew()
     # Test for conditions which prevent calling for help 
     if game.condition == "docked":
        prout(_("Lt. Uhura-  \"But Captain, we're already docked.\""))
@@ -4559,11 +4555,11 @@ def mayday():
     game.nhelp += 1
     if game.base.x!=0:
        # There's one in this quadrant 
-       ddist = distance(game.base, game.sector)
+       ddist = (game.base - game.sector).distance()
     else:
        ddist = FOREVER
        for m in range(game.state.rembase):
-           xdist = QUADSIZE * distance(game.state.baseq[m], game.quadrant)
+           xdist = QUADSIZE * (game.state.baseq[m] - game.quadrant).distance()
            if xdist < ddist:
                ddist = xdist
                line = m
@@ -4582,7 +4578,7 @@ def mayday():
            # found one -- finish up 
             game.sector = w
            break
-    if not is_valid(game.sector):
+    if not game.sector.is_valid():
        prout(_("You have been lost in space..."))
        finish(FMATERIALIZE)
        return
@@ -4637,7 +4633,7 @@ def mayday():
 
 def abandon():
     # abandon ship 
-    chew()
+    scanner.chew()
     if game.condition=="docked":
        if game.ship!=IHE:
            prout(_("You cannot abandon Ye Faerie Queene."))
@@ -4747,7 +4743,7 @@ def survey():
     # report on (uninhabited) planets in the galaxy 
     iknow = False
     skip(1)
-    chew()
+    scanner.chew()
     prout(_("Spock-  \"Planet report follows, Captain.\""))
     skip(1)
     for i in range(game.inplan):
@@ -4774,14 +4770,14 @@ def survey():
 def orbit():
     # enter standard orbit 
     skip(1)
-    chew()
+    scanner.chew()
     if game.inorbit:
        prout(_("Already in standard orbit."))
        return
     if damaged(DWARPEN) and damaged(DIMPULS):
        prout(_("Both warp and impulse engines damaged."))
        return
-    if not is_valid(game.plnet) or abs(game.sector.x-game.plnet.x) > 1 or abs(game.sector.y-game.plnet.y) > 1:
+    if not game.plnet.is_valid() or abs(game.sector.x-game.plnet.x) > 1 or abs(game.sector.y-game.plnet.y) > 1:
        crmshp()
        prout(_(" not adjacent to planet."))
        skip(1)
@@ -4826,7 +4822,7 @@ def sensor():
 def beam():
     # use the transporter 
     nrgneed = 0
-    chew()
+    scanner.chew()
     skip(1)
     if damaged(DTRANSP):
        prout(_("Transporter damaged."))
@@ -4853,7 +4849,7 @@ def beam():
        prout(_("  exploring a planet with no dilithium crystals."))
        proutn(_("  Are you sure this is wise?\" "))
        if ja() == False:
-           chew()
+           scanner.chew()
            return
     if not (game.options & OPTION_PLAIN):
        nrgneed = 50 * game.skill + game.height / 100.0
@@ -4869,14 +4865,14 @@ def beam():
                prout(_("  Although the Galileo shuttle craft may still be on a surface."))
            proutn(_("  Are you sure this is wise?\" "))
            if ja() == False:
-               chew()
+               scanner.chew()
                return
     if game.landed:
        # Coming from planet 
        if game.iplnet.known=="shuttle_down":
            proutn(_("Spock-  \"Wouldn't you rather take the Galileo?\" "))
            if ja() == True:
-               chew()
+               scanner.chew()
                return
            prout(_("Your crew hides the Galileo to prevent capture by aliens."))
        prout(_("Landing party assembled, ready to beam up."))
@@ -4918,7 +4914,7 @@ def beam():
 def mine():
     # strip-mine a world for dilithium 
     skip(1)
-    chew()
+    scanner.chew()
     if not game.landed:
        prout(_("Mining party not on planet."))
        return
@@ -4948,7 +4944,7 @@ def usecrystals():
     # use dilithium crystals 
     game.ididit = False
     skip(1)
-    chew()
+    scanner.chew()
     if not game.icrystl:
        prout(_("No dilithium crystals available."))
        return
@@ -4961,7 +4957,7 @@ def usecrystals():
     prout(_("  system may risk a severe explosion."))
     proutn(_("  Are you sure this is wise?\" "))
     if ja() == False:
-       chew()
+       scanner.chew()
        return
     skip(1)
     prout(_("Engineering Officer Scott-  \"(GULP) Aye Sir."))
@@ -4992,7 +4988,7 @@ def usecrystals():
 
 def shuttle():
     # use shuttlecraft for planetary jaunt 
-    chew()
+    scanner.chew()
     skip(1)
     if damaged(DSHUTTL):
        if game.damage[DSHUTTL] == -1.0:
@@ -5096,11 +5092,11 @@ def deathray():
     # use the big zapper 
     game.ididit = False
     skip(1)
-    chew()
+    scanner.chew()
     if game.ship != IHE:
        prout(_("Ye Faerie Queene has no death ray."))
        return
-    if game.nenhere==0:
+    if len(game.enemies)==0:
        prout(_("Sulu-  \"But Sir, there are no enemies in this quadrant.\""))
        return
     if damaged(DDRAY):
@@ -5132,7 +5128,7 @@ def deathray():
     if r > dprob:
        prouts(_("Sulu- \"Captain!  It's working!\""))
        skip(2)
-       while game.nenhere > 0:
+       while len(game.enemies) > 0:
            deadkl(game.enemies[1].kloc, game.quad[game.enemies[1].kloc.x][game.enemies[1].kloc.y],game.enemies[1].kloc)
        prout(_("Ensign Chekov-  \"Congratulations, Captain!\""))
        if (game.state.remkl + game.state.remcom + game.state.nscrem) == 0:
@@ -5217,7 +5213,7 @@ def attackreport(curt):
 
 def report():
     # report on general game status 
-    chew()
+    scanner.chew()
     s1 = "" and game.thawed and _("thawed ")
     s2 = {1:"short", 2:"medium", 4:"long"}[game.length]
     s3 = (None, _("novice"). _("fair"),
@@ -5319,7 +5315,7 @@ def lrscan(silent):
 def damagereport():
     # damage report 
     jdam = False
-    chew()
+    scanner.chew()
 
     for i in range(NDEVICES):
        if damaged(i):
@@ -5345,7 +5341,7 @@ def rechart():
 
 def chart():
     # display the star chart  
-    chew()
+    scanner.chew()
     if (game.options & OPTION_AUTOSCAN):
         lrscan(silent=True)
     if not damaged(DRADIO):
@@ -5457,11 +5453,11 @@ def status(req=0):
 
 def request():
     requests = ("da","co","po","ls","wa","en","to","sh","kl","sy", "ti")
-    while scan() == IHEOL:
+    while scanner.next() == IHEOL:
        proutn(_("Information desired? "))
-    chew()
-    if citem in requests:
-        status(requests.index(citem))
+    scanner.chew()
+    if scanner.token in requests:
+        status(requests.index(scanner.token))
     else:
        prout(_("UNRECOGNIZED REQUEST. Legal requests are:"))
        prout(("  date, condition, position, lsupport, warpfactor,"))
@@ -5493,7 +5489,6 @@ def srscan():
            sectscan(goodScan, i, j)
        skip(1)
                        
-                       
 def eta():
     # use computer to get estimated time of arrival for a warp jump 
     w1 = coord(); w2 = coord()
@@ -5502,24 +5497,24 @@ def eta():
        prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR."))
        skip(1)
        return
-    if scan() != IHREAL:
+    if scanner.next() != IHREAL:
        prompt = True
-       chew()
+       scanner.chew()
        proutn(_("Destination quadrant and/or sector? "))
-       if scan()!=IHREAL:
+       if scanner.next()!=IHREAL:
            huh()
            return
-    w1.y = int(aaitem-0.5)
-    if scan() != IHREAL:
+    w1.y = int(scanner.real-0.5)
+    if scanner.next() != IHREAL:
        huh()
        return
-    w1.x = int(aaitem-0.5)
-    if scan() == IHREAL:
-       w2.y = int(aaitem-0.5)
-       if scan() != IHREAL:
+    w1.x = int(scanner.real-0.5)
+    if scanner.next() == IHREAL:
+       w2.y = int(scanner.real-0.5)
+       if scanner.next() != IHREAL:
            huh()
            return
-       w2.x = int(aaitem-0.5)
+       w2.x = int(scanner.real-0.5)
     else:
        if game.quadrant.y>w1.x:
            w2.x = 0
@@ -5532,39 +5527,39 @@ def eta():
     if not VALID_QUADRANT(w1.x, w1.y) or not VALID_SECTOR(w2.x, w2.y):
        huh()
        return
-    game.dist = math.sqrt(square(w1.y-game.quadrant.y+0.1*(w2.y-game.sector.y))+
-               square(w1.x-game.quadrant.x+0.1*(w2.x-game.sector.x)))
+    game.dist = math.sqrt((w1.y-game.quadrant.y+0.1*(w2.y-game.sector.y))**2+
+               (w1.x-game.quadrant.x+0.1*(w2.x-game.sector.x))**2)
     wfl = False
     if prompt:
        prout(_("Answer \"no\" if you don't know the value:"))
     while True:
-       chew()
+       scanner.chew()
        proutn(_("Time or arrival date? "))
-       if scan()==IHREAL:
-           ttime = aaitem
+       if scanner.next()==IHREAL:
+           ttime = scanner.real
            if ttime > game.state.date:
                ttime -= game.state.date # Actually a star date
             twarp=(math.floor(math.sqrt((10.0*game.dist)/ttime)*10.0)+1.0)/10.0
             if ttime <= 1e-10 or twarp > 10:
                prout(_("We'll never make it, sir."))
-               chew()
+               scanner.chew()
                return
            if twarp < 1.0:
                twarp = 1.0
            break
-       chew()
+       scanner.chew()
        proutn(_("Warp factor? "))
-       if scan()== IHREAL:
+       if scanner.next()== IHREAL:
            wfl = True
-           twarp = aaitem
+           twarp = scanner.real
            if twarp<1.0 or twarp > 10.0:
                huh()
                return
            break
        prout(_("Captain, certainly you can give me one of these."))
     while True:
-       chew()
-       ttime = (10.0*game.dist)/square(twarp)
+       scanner.chew()
+       ttime = (10.0*game.dist)/twarp**2
        tpower = game.dist*twarp*twarp*twarp*(game.shldup+1)
        if tpower >= game.energy:
            prout(_("Insufficient energy, sir."))
@@ -5572,15 +5567,15 @@ def eta():
                if not wfl:
                    return
                proutn(_("New warp factor to try? "))
-               if scan() == IHREAL:
+               if scanner.next() == IHREAL:
                    wfl = True
-                   twarp = aaitem
+                   twarp = scanner.real
                    if twarp<1.0 or twarp > 10.0:
                        huh()
                        return
                    continue
                else:
-                   chew()
+                   scanner.chew()
                    skip(1)
                    return
            prout(_("But if you lower your shields,"))
@@ -5605,14 +5600,14 @@ def eta():
            (scheduled(FCDBAS)<ttime+game.state.date and game.battle == w1):
            prout(_("The starbase there will be destroyed by then."))
        proutn(_("New warp factor to try? "))
-       if scan() == IHREAL:
+       if scanner.next() == IHREAL:
            wfl = True
-           twarp = aaitem
+           twarp = scanner.real
            if twarp<1.0 or twarp > 10.0:
                huh()
                return
        else:
-           chew()
+           scanner.chew()
            skip(1)
            return
                        
@@ -5631,22 +5626,22 @@ def prelim():
 def freeze(boss):
     # save game 
     if boss:
-       citem = "emsave.trk"
+       scanner.token = "emsave.trk"
     else:
-        key = scan()
+        key = scanner.next()
        if key == IHEOL:
            proutn(_("File name: "))
-           key = scan()
+           key = scanner.next()
        if key != IHALPHA:
            huh()
            return
-       chew()
-        if '.' not in citem:
-           citem += ".trk"
+       scanner.chew()
+        if '.' not in scanner.token:
+           scanner.token += ".trk"
     try:
-        fp = open(citem, "wb")
+        fp = open(scanner.token, "wb")
     except IOError:
-       prout(_("Can't freeze game as file %s") % citem)
+       prout(_("Can't freeze game as file %s") % scanner.token)
        return
     cPickle.dump(game, fp)
     fp.close()
@@ -5654,20 +5649,20 @@ def freeze(boss):
 def thaw():
     # retrieve saved game 
     game.passwd[0] = '\0'
-    key = scan()
+    key = scanner.next()
     if key == IHEOL:
        proutn(_("File name: "))
-       key = scan()
+       key = scanner.next()
     if key != IHALPHA:
        huh()
        return True
-    chew()
-    if '.' not in citem:
-        citem += ".trk"
+    scanner.chew()
+    if '.' not in scanner.token:
+        scanner.token += ".trk"
     try:
-        fp = open(citem, "rb")
+        fp = open(scanner.token, "rb")
     except IOError:
-       prout(_("Can't thaw game in %s") % citem)
+       prout(_("Can't thaw game in %s") % scanner.token)
        return
     game = cPickle.load(fp)
     fp.close()
@@ -5744,11 +5739,11 @@ device = (
        _("D. S. Probe"), \
 )
 
-def setup(needprompt):
+def setup():
     # prepare to play, set up cosmos 
     w = coord()
     #  Decide how many of everything
-    if choose(needprompt):
+    if choose():
        return # frozen game
     # Prepare the Enterprise
     game.alldone = game.gamewon = False
@@ -5828,7 +5823,7 @@ def setup(needprompt):
             # so it did them in the opposite order.
             for j in range(1, i):
                # Improved placement algorithm to spread out bases
-               distq = w.distance(game.state.baseq[j])
+               distq = (w - game.state.baseq[j]).distance()
                if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75):
                    contflag = True
                    if idebug:
@@ -5862,7 +5857,7 @@ def setup(needprompt):
         if krem <= 0:
             break
     # Position Klingon Commander Ships
-    for i in range(1, game.incom+1):
+    for i in range(game.incom):
         while True:
             w = randplace(GALSIZE)
            if (game.state.galaxy[w.x][w.y].klingons or withprob(0.25)) and \
@@ -5944,12 +5939,12 @@ def setup(needprompt):
        prout(_("  YOU'LL NEED IT."))
     waitfor()
     newqad(False)
-    if game.nenhere - (thing == game.quadrant) - (game.tholian != None):
+    if len(game.enemies) - (thing == game.quadrant) - (game.tholian != None):
        game.shldup = True
     if game.neutz:     # bad luck to start in a Romulan Neutral Zone
        attack(torps_ok=False)
 
-def choose(needprompt):
+def choose():
     # choose your game type
     global thing
     while True:
@@ -5957,26 +5952,26 @@ def choose(needprompt):
        game.thawed = False
        game.skill = SKILL_NONE
        game.length = 0
-       if needprompt: # Can start with command line options 
+       if not scanner.inqueue: # Can start with command line options 
            proutn(_("Would you like a regular, tournament, or saved game? "))
-       scan()
-       if len(citem)==0: # Try again
+        scanner.next()
+       if len(scanner.token)==0: # Try again
            continue
-        if isit("tournament"):
-           while scan() == IHEOL:
+        if scanner.sees("tournament"):
+           while scanner.next() == IHEOL:
                proutn(_("Type in tournament number-"))
-           if aaitem == 0:
-               chew()
+           if scanner.real == 0:
+               scanner.chew()
                continue # We don't want a blank entry
-           game.tourn = int(round(aaitem))
-           random.seed(aaitem)
+           game.tourn = int(round(scanner.real))
+           random.seed(scanner.real)
             if logfp:
-                logfp.write("# random.seed(%d)\n" % aaitem)
+                logfp.write("# random.seed(%d)\n" % scanner.real)
            break
-        if isit("saved") or isit("frozen"):
+        if scanner.sees("saved") or scanner.sees("frozen"):
            if thaw():
                continue
-           chew()
+           scanner.chew()
            if game.passwd == None:
                continue
            if not game.alldone:
@@ -5984,55 +5979,55 @@ def choose(needprompt):
            report()
            waitfor()
            return True
-        if isit("regular"):
+        if scanner.sees("regular"):
            break
-       proutn(_("What is \"%s\"?"), citem)
-       chew()
+       proutn(_("What is \"%s\"?") % scanner.token)
+       scanner.chew()
     while game.length==0 or game.skill==SKILL_NONE:
-       if scan() == IHALPHA:
-            if isit("short"):
+       if scanner.next() == IHALPHA:
+            if scanner.sees("short"):
                game.length = 1
-           elif isit("medium"):
+           elif scanner.sees("medium"):
                game.length = 2
-           elif isit("long"):
+           elif scanner.sees("long"):
                game.length = 4
-           elif isit("novice"):
+           elif scanner.sees("novice"):
                game.skill = SKILL_NOVICE
-           elif isit("fair"):
+           elif scanner.sees("fair"):
                game.skill = SKILL_FAIR
-           elif isit("good"):
+           elif scanner.sees("good"):
                game.skill = SKILL_GOOD
-           elif isit("expert"):
+           elif scanner.sees("expert"):
                game.skill = SKILL_EXPERT
-           elif isit("emeritus"):
+           elif scanner.sees("emeritus"):
                game.skill = SKILL_EMERITUS
            else:
                proutn(_("What is \""))
-               proutn(citem)
+               proutn(scanner.token)
                prout("\"?")
        else:
-           chew()
+           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 scan() != IHALPHA:
-       chew()
+    if scanner.next() != IHALPHA:
+       scanner.chew()
        proutn(_("Choose your game style (or just press enter): "))
-       scan()
-    if isit("plain"):
+       scanner.next()
+    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_PLAIN
-    elif isit("almy"):
+    elif scanner.sees("almy"):
        # Approximates Tom Almy's version.
        game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
        game.options |= OPTION_ALMY
-    elif isit("fancy"):
+    elif scanner.sees("fancy"):
        pass
-    elif len(citem):
-        proutn(_("What is \"%s\"?") % citem)
+    elif len(scanner.token):
+        proutn(_("What is \"%s\"?") % scanner.token)
     setpassword()
     if game.passwd == "debug":
        idebug = True
@@ -6096,12 +6091,13 @@ def newqad(shutup):
     game.ishere = False
     game.irhere = 0
     game.iplnet = 0
-    game.nenhere = 0
     game.neutz = False
     game.inorbit = False
     game.landed = False
     game.ientesc = False
     game.iseenit = False
+    # Create a blank quadrant
+    game.quad = fill2d(QUADSIZE, lambda i, j: IHDOT)
     if game.iscate:
        # Attempt to escape Super-commander, so tbeam back!
        game.iscate = False
@@ -6112,7 +6108,6 @@ def newqad(shutup):
        return
     game.klhere = q.klingons
     game.irhere = q.romulans
-    game.nenhere = game.klhere + game.irhere
     # Position Starship
     game.quad[game.sector.x][game.sector.y] = game.ship
     game.enemies = []
@@ -6136,7 +6131,7 @@ def newqad(shutup):
            game.iscate = (game.state.remkl > 1)
            game.ishere = True
     # Put in Romulans if needed
-    for i in range(game.klhere, game.nenhere):
+    for i in range(game.klhere, len(game.enemies)):
         enemy(IHR, loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill)
     # If quadrant needs a starbase, put it in
     if q.starbase:
@@ -6214,10 +6209,10 @@ def setpassword():
     # set the self-destruct password 
     if game.options & OPTION_PLAIN:
        while True:
-           chew()
+           scanner.chew()
            proutn(_("Please type in a secret password- "))
-           scan()
-           game.passwd = citem
+           scanner.next()
+           game.passwd = scanner.token
            if game.passwd != None:
                break
     else:
@@ -6288,23 +6283,23 @@ def listCommands():
 def helpme():
     # browse on-line help 
     # Give help on commands 
-    key = scan()
+    key = scanner.next()
     while True:
        if key == IHEOL:
            setwnd(prompt_window)
            proutn(_("Help on what command? "))
-           key = scan()
+           key = scanner.next()
        setwnd(message_window)
        if key == IHEOL:
            return
-        if citem in commands or citem == "ABBREV":
+        if scanner.token in commands or scanner.token == "ABBREV":
            break
        skip(1)
        listCommands()
        key = IHEOL
-       chew()
+       scanner.chew()
        skip(1)
-    cmd = citem.upper()
+    cmd = scanner.token.upper()
     try:
         fp = open(SSTDOC, "r")
     except IOError:
@@ -6353,25 +6348,27 @@ def makemoves():
            hitme = False
            game.justin = False
            game.optime = 0.0
-           chew()
+           scanner.chew()
            setwnd(prompt_window)
            clrscr()
            proutn("COMMAND> ")
-           if scan() == IHEOL:
+           if scanner.next() == IHEOL:
                if game.options & OPTION_CURSES:
                    makechart()
                continue
+            elif scanner.token == "":
+                continue
            game.ididit = False
            clrscr()
            setwnd(message_window)
            clrscr()
-            candidates = filter(lambda x: x.startswith(citem.upper()),
+            candidates = filter(lambda x: x.startswith(scanner.token.upper()),
                                 commands)
             if len(candidates) == 1:
                 cmd = candidates[0]
                 break
             elif candidates and not (game.options & OPTION_PLAIN):
-                prout("Commands with that prefix: " + " ".join(candidates))
+                prout("Commands with prefix '%s': %s" % (scanner.token, " ".join(candidates)))
             else:
                 listCommands()
                 continue
@@ -6409,7 +6406,7 @@ def makemoves():
        elif cmd == "IMPULSE":          # impulse
            impulse()
        elif cmd == "REST":             # rest
-           os.wait()
+           wait()
            if game.ididit:
                hitme = True
        elif cmd == "WARP":             # warp
@@ -6554,72 +6551,82 @@ def randplace(size):
     w.y = randrange(size)
     return w
 
-def chew():
-    # Demand input for next scan
-    global inqueue
-    inqueue = None
-
-def chew2():
-    # return IHEOL next time 
-    global inqueue
-    inqueue = []
-
-def scan():
-    # Get a token from the user
-    global inqueue, line, citem, aaitem
-    aaitem = 0.0
-    citem = ''
-
-    # Read a line if nothing here
-    if inqueue == None:
-       line = cgetline()
-       if curwnd==prompt_window:
-           clrscr()
-           setwnd(message_window)
-           clrscr()
-        # Skip leading white space
-        line = line.lstrip()
-        if line:
-            inqueue = line.split()
-        else:
-            inqueue = []
+class sstscanner:
+    def __init__(self):
+        self.type = None
+        self.token = None
+        self.real = 0.0
+        self.inqueue = []
+    def next(self):
+        # Get a token from the user
+        self.real = 0.0
+        self.token = ''
+        # Fill the token quue if nothing here
+        while not self.inqueue:
+            line = cgetline()
+            if curwnd==prompt_window:
+                clrscr()
+                setwnd(message_window)
+                clrscr()
+            if line == '':
+                return None
+            # Skip leading white space
+            line = line.lstrip()
+            if not line:
+                continue
+            else:
+                self.inqueue = line.lstrip().split() + [IHEOL] 
+        # From here on in it's all looking at the queue
+        self.token = self.inqueue.pop(0)
+        if self.token == IHEOL:
+            self.type = IHEOL
             return IHEOL
-    elif not inqueue:
-        return IHEOL
-    # From here on in it's all looking at the queue
-    citem = inqueue.pop(0)
-    if citem == IHEOL:
-        return IHEOL
-    try:
-        aaitem = float(citem)
-        return IHREAL
-    except ValueError:
-        pass
-    # Treat as alpha
-    citem = citem.lower()
-    return IHALPHA
+        try:
+            self.real = float(self.token)
+            self.type = IHREAL
+            return IHREAL
+        except ValueError:
+            pass
+        # Treat as alpha
+        self.token = self.token.lower()
+        self.type = IHALPHA
+        self.real = None
+        return IHALPHA
+    def push(self, toklist):
+        self.inqueue += toklist
+    def chew(self):
+        # Demand input for next scan
+        self.inqueue = None
+        self.real = self.token = None
+    def chew2(self):
+        # return IHEOL next time 
+        self.inqueue = []
+        self.real = self.token = None
+    def sees(self, s):
+        # compares s to item and returns true if it matches to the length of s
+        return s.startswith(self.token)
+    def int(self):
+        # Round token value to nearest integer
+        return int(round(scanner.real))
 
 def ja():
     # yes-or-no confirmation 
-    chew()
+    scanner.chew()
     while True:
-       scan()
-       chew()
-       if citem == 'y':
+       scanner.next()
+       scanner.chew()
+       if scanner.token == 'y':
            return True
-       if citem == 'n':
+       if scanner.token == 'n':
            return False
        proutn(_("Please answer with \"y\" or \"n\": "))
 
 def huh():
     # complain about unparseable input 
-    chew()
+    scanner.chew()
     skip(1)
     prout(_("Beg your pardon, Captain?"))
 
-def isit(s):
-    # compares s to citem and returns true if it matches to the length of s
-    return s.startswith(citem)
 
 def debugme():
     # access to the internals for debugging 
@@ -6648,9 +6655,9 @@ def debugme():
            proutn("Kill ")
            proutn(device[i])
            proutn("? ")
-           chew()
-           key = scan()
-            if key == IHALPHA and isit("y"):
+           scanner.chew()
+           key = scanner.next()
+            if key == IHALPHA and scanner.sees("y"):
                game.damage[i] = 10.0
     proutn("Examine/change events? ")
     if ja() == True:
@@ -6679,32 +6686,32 @@ def debugme():
            else:
                proutn("never")
            proutn("? ")
-           chew()
-           key = scan()
+           scanner.chew()
+           key = scanner.next()
            if key == 'n':
                unschedule(i)
-               chew()
+               scanner.chew()
            elif key == IHREAL:
-               ev = schedule(i, aaitem)
+               ev = schedule(i, scanner.real)
                if i == FENSLV or i == FREPRO:
-                   chew()
+                   scanner.chew()
                    proutn("In quadrant- ")
-                   key = scan()
+                   key = scanner.next()
                    # IHEOL says to leave coordinates as they are 
                    if key != IHEOL:
                        if key != IHREAL:
                            prout("Event %d canceled, no x coordinate." % (i))
                            unschedule(i)
                            continue
-                       w.x = int(round(aaitem))
-                       key = scan()
+                       w.x = int(round(scanner.real))
+                       key = scanner.next()
                        if key != IHREAL:
                            prout("Event %d canceled, no y coordinate." % (i))
                            unschedule(i)
                            continue
-                       w.y = int(round(aaitem))
+                       w.y = int(round(scanner.real))
                        ev.quadrant = w
-       chew()
+       scanner.chew()
     proutn("Induce supernova here? ")
     if ja() == True:
        game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova = True
@@ -6713,8 +6720,7 @@ def debugme():
 if __name__ == '__main__':
     try:
         global line, thing, game, idebug
-        game = citem = aaitem = inqueue = None
-        line = ''
+        game = None
         thing = coord()
         thing.angry = False
         game = gamestate()
@@ -6763,17 +6769,15 @@ if __name__ == '__main__':
             logfp.write("# seed %s\n" % seed)
             logfp.write("# options %s\n" % " ".join(arguments))
         random.seed(seed)
-        if arguments:
-            inqueue = arguments
-        else:
-            inqueue = None
+        scanner = sstscanner()
+        scanner.push(arguments)
         try:
             iostart()
             while True: # Play a game 
                 setwnd(fullscreen_window)
                 clrscr()
                 prelim()
-                setup(needprompt=not inqueue)
+                setup()
                 if game.alldone:
                     score()
                     game.alldone = False
@@ -6785,9 +6789,9 @@ if __name__ == '__main__':
                 if game.tourn and game.alldone:
                     proutn(_("Do you want your score recorded?"))
                     if ja() == True:
-                        chew2()
+                        scanner.chew2()
                         freeze(False)
-                chew()
+                scanner.chew()
                 proutn(_("Do you want to play again? "))
                 if not ja():
                     break