X-Git-Url: https://jxself.org/git/?p=super-star-trek.git;a=blobdiff_plain;f=sst.py;h=95b4722494b853fa58e1ba45c39fdcb69a46f376;hp=bf13aa9d436cfc54a46e97c2a891facee1b7eb2c;hb=ab8a2121a3a3404521081378479a364187ca1fee;hpb=b039f9f202f3a7774e5daa92f8cd0ed9940045a8 diff --git a/sst.py b/sst.py index bf13aa9..95b4722 100755 --- a/sst.py +++ b/sst.py @@ -11,13 +11,14 @@ Stas Sergeev, and Eric S. Raymond. See the doc/HACKING file in the distribution for designers notes and advice on how to modify (and how not to modify!) this code. """ -import os, sys, math, curses, time, readline, cPickle, random, copy, gettext, getpass +import os, sys, math, curses, time, readline, pickle, random, copy, gettext, getpass -version="2.1" +version = "2.1" docpath = (".", "../doc", "/usr/share/doc/sst") -def _(str): return gettext.gettext(str) +def _(st): + return gettext.gettext(st) GALSIZE = 8 # Galaxy size in quadrants NINHAB = (GALSIZE * GALSIZE / 2) # Number of inhabited worlds @@ -63,9 +64,9 @@ class Coord: self.i = x self.j = y def valid_quadrant(self): - return self.i>=0 and self.i=0 and self.j= 0 and self.i < GALSIZE and self.j >= 0 and self.j < GALSIZE def valid_sector(self): - return self.i>=0 and self.i=0 and self.j= 0 and self.i < QUADSIZE and self.j >= 0 and self.j < QUADSIZE def invalidate(self): self.i = self.j = None def is_valid(self): @@ -91,7 +92,8 @@ class Coord: def roundtogrid(self): return Coord(int(round(self.i)), int(round(self.j))) def distance(self, other=None): - if not other: other = Coord(0, 0) + if not other: + other = Coord(0, 0) return math.sqrt((self.i - other.i)**2 + (self.j - other.j)**2) def bearing(self): return 1.90985*math.atan2(self.j, self.i) @@ -122,6 +124,16 @@ class Coord: return "%s - %s" % (self.i+1, self.j+1) __repr__ = __str__ +class Thingy(Coord): + "Do not anger the Space Thingy!" + def __init__(self): + Coord.__init__(self) + self.angered = False + def angry(self): + self.angered = True + def at(self, q): + return (q.i, q.j) == (self.i, self.j) + class Planet: def __init__(self): self.name = None # string-valued if inhabited @@ -129,7 +141,7 @@ class Planet: self.pclass = None # could be ""M", "N", "O", or "destroyed" self.crystals = "absent"# could be "mined", "present", "absent" self.known = "unknown" # could be "unknown", "known", "shuttle_down" - self.inhabited = False # is it inhabites? + self.inhabited = False # is it inhabited? def __str__(self): return self.name @@ -147,8 +159,10 @@ class Quadrant: class Page: def __init__(self): self.stars = None - self.starbase = None + self.starbase = False self.klingons = None + def __repr__(self): + return "<%s,%s,%s>" % (self.klingons, self.starbase, self.stars) def fill2d(size, fillfun): "Fill an empty list in 2D." @@ -208,23 +222,23 @@ OPTION_ALMY = 0x02000000 # user chose Almy variant OPTION_COLOR = 0x04000000 # enable color display (experimental, ESR, 2010) # Define devices -DSRSENS = 0 -DLRSENS = 1 -DPHASER = 2 -DPHOTON = 3 -DLIFSUP = 4 -DWARPEN = 5 -DIMPULS = 6 -DSHIELD = 7 -DRADIO = 0 -DSHUTTL = 9 -DCOMPTR = 10 -DNAVSYS = 11 -DTRANSP = 12 -DSHCTRL = 13 -DDRAY = 14 -DDSP = 15 -NDEVICES= 16 # Number of devices +DSRSENS = 0 +DLRSENS = 1 +DPHASER = 2 +DPHOTON = 3 +DLIFSUP = 4 +DWARPEN = 5 +DIMPULS = 6 +DSHIELD = 7 +DRADIO = 0 +DSHUTTL = 9 +DCOMPTR = 10 +DNAVSYS = 11 +DTRANSP = 12 +DSHCTRL = 13 +DDRAY = 14 +DDSP = 15 +NDEVICES = 16 # Number of devices SKILL_NONE = 0 SKILL_NOVICE = 1 @@ -233,8 +247,10 @@ SKILL_GOOD = 3 SKILL_EXPERT = 4 SKILL_EMERITUS = 5 -def damaged(dev): return (game.damage[dev] != 0.0) -def communicating(): return not damaged(DRADIO) or game.condition=="docked" +def damaged(dev): + return (game.damage[dev] != 0.0) +def communicating(): + return not damaged(DRADIO) or game.condition=="docked" # Define future events FSPY = 0 # Spy event happens always (no future[] entry) @@ -254,12 +270,15 @@ NEVENTS = 12 # Abstract out the event handling -- underlying data structures will change # when we implement stateful events -def findevent(evtype): return game.future[evtype] +def findevent(evtype): + return game.future[evtype] class Enemy: - def __init__(self, type=None, loc=None, power=None): - self.type = type + def __init__(self, etype=None, loc=None, power=None): + self.type = etype self.location = Coord() + self.kdist = None + self.kavgd = None if loc: self.move(loc) self.power = power # enemy energy level @@ -296,7 +315,7 @@ class Gamestate: while i > 0: i -= 1 self.future.append(Event()) - self.passwd = None; # Self Destruct password + self.passwd = None # Self Destruct password self.enemies = [] self.quadrant = None # where we are in the large self.sector = None # where we are in the small @@ -366,6 +385,7 @@ class Gamestate: self.score = 0.0 # overall score self.perdate = 0.0 # rate of kills self.idebug = False # Debugging instrumentation enabled? + self.statekscmdr = None # No SuperCommander coordinates yet. def recompute(self): # Stas thinks this should be (C expression): # game.state.remkl + len(game.state.kcmdr) > 0 ? @@ -373,7 +393,7 @@ class Gamestate: # He says the existing expression is prone to divide-by-zero errors # after killing the last klingon when score is shown -- perhaps also # if the only remaining klingon is SCOM. - game.state.remtime = game.state.remres/(game.state.remkl + 4*len(game.state.kcmdr)) + self.state.remtime = self.state.remres/(self.state.remkl + 4*len(self.state.kcmdr)) FWON = 0 FDEPLETE = 1 @@ -426,26 +446,21 @@ def tryexit(enemy, look, irun): iq.i = game.quadrant.i+(look.i+(QUADSIZE-1))/QUADSIZE - 1 iq.j = game.quadrant.j+(look.j+(QUADSIZE-1))/QUADSIZE - 1 if not welcoming(iq): - return False; + return False if enemy.type == 'R': - return False; # Romulans cannot escape! + return False # Romulans cannot escape! if not irun: # avoid intruding on another commander's territory if enemy.type == 'C': if iq in game.state.kcmdr: - return False + return [] # refuse to leave if currently attacking starbase if game.battle == game.quadrant: - return False + return [] # don't leave if over 1000 units of energy if enemy.power > 1000.0: - return False - # emit escape message and move out of quadrant. - # we know this if either short or long range sensors are working - if not damaged(DSRSENS) or not damaged(DLRSENS) or \ - game.condition == "docked": - prout(crmena(True, enemy.type, "sector", enemy.location) + \ - (_(" escapes to Quadrant %s (and regains strength).") % iq)) + return [] + oldloc = copy.copy(enemy.location) # handle local matters related to escape enemy.move(None) game.klhere -= 1 @@ -454,19 +469,20 @@ def tryexit(enemy, look, irun): # Handle global matters related to escape game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1 game.state.galaxy[iq.i][iq.j].klingons += 1 - if enemy.type=='S': + if enemy.type == 'S': game.iscate = False game.ientesc = False game.isatb = 0 schedule(FSCMOVE, 0.2777) unschedule(FSCDBAS) - game.state.kscmdr=iq + game.state.kscmdr = iq else: for cmdr in game.state.kcmdr: if cmdr == game.quadrant: game.state.kcmdr.append(iq) break - return True; # success + # report move out of quadrant. + return [(True, enemy, oldloc, ibq)] # The bad-guy movement algorithm: # @@ -508,17 +524,18 @@ def tryexit(enemy, look, irun): def movebaddy(enemy): "Tactical movement for the bad guys." - goto = Coord(); look = Coord() + goto = Coord() + look = Coord() irun = False # This should probably be just (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant) if game.skill >= SKILL_EXPERT: nbaddys = (((game.quadrant in game.state.kcmdr)*2 + (game.state.kscmdr==game.quadrant)*2+game.klhere*1.23+game.irhere*1.5)/2.0) else: nbaddys = (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant) - dist1 = enemy.kdist - mdist = int(dist1 + 0.5); # Nearest integer distance + old_dist = enemy.kdist + mdist = int(old_dist + 0.5) # Nearest integer distance # If SC, check with spy to see if should hi-tail it - if enemy.type=='S' and \ + if enemy.type == 'S' and \ (enemy.power <= 500.0 or (game.condition=="docked" and not damaged(DPHOTON))): irun = True motion = -QUADSIZE @@ -526,7 +543,7 @@ def movebaddy(enemy): # decide whether to advance, retreat, or hold position forces = enemy.power+100.0*len(game.enemies)+400*(nbaddys-1) if not game.shldup: - forces += 1000; # Good for enemy if shield is down! + forces += 1000 # Good for enemy if shield is down! if not damaged(DPHASER) or not damaged(DPHOTON): if damaged(DPHASER): # phasers damaged forces += 300.0 @@ -544,14 +561,14 @@ 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 - randreal())**2 * dist1 + 1.0 - if game.condition=="docked" and (game.options & OPTION_BASE): # protected by base -- back off ! + motion = (1.0 - randreal())**2 * old_dist + 1.0 + if game.condition == "docked" and (game.options & OPTION_BASE): # protected by base -- back off ! motion -= game.skill*(2.0-randreal()**2) if game.idebug: proutn("=== MOTION = %d, FORCES = %1.2f, " % (motion, forces)) # don't move if no motion - if motion==0: - return + if motion == 0: + return [] # Limit motion according to skill if abs(motion) > game.skill: if motion < 0: @@ -561,11 +578,11 @@ def movebaddy(enemy): # calculate preferred number of steps nsteps = abs(int(motion)) if motion > 0 and nsteps > mdist: - nsteps = mdist; # don't overshoot + nsteps = mdist # don't overshoot if nsteps > QUADSIZE: - nsteps = QUADSIZE; # This shouldn't be necessary + nsteps = QUADSIZE # This shouldn't be necessary if nsteps < 1: - nsteps = 1; # This shouldn't be necessary + nsteps = 1 # This shouldn't be necessary if game.idebug: proutn("NSTEPS = %d:" % nsteps) # Compute preferred values of delta X and Y @@ -591,19 +608,19 @@ def movebaddy(enemy): else: krawlj = -1 success = False - attempts = 0; # Settle mysterious hang problem + attempts = 0 # Settle mysterious hang problem while attempts < 20 and not success: attempts += 1 if look.i < 0 or look.i >= QUADSIZE: - if motion < 0 and tryexit(enemy, look, irun): - return + if motion < 0: + return tryexit(enemy, look, irun) if krawli == m.i or m.j == 0: break look.i = goto.i + krawli krawli = -krawli elif look.j < 0 or look.j >= QUADSIZE: - if motion < 0 and tryexit(enemy, look, irun): - return + if motion < 0: + return tryexit(enemy, look, irun) if krawlj == m.j or m.i == 0: break look.j = goto.j + krawlj @@ -613,7 +630,7 @@ def movebaddy(enemy): if game.quad[look.i][look.j] == game.ship and \ (enemy.type == 'C' or enemy.type == 'S'): collision(rammed=True, enemy=enemy) - return + return [] if krawli != m.i and m.j != 0: look.i = goto.i + krawli krawli = -krawli @@ -621,25 +638,19 @@ def movebaddy(enemy): look.j = goto.j + krawlj krawlj = -krawlj else: - break; # we have failed + break # we have failed else: success = True if success: goto = look if game.idebug: - proutn(`goto`) + proutn(repr(goto)) else: - break; # done early + break # done early if game.idebug: skip(1) - if enemy.move(goto): - if not damaged(DSRSENS) or game.condition == "docked": - proutn(_("*** %s from Sector %s") % (cramen(enemy.type), enemy.location)) - if enemy.kdist < dist1: - proutn(_(" advances to ")) - else: - proutn(_(" retreats to ")) - prout("Sector %s." % goto) + # Enemy moved, but is still in sector + return [(False, enemy, old_dist, goto)] def moveklings(): "Sequence Klingon tactical movement." @@ -647,14 +658,15 @@ def moveklings(): prout("== MOVCOM") # Figure out which Klingon is the commander (or Supercommander) # and do move + tacmoves = [] if game.quadrant in game.state.kcmdr: for enemy in game.enemies: if enemy.type == 'C': - movebaddy(enemy) - if game.state.kscmdr==game.quadrant: + tacmoves += movebaddy(enemy) + if game.state.kscmdr == game.quadrant: for enemy in game.enemies: if enemy.type == 'S': - movebaddy(enemy) + tacmoves += movebaddy(enemy) break # If skill level is high, move other Klingons and Romulans too! # Move these last so they can base their actions on what the @@ -662,8 +674,8 @@ def moveklings(): if game.skill >= SKILL_EXPERT and (game.options & OPTION_MVBADDY): for enemy in game.enemies: if enemy.type in ('K', 'R'): - movebaddy(enemy) - sortenemies() + tacmoves += movebaddy(enemy) + return tacmoves def movescom(iq, avoid): "Commander movement helper." @@ -676,16 +688,15 @@ def movescom(iq, avoid): game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons -= 1 game.state.kscmdr = iq game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons += 1 - if game.state.kscmdr==game.quadrant: + if game.state.kscmdr == game.quadrant: # SC has scooted, remove him from current quadrant - game.iscate=False - game.isatb=0 + game.iscate = False + game.isatb = 0 game.ientesc = False unschedule(FSCDBAS) for enemy in game.enemies: if enemy.type == 'S': - break - enemy.move(None) + enemy.move(None) game.klhere -= 1 if game.condition != "docked": newcnd() @@ -703,11 +714,14 @@ def movescom(iq, avoid): proutn(_(" a planet in Quadrant %s has been destroyed") % game.state.kscmdr) prout(_(" by the Super-commander.\"")) break - return True; # looks good! + return True # looks good! def supercommander(): "Move the Super Commander." - iq = Coord(); sc = Coord(); ibq = Coord(); idelta = Coord() + iq = Coord() + sc = Coord() + ibq = Coord() + idelta = Coord() basetbl = [] if game.idebug: prout("== SUPERCOMMANDER") @@ -736,8 +750,8 @@ def supercommander(): # without too many Klingons, and not already under attack. ifindit = iwhichb = 0 for (i2, base) in enumerate(game.state.baseq): - i = basetbl[i2][0]; # bug in original had it not finding nearest - if base==game.quadrant or base==game.battle or not welcoming(base): + i = basetbl[i2][0] # bug in original had it not finding nearest + if base == game.quadrant or base == game.battle or not welcoming(base): continue # if there is a commander, and no other base is appropriate, # we will take the one with the commander @@ -750,7 +764,7 @@ def supercommander(): ifindit = 1 iwhichb = i break - if ifindit==0: + if ifindit == 0: return # Nothing suitable -- wait until next time ibq = game.state.baseq[iwhichb] # decide how to move toward base @@ -763,7 +777,7 @@ def supercommander(): iq = game.state.kscmdr + idelta if not movescom(iq, avoid): # failed -- try some other maneuvers - if idelta.i==0 or idelta.j==0: + if idelta.i == 0 or idelta.j == 0: # attempt angle move if idelta.i != 0: iq.j = game.state.kscmdr.j + 1 @@ -811,7 +825,7 @@ def supercommander(): if not ja(): return game.resting = False - game.optime = 0.0; # actually finished + game.optime = 0.0 # actually finished return # Check for intelligence report if not game.idebug and \ @@ -830,13 +844,17 @@ def movetholian(): return tid = Coord() if game.tholian.location.i == 0 and game.tholian.location.j == 0: - tid.i = 0; tid.j = QUADSIZE-1 + tid.i = 0 + tid.j = QUADSIZE-1 elif game.tholian.location.i == 0 and game.tholian.location.j == QUADSIZE-1: - tid.i = QUADSIZE-1; tid.j = QUADSIZE-1 + tid.i = QUADSIZE-1 + tid.j = QUADSIZE-1 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == QUADSIZE-1: - tid.i = QUADSIZE-1; tid.j = 0 + tid.i = QUADSIZE-1 + tid.j = 0 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == 0: - tid.i = 0; tid.j = 0 + tid.i = 0 + tid.j = 0 else: # something is wrong! game.tholian.move(None) @@ -850,25 +868,25 @@ def movetholian(): # move in x axis while here.i != tid.i: here.i += delta.i - if game.quad[here.i][here.j]=='.': + if game.quad[here.i][here.j] == '.': game.tholian.move(here) # move in y axis while here.j != tid.j: here.j += delta.j - if game.quad[here.i][here.j]=='.': + if game.quad[here.i][here.j] == '.': game.tholian.move(here) # check to see if all holes plugged for i in range(QUADSIZE): - if game.quad[0][i]!='#' and game.quad[0][i]!='T': + if game.quad[0][i] != '#' and game.quad[0][i] != 'T': return - if game.quad[QUADSIZE-1][i]!='#' and game.quad[QUADSIZE-1][i]!='T': + if game.quad[QUADSIZE-1][i] != '#' and game.quad[QUADSIZE-1][i] != 'T': return - if game.quad[i][0]!='#' and game.quad[i][0]!='T': + if game.quad[i][0] != '#' and game.quad[i][0] != 'T': return - if game.quad[i][QUADSIZE-1]!='#' and game.quad[i][QUADSIZE-1]!='T': + if game.quad[i][QUADSIZE-1] != '#' and game.quad[i][QUADSIZE-1] != 'T': return # All plugged up -- Tholian splits - game.quad[game.tholian.location.i][game.tholian.location.j]='#' + game.quad[game.tholian.location.i][game.tholian.location.j] = '#' dropin(' ') prout(crmena(True, 'T', "sector", game.tholian) + _(" completes web.")) game.tholian.move(None) @@ -883,7 +901,7 @@ def doshield(shraise): if shraise: action = "SHUP" else: - key = scanner.next() + key = scanner.nexttok() if key == "IHALPHA": if scanner.sees("transfer"): action = "NRG" @@ -895,7 +913,7 @@ def doshield(shraise): action = "SHUP" elif scanner.sees("down"): action = "SHDN" - if action=="NONE": + if action == "NONE": proutn(_("Do you wish to change shield energy? ")) if ja(): action = "NRG" @@ -930,19 +948,19 @@ def doshield(shraise): prout(_("Shields raising uses up last of energy.")) finish(FNRG) return - game.ididit=True + game.ididit = True return elif action == "SHDN": if not game.shldup: prout(_("Shields already down.")) return - game.shldup=False - game.shldchg=True + game.shldup = False + game.shldchg = True prout(_("Shields lowered.")) game.ididit = True return elif action == "NRG": - while scanner.next() != "IHREAL": + while scanner.nexttok() != "IHREAL": scanner.chew() proutn(_("Energy to transfer to shields- ")) nrg = scanner.real @@ -1009,10 +1027,10 @@ def randdevice(): wsum += w if idx < wsum: return i - return None; # we should never get here + return None # we should never get here def collision(rammed, enemy): - "Collision handling fot rammong events." + "Collision handling for rammong events." prouts(_("***RED ALERT! RED ALERT!")) skip(1) prout(_("***COLLISION IMMINENT.")) @@ -1057,7 +1075,7 @@ def collision(rammed, enemy): def torpedo(origin, bearing, dispersion, number, nburst): "Let a photon torpedo fly" - if not damaged(DSRSENS) or game.condition=="docked": + if not damaged(DSRSENS) or game.condition == "docked": setwnd(srscan_window) else: setwnd(message_window) @@ -1068,42 +1086,44 @@ def torpedo(origin, bearing, dispersion, number, nburst): # Loop to move a single torpedo setwnd(message_window) for step in range(1, QUADSIZE*2): - if not track.next(): break + if not track.nexttok(): + break w = track.sector() if not w.valid_sector(): break - iquad=game.quad[w.i][w.j] + iquad = game.quad[w.i][w.j] tracktorpedo(w, step, number, nburst, iquad) - if iquad=='.': + if iquad == '.': continue # hit something - if not damaged(DSRSENS) or game.condition == "docked": - skip(1); # start new line after text track + setwnd(message_window) + if not damaged(DSRSENS) or game.condition == "docked": + skip(1) # start new line after text track if iquad in ('E', 'F'): # 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-track.angle)) - newcnd(); # we're blown out of dock - if game.landed or game.condition=="docked": + newcnd() # we're blown out of dock + if game.landed or game.condition == "docked": return hit # Cheat if on a planet # In the C/FORTRAN version, dispersion was 2.5 radians, which # is 143 degrees, which is almost exactly 4.8 clockface units - displacement = course(track.bearing+randreal(-2.4,2.4), distance=2**0.5) - displacement.next() + displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5) + displacement.nexttok() bumpto = displacement.sector() if not bumpto.valid_sector(): return hit - if game.quad[bumpto.i][bumpto.j]==' ': + if game.quad[bumpto.i][bumpto.j] == ' ': finish(FHOLE) return hit - if game.quad[bumpto.i][bumpto.j]!='.': + if game.quad[bumpto.i][bumpto.j] != '.': # can't move into object return hit game.sector = bumpto proutn(crmshp()) - game.quad[w.i][w.j]='.' - game.quad[bumpto.i][bumpto.j]=iquad + game.quad[w.i][w.j] = '.' + 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.location).distance() @@ -1117,49 +1137,52 @@ def torpedo(origin, bearing, dispersion, number, nburst): return None for enemy in game.enemies: if w == enemy.location: - break - kp = math.fabs(enemy.power) - h1 = 700.0 + randrange(100) - \ - 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle)) - h1 = math.fabs(h1) - if kp < h1: - h1 = kp - if enemy.power < 0: - enemy.power -= -h1 - else: - enemy.power -= h1 - if enemy.power == 0: - deadkl(w, iquad, w) - return None - proutn(crmena(True, iquad, "sector", w)) - displacement = course(track.bearing+randreal(-2.4,2.4), distance=2**0.5) - displacement.next() - bumpto = displacement.sector() - if not bumpto.valid_sector(): - prout(_(" damaged but not destroyed.")) - return - if game.quad[bumpto.i][bumpto.j] == ' ': - prout(_(" buffeted into black hole.")) - deadkl(w, iquad, bumpto) - if game.quad[bumpto.i][bumpto.j] != '.': - prout(_(" damaged but not destroyed.")) + kp = math.fabs(enemy.power) + h1 = 700.0 + randrange(100) - \ + 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle)) + h1 = math.fabs(h1) + if kp < h1: + h1 = kp + if enemy.power < 0: + enemy.power -= -h1 + else: + enemy.power -= h1 + if enemy.power == 0: + deadkl(w, iquad, w) + return None + proutn(crmena(True, iquad, "sector", w)) + displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5) + displacement.nexttok() + bumpto = displacement.sector() + if not bumpto.valid_sector(): + prout(_(" damaged but not destroyed.")) + return + if game.quad[bumpto.i][bumpto.j] == ' ': + prout(_(" buffeted into black hole.")) + deadkl(w, iquad, bumpto) + if game.quad[bumpto.i][bumpto.j] != '.': + prout(_(" damaged but not destroyed.")) + else: + prout(_(" damaged-- displaced by blast to Sector %s ")%bumpto) + enemy.location = bumpto + game.quad[w.i][w.j] = '.' + game.quad[bumpto.i][bumpto.j] = iquad + for enemy in game.enemies: + enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance() + sortenemies() + break else: - prout(_(" damaged-- displaced by blast to Sector %s ")%bumpto) - enemy.location = bumpto - game.quad[w.i][w.j]='.' - game.quad[bumpto.i][bumpto.j]=iquad - for enemy in game.enemies: - enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance() - sortenemies() + prout("Internal error, no enemy where expected!") + raise SystemExit, 1 return None elif iquad == 'B': # Hit a base skip(1) prout(_("***STARBASE DESTROYED..")) game.state.baseq = filter(lambda x: x != game.quadrant, game.state.baseq) - game.quad[w.i][w.j]='.' + game.quad[w.i][w.j] = '.' game.base.invalidate() - game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase -= 1 - game.state.chart[game.quadrant.i][game.quadrant.j].starbase -= 1 + game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False + game.state.chart[game.quadrant.i][game.quadrant.j].starbase = False game.state.basekl += 1 newcnd() return None @@ -1209,7 +1232,7 @@ def torpedo(origin, bearing, dispersion, number, nburst): # Stas Sergeev added the possibility that # you can shove the Thingy and piss it off. # It then becomes an enemy and may fire at you. - thing.angry = True + thing.angry() return None elif iquad == ' ': # Black hole skip(1) @@ -1246,8 +1269,9 @@ def torpedo(origin, bearing, dispersion, number, nburst): return None break skip(1) + setwnd(message_window) prout(_("Torpedo missed.")) - return None; + return None def fry(hit): "Critical-hit resolution." @@ -1258,15 +1282,15 @@ def fry(hit): # Select devices and cause damage cdam = [] while ncrit > 0: - ncrit -= 1 while True: j = randdevice() # Cheat to prevent shuttle damage unless on ship - if not (game.damage[j]<0.0 or (j==DSHUTTL and game.iscraft != "onship")): + if not (game.damage[j]<0.0 or (j == DSHUTTL and game.iscraft != "onship")): break cdam.append(j) extradm = (hit*game.damfac)/(ncrit*randreal(75, 100)) game.damage[j] += extradm + ncrit -= 1 skipcount = 0 for (i, j) in enumerate(cdam): proutn(device[j]) @@ -1278,7 +1302,7 @@ def fry(hit): prout(_(" damaged.")) if damaged(DSHIELD) and game.shldup: prout(_("***Shields knocked down.")) - game.shldup=False + game.shldup = False def attack(torps_ok): # bad guy attacks us @@ -1286,8 +1310,11 @@ def attack(torps_ok): # game could be over at this point, check if game.alldone: return - attempt = False; ihurt = False; - hitmax=0.0; hittot=0.0; chgfac=1.0 + attempt = False + ihurt = False + hitmax = 0.0 + hittot = 0.0 + chgfac = 1.0 where = "neither" if game.idebug: prout("=== ATTACK!") @@ -1299,10 +1326,27 @@ def attack(torps_ok): game.neutz = False return # commanders get a chance to tac-move towards you - if (((game.quadrant in game.state.kcmdr or game.state.kscmdr==game.quadrant) and not game.justin) or game.skill == SKILL_EMERITUS) and torps_ok: - moveklings() + if (((game.quadrant in game.state.kcmdr or game.state.kscmdr == game.quadrant) and not game.justin) or game.skill == SKILL_EMERITUS) and torps_ok: + for (bugout, enemy, old, goto) in moveklings(): + if bugout: + # we know about this if either short or long range + # sensors are working + if damaged(DSRSENS) and damaged(DLRSENS) \ + and game.condition != "docked": + prout(crmena(True, enemy.type, "sector", old) + \ + (_(" escapes to Quadrant %s (and regains strength).") % goto)) + else: # Enemy still in-sector + if enemy.move(goto): + if not damaged(DSRSENS) or game.condition == "docked": + proutn(_("*** %s from Sector %s") % (cramen(enemy.type), enemy.location)) + if enemy.kdist < old: + proutn(_(" advances to ")) + else: + proutn(_(" retreats to ")) + prout("Sector %s." % goto) + sortenemies() # if no enemies remain after movement, we're done - if len(game.enemies)==0 or (len(game.enemies)==1 and thing == game.quadrant and not thing.angry): + if len(game.enemies) == 0 or (len(game.enemies) == 1 and thing.at(game.quadrant) and not thing.angered): return # set up partial hits if attack happens during shield status change pfac = 1.0/game.inshld @@ -1314,29 +1358,29 @@ def attack(torps_ok): where = "sector" for enemy in game.enemies: if enemy.power < 0: - continue; # too weak to attack + continue # too weak to attack # compute hit strength and diminish shield power r = randreal() # Increase chance of photon torpedos if docked or enemy energy is low if game.condition == "docked": r *= 0.25 if enemy.power < 500: - r *= 0.25; - if enemy.type=='T' or (enemy.type=='?' and not thing.angry): + r *= 0.25 + if enemy.type == 'T' or (enemy.type == '?' and not thing.angered): continue # different enemies have different probabilities of throwing a torp usephasers = not torps_ok or \ (enemy.type == 'K' and r > 0.0005) or \ - (enemy.type=='C' and r > 0.015) or \ - (enemy.type=='R' and r > 0.3) or \ - (enemy.type=='S' and r > 0.07) or \ - (enemy.type=='?' and r > 0.05) + (enemy.type == 'C' and r > 0.015) or \ + (enemy.type == 'R' and r > 0.3) or \ + (enemy.type == 'S' and r > 0.07) or \ + (enemy.type == '?' and r > 0.05) if usephasers: # Enemy uses phasers if game.condition == "docked": - continue; # Don't waste the effort! - attempt = True; # Attempt to attack + continue # Don't waste the effort! + attempt = True # Attempt to attack dustfac = randreal(0.8, 0.85) - hit = enemy.power*math.pow(dustfac,enemy.kavgd) + hit = enemy.power*math.pow(dustfac, enemy.kavgd) enemy.power *= 0.75 else: # Enemy uses photon torpedo # We should be able to make the bearing() method work here @@ -1350,17 +1394,17 @@ def attack(torps_ok): dispersion = (randreal()+randreal())*0.5 - 0.5 dispersion += 0.002*enemy.power*dispersion hit = torpedo(enemy.location, pcourse, dispersion, number=1, nburst=1) - if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0: - finish(FWON); # Klingons did themselves in! + if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0: + finish(FWON) # Klingons did themselves in! if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.alldone: return # Supernova or finished if hit == None: continue # incoming phaser or torpedo, shields may dissipate it - if game.shldup or game.shldchg or game.condition=="docked": + if game.shldup or game.shldchg or game.condition == "docked": # shields will take hits propor = pfac * game.shield - if game.condition =="docked": + if game.condition == "docked": propor *= 2.1 if propor < 0.1: propor = 0.1 @@ -1426,20 +1470,20 @@ def attack(torps_ok): sortenemies() return -def deadkl(w, type, mv): +def deadkl(w, etype, mv): "Kill a Klingon, Tholian, Romulan, or Thingy." # Added mv to allow enemy to "move" before dying - proutn(crmena(True, type, "sector", mv)) + proutn(crmena(True, etype, "sector", mv)) # Decide what kind of enemy it is and update appropriately - if type == 'R': + if etype == 'R': # Chalk up a Romulan game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans -= 1 game.irhere -= 1 game.state.nromrem -= 1 - elif type == 'T': + elif etype == 'T': # Killed a Tholian game.tholian = None - elif type == '?': + elif etype == '?': # Killed a Thingy global thing thing = None @@ -1465,7 +1509,7 @@ def deadkl(w, type, mv): unschedule(FSCDBAS) # For each kind of enemy, finish message to player prout(_(" destroyed.")) - if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0: + if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0: return game.recompute() # Remove enemy ship from arrays describing local conditions @@ -1481,9 +1525,9 @@ def targetcheck(w): huh() return None delta = Coord() - # FIXME: C code this was translated from is wacky -- why the sign reversal? - delta.j = (w.j - game.sector.j); - delta.i = (game.sector.i - w.i); + # C code this was translated from is wacky -- why the sign reversal? + delta.j = (w.j - game.sector.j) + delta.i = (game.sector.i - w.i) if delta == Coord(0, 0): skip(1) prout(_("Spock- \"Bridge to sickbay. Dr. McCoy,")) @@ -1507,7 +1551,7 @@ def torps(): return # First, get torpedo count while True: - scanner.next() + scanner.nexttok() if scanner.token == "IHALPHA": huh() return @@ -1532,10 +1576,10 @@ def torps(): # Next, get targets target = [] for i in range(n): - key = scanner.next() - if i==0 and key == "IHEOL": - break; # no coordinate waiting, we will try prompting - if i==1 and key == "IHEOL": + key = scanner.nexttok() + if i == 0 and key == "IHEOL": + break # no coordinate waiting, we will try prompting + if i == 1 and key == "IHEOL": # direct all torpedoes at one target while i < n: target.append(target[0]) @@ -1587,7 +1631,7 @@ def torps(): if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova: return if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)<=0: - finish(FWON); + finish(FWON) def overheat(rpow): "Check for phasers overheating." @@ -1631,18 +1675,18 @@ def checkshctrl(rpow): prout(_("Phaser energy dispersed by shields.")) prout(_("Enemy unaffected.")) overheat(rpow) - return True; + return True def hittem(hits): "Register a phaser hit on Klingons and Romulans." - kk = 0 w = Coord() skip(1) - for (k, wham) in enumerate(hits): - if wham==0: + kk = 0 + for wham in hits: + if wham == 0: continue dustfac = randreal(0.9, 1.0) - hit = wham*math.pow(dustfac,game.enemies[kk].kdist) + hit = wham*math.pow(dustfac, game.enemies[kk].kdist) kpini = game.enemies[kk].power kp = math.fabs(kpini) if PHASEFAC*hit < kp: @@ -1660,20 +1704,20 @@ def hittem(hits): else: proutn(_("Very small hit on ")) ienm = game.quad[w.i][w.j] - if ienm=='?': - thing.angry = True + if ienm == '?': + thing.angry() proutn(crmena(False, ienm, "sector", w)) skip(1) if kpow == 0: deadkl(w, ienm, w) if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0: - finish(FWON); + finish(FWON) if game.alldone: return kk -= 1 # don't do the increment continue else: # decide whether or not to emasculate klingon - if kpow>0 and withprob(0.9) and kpow <= randreal(0.4, 0.8)*kpini: + if kpow > 0 and withprob(0.9) and kpow <= randreal(0.4, 0.8)*kpini: prout(_("***Mr. Spock- \"Captain, the vessel at Sector %s")%w) prout(_(" has just lost its firepower.\"")) game.enemies[kk].power = -kpow @@ -1683,10 +1727,16 @@ def hittem(hits): def phasers(): "Fire phasers at bad guys." hits = [] - kz = 0; k = 1; irec=0 # Cheating inhibitor - ifast = False; no = False; itarg = True; msgflag = True; rpow=0 + kz = 0 + k = 1 + irec = 0 # Cheating inhibitor + ifast = False + no = False + itarg = True + msgflag = True + rpow = 0 automode = "NOTSET" - key=0 + key = 0 skip(1) # SR sensors and Computer are needed for automode if damaged(DSRSENS) or damaged(DCOMPTR): @@ -1712,18 +1762,18 @@ def phasers(): 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=scanner.next() + while automode == "NOTSET": + key = scanner.nexttok() if key == "IHALPHA": if scanner.sees("manual"): if len(game.enemies)==0: prout(_("There is no enemy present to select.")) scanner.chew() key = "IHEOL" - automode="AUTOMATIC" + automode = "AUTOMATIC" else: automode = "MANUAL" - key = scanner.next() + key = scanner.nexttok() elif scanner.sees("automatic"): if (not itarg) and len(game.enemies) != 0: automode = "FORCEMAN" @@ -1731,7 +1781,7 @@ def phasers(): if len(game.enemies)==0: prout(_("Energy will be expended into space.")) automode = "AUTOMATIC" - key = scanner.next() + key = scanner.nexttok() elif scanner.sees("no"): no = True else: @@ -1761,21 +1811,21 @@ def phasers(): if automode == "AUTOMATIC": if key == "IHALPHA" and scanner.sees("no"): no = True - key = scanner.next() + key = scanner.nexttok() if key != "IHREAL" and len(game.enemies) != 0: prout(_("Phasers locked on target. Energy available: %.2f")%avail) - irec=0 + irec = 0 while True: scanner.chew() if not kz: for i in range(len(game.enemies)): - irec += math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90,game.enemies[i].kdist))*randreal(1.01, 1.06) + 1.0 - kz=1 + irec += math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))*randreal(1.01, 1.06) + 1.0 + kz = 1 proutn(_("%d units required. ") % irec) scanner.chew() proutn(_("Units to fire= ")) - key = scanner.next() - if key!="IHREAL": + key = scanner.nexttok() + if key != "IHREAL": return rpow = scanner.real if rpow > avail: @@ -1784,15 +1834,15 @@ def phasers(): key = "IHEOL" if not rpow > avail: break - if rpow<=0: + if rpow <= 0: # chicken out scanner.chew() return - key=scanner.next() + key = scanner.nexttok() if key == "IHALPHA" and scanner.sees("no"): no = True if ifast: - game.energy -= 200; # Go and do it! + game.energy -= 200 # Go and do it! if checkshctrl(rpow): return scanner.chew() @@ -1805,7 +1855,7 @@ def phasers(): hits.append(0.0) if powrem <= 0: continue - hits[i] = math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90,game.enemies[i].kdist)) + hits[i] = math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist)) over = randreal(1.01, 1.06) * hits[i] temp = powrem powrem -= hits[i] + over @@ -1854,13 +1904,13 @@ def phasers(): prout(cramen(ienm) + _(" can't be located without short range scan.")) scanner.chew() key = "IHEOL" - hits[k] = 0; # prevent overflow -- thanks to Alexei Voitenko + hits[k] = 0 # prevent overflow -- thanks to Alexei Voitenko k += 1 continue if key == "IHEOL": scanner.chew() if itarg and k > kz: - irec=(abs(game.enemies[k].power)/(PHASEFAC*math.pow(0.9,game.enemies[k].kdist))) * randreal(1.01, 1.06) + 1.0 + irec = (abs(game.enemies[k].power)/(PHASEFAC*math.pow(0.9, game.enemies[k].kdist))) * randreal(1.01, 1.06) + 1.0 kz = k proutn("(") if not damaged(DCOMPTR): @@ -1869,16 +1919,16 @@ def phasers(): proutn("??") proutn(") ") proutn(_("units to fire at %s- ") % crmena(False, ienm, "sector", aim)) - key = scanner.next() + key = scanner.nexttok() if key == "IHALPHA" and scanner.sees("no"): no = True - key = scanner.next() + key = scanner.nexttok() continue if key == "IHALPHA": huh() return if key == "IHEOL": - if k==1: # Let me say I'm baffled by this + if k == 1: # Let me say I'm baffled by this msgflag = True continue if scanner.real < 0: @@ -1892,7 +1942,7 @@ def phasers(): prout(_("Available energy exceeded -- try again.")) scanner.chew() return - key = scanner.next(); # scan for next value + key = scanner.nexttok() # scan for next value k += 1 if rpow == 0.0: # zero energy -- abort @@ -1923,7 +1973,7 @@ def phasers(): prout(_("Shields raised.")) else: game.shldup = False - overheat(rpow); + overheat(rpow) # Code from events,c begins here. @@ -1967,11 +2017,15 @@ def cancelrest(): def events(): "Run through the event queue looking for things to do." - i=0 - fintim = game.state.date + game.optime; yank=0 - ictbeam = False; istract = False - w = Coord(); hold = Coord() - ev = Event(); ev2 = Event() + i = 0 + fintim = game.state.date + game.optime + yank = 0 + ictbeam = False + istract = False + w = Coord() + hold = Coord() + ev = Event() + ev2 = Event() def tractorbeam(yank): "Tractor-beaming cases merge here." @@ -2013,8 +2067,8 @@ def events(): else: prout(_("(Shields not currently useable.)")) newqad() - # Adjust finish time to time of tractor beaming - fintim = game.state.date+game.optime + # Adjust finish time to time of tractor beaming? + # fintim = game.state.date+game.optime attack(torps_ok=False) if not game.state.kcmdr: unschedule(FTBEAM) @@ -2089,11 +2143,11 @@ def events(): # Decrement Federation resources and recompute remaining time game.state.remres -= (game.state.remkl+4*len(game.state.kcmdr))*xtime game.recompute() - if game.state.remtime <=0: + if game.state.remtime <= 0: finish(FDEPLETE) return # Any crew left alive? - if game.state.crew <=0: + if game.state.crew <= 0: finish(FCREW) return # Is life support adequate? @@ -2137,7 +2191,7 @@ def events(): elif evcode == FSPY: # Check with spy to see if SC should tractor beam if game.state.nscrem == 0 or \ ictbeam or istract or \ - game.condition=="docked" or game.isatb==1 or game.iscate: + game.condition == "docked" or game.isatb == 1 or game.iscate: return if game.ientesc or \ (game.energy<2000 and game.torps<4 and game.shield < 1250) or \ @@ -2175,9 +2229,9 @@ def events(): continue try: for ibq in game.state.baseq: - for cmdr in game.state.kcmdr: - if ibq == cmdr and ibq != game.quadrant and ibq != game.state.kscmdr: - raise JumpOut + for cmdr in game.state.kcmdr: + if ibq == cmdr and ibq != game.quadrant and ibq != game.state.kscmdr: + raise JumpOut else: # no match found -- try later schedule(FBATTAK, expran(0.3*game.intime)) @@ -2211,7 +2265,7 @@ def events(): game.battle = game.state.kscmdr destroybase() elif evcode == FCDBAS: # Commander succeeds in destroying base - if evcode==FCDBAS: + if evcode == FCDBAS: unschedule(FCDBAS) if not game.state.baseq() \ or not game.state.galaxy[game.battle.i][game.battle.j].starbase: @@ -2232,7 +2286,7 @@ def events(): supercommander() elif evcode == FDSPROB: # Move deep space probe schedule(FDSPROB, 0.01) - if not game.probe.next(): + if not game.probe.nexttok(): if not game.probe.quadrant().valid_quadrant() or \ game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j].supernova: # Left galaxy or ran into supernova @@ -2250,18 +2304,18 @@ def events(): #announce() skip(1) prout(_("Lt. Uhura- \"The deep space probe is now in Quadrant %s.\"") % game.probe.quadrant()) - pdest = game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j] + pquad = game.probe.quadrant() + pdest = game.state.galaxy[pquad.i][pquad.j] if communicating(): - chp = game.state.chart[game.probe.quadrant().i][game.probe.quadrant().j] - chp.klingons = pdest.klingons - chp.starbase = pdest.starbase - chp.stars = pdest.stars + game.state.chart[pquad.i][pquad.j].klingons = pdest.klingons + game.state.chart[pquad.i][pquad.j].starbase = pdest.starbase + game.state.chart[pquad.i][pquad.j].stars = pdest.stars pdest.charted = True game.probe.moves -= 1 # One less to travel if game.probe.arrived() and game.isarmed and pdest.stars: supernova(game.probe) # fire in the hole! unschedule(FDSPROB) - if game.state.galaxy[game.quadrant().i][game.quadrant().j].supernova: + if game.state.galaxy[pquad.i][pquad.j].supernova: return elif evcode == FDISTR: # inhabited system issues distress call unschedule(FDISTR) @@ -2289,7 +2343,7 @@ def events(): # tell the captain about it if we can if communicating(): prout(_("Uhura- Captain, %s in Quadrant %s reports it is under attack") \ - % (q.planet, `w`)) + % (q.planet, repr(w))) prout(_("by a Klingon invasion fleet.")) if cancelrest(): return @@ -2320,7 +2374,7 @@ def events(): if q.klingons <= 0: q.status = "secure" continue - if game.state.remkl >=MAXKLGAME: + if game.state.remkl >= MAXKLGAME: continue # full right now # reproduce one Klingon w = ev.quadrant @@ -2363,7 +2417,7 @@ def wait(): "Wait on events." game.ididit = False while True: - key = scanner.next() + key = scanner.nexttok() if key != "IHEOL": break proutn(_("How long? ")) @@ -2431,7 +2485,7 @@ def nova(nov): start = hits.pop() for offset.i in range(-1, 1+1): for offset.j in range(-1, 1+1): - if offset.j==0 and offset.i==0: + if offset.j == 0 and offset.i == 0: continue neighbor = start + offset if not neighbor.valid_sector(): @@ -2458,7 +2512,7 @@ def nova(nov): if iquad == 'P': game.state.nplankl += 1 else: - game.state.worldkl += 1 + game.state.nworldkl += 1 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed.")) game.iplnet.pclass = "destroyed" game.iplnet = None @@ -2663,7 +2717,7 @@ def selfdestruct(): skip(1) prout(_("SELF-DESTRUCT-SEQUENCE-WILL-BE-ABORTED")) skip(1) - scanner.next() + scanner.nexttok() if game.passwd != scanner.token: prouts(_("PASSWORD-REJECTED;")) skip(1) @@ -3090,16 +3144,16 @@ def iostart(): curses.nonl() curses.cbreak() if game.options & OPTION_COLOR: - curses.start_color(); + curses.start_color() curses.use_default_colors() - curses.init_pair(curses.COLOR_BLACK, curses.COLOR_BLACK, -1); - curses.init_pair(curses.COLOR_GREEN, curses.COLOR_GREEN, -1); - curses.init_pair(curses.COLOR_RED, curses.COLOR_RED, -1); - curses.init_pair(curses.COLOR_CYAN, curses.COLOR_CYAN, -1); - curses.init_pair(curses.COLOR_WHITE, curses.COLOR_WHITE, -1); - curses.init_pair(curses.COLOR_MAGENTA, curses.COLOR_MAGENTA, -1); - curses.init_pair(curses.COLOR_BLUE, curses.COLOR_BLUE, -1); - curses.init_pair(curses.COLOR_YELLOW, curses.COLOR_YELLOW, -1); + curses.init_pair(curses.COLOR_BLACK, curses.COLOR_BLACK, -1) + curses.init_pair(curses.COLOR_GREEN, curses.COLOR_GREEN, -1) + curses.init_pair(curses.COLOR_RED, curses.COLOR_RED, -1) + curses.init_pair(curses.COLOR_CYAN, curses.COLOR_CYAN, -1) + curses.init_pair(curses.COLOR_WHITE, curses.COLOR_WHITE, -1) + curses.init_pair(curses.COLOR_MAGENTA, curses.COLOR_MAGENTA, -1) + curses.init_pair(curses.COLOR_BLUE, curses.COLOR_BLUE, -1) + curses.init_pair(curses.COLOR_YELLOW, curses.COLOR_YELLOW, -1) global fullscreen_window, srscan_window, report_window, status_window global lrscan_window, message_window, prompt_window (rows, columns) = stdscr.getmaxyx() @@ -3150,7 +3204,8 @@ def pause_game(): global linecount sys.stdout.write('\n') proutn(prompt) - raw_input() + if not replayfp: + raw_input() sys.stdout.write('\n' * rows) linecount = 0 @@ -3179,6 +3234,9 @@ def proutn(line): if curwnd == message_window and y >= my - 2: pause_game() clrscr() + # Uncomment this to debug curses problems + if logfp: + logfp.write("#curses: at %s proutn(%s)\n" % ((y, x), repr(line))) curwnd.addstr(line) curwnd.refresh() else: @@ -3219,7 +3277,7 @@ def cgetline(): elif line[0] != "#": break else: - line = raw_input() + "\n" + line = input() + "\n" if logfp: logfp.write(line) return line @@ -3228,8 +3286,31 @@ def setwnd(wnd): "Change windows -- OK for this to be a no-op in tty mode." global curwnd if game.options & OPTION_CURSES: + # Uncomment this to debug curses problems + if logfp: + if wnd == fullscreen_window: + legend = "fullscreen" + elif wnd == srscan_window: + legend = "srscan" + elif wnd == report_window: + legend = "report" + elif wnd == status_window: + legend = "status" + elif wnd == lrscan_window: + legend = "lrscan" + elif wnd == message_window: + legend = "message" + elif wnd == prompt_window: + legend = "prompt" + else: + legend = "unknown" + logfp.write("#curses: setwnd(%s)\n" % legend) curwnd = wnd - curses.curs_set(wnd == fullscreen_window or wnd == message_window or wnd == prompt_window) + # Some curses implementations get confused when you try this. + try: + curses.curs_set(wnd in (fullscreen_window, message_window, prompt_window)) + except curses.error: + pass def clreol(): "Clear to end of line -- can be a no-op in tty mode" @@ -3241,47 +3322,47 @@ def clrscr(): "Clear screen -- can be a no-op in tty mode." global linecount if game.options & OPTION_CURSES: - curwnd.clear() - curwnd.move(0, 0) - curwnd.refresh() + curwnd.clear() + curwnd.move(0, 0) + curwnd.refresh() linecount = 0 def textcolor(color=DEFAULT): if game.options & OPTION_COLOR: if color == DEFAULT: - curwnd.attrset(0); + curwnd.attrset(0) elif color == BLACK: - curwnd.attron(curses.color_pair(curses.COLOR_BLACK)); + curwnd.attron(curses.color_pair(curses.COLOR_BLACK)) elif color == BLUE: - curwnd.attron(curses.color_pair(curses.COLOR_BLUE)); + curwnd.attron(curses.color_pair(curses.COLOR_BLUE)) elif color == GREEN: - curwnd.attron(curses.color_pair(curses.COLOR_GREEN)); + curwnd.attron(curses.color_pair(curses.COLOR_GREEN)) elif color == CYAN: - curwnd.attron(curses.color_pair(curses.COLOR_CYAN)); + curwnd.attron(curses.color_pair(curses.COLOR_CYAN)) elif color == RED: - curwnd.attron(curses.color_pair(curses.COLOR_RED)); + curwnd.attron(curses.color_pair(curses.COLOR_RED)) elif color == MAGENTA: - curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA)); + curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA)) elif color == BROWN: - curwnd.attron(curses.color_pair(curses.COLOR_YELLOW)); + curwnd.attron(curses.color_pair(curses.COLOR_YELLOW)) elif color == LIGHTGRAY: - curwnd.attron(curses.color_pair(curses.COLOR_WHITE)); + curwnd.attron(curses.color_pair(curses.COLOR_WHITE)) elif color == DARKGRAY: - curwnd.attron(curses.color_pair(curses.COLOR_BLACK) | curses.A_BOLD); + curwnd.attron(curses.color_pair(curses.COLOR_BLACK) | curses.A_BOLD) elif color == LIGHTBLUE: - curwnd.attron(curses.color_pair(curses.COLOR_BLUE) | curses.A_BOLD); + curwnd.attron(curses.color_pair(curses.COLOR_BLUE) | curses.A_BOLD) elif color == LIGHTGREEN: - curwnd.attron(curses.color_pair(curses.COLOR_GREEN) | curses.A_BOLD); + curwnd.attron(curses.color_pair(curses.COLOR_GREEN) | curses.A_BOLD) elif color == LIGHTCYAN: - curwnd.attron(curses.color_pair(curses.COLOR_CYAN) | curses.A_BOLD); + curwnd.attron(curses.color_pair(curses.COLOR_CYAN) | curses.A_BOLD) elif color == LIGHTRED: - curwnd.attron(curses.color_pair(curses.COLOR_RED) | curses.A_BOLD); + curwnd.attron(curses.color_pair(curses.COLOR_RED) | curses.A_BOLD) elif color == LIGHTMAGENTA: - curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA) | curses.A_BOLD); + curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA) | curses.A_BOLD) elif color == YELLOW: - curwnd.attron(curses.color_pair(curses.COLOR_YELLOW) | curses.A_BOLD); + curwnd.attron(curses.color_pair(curses.COLOR_YELLOW) | curses.A_BOLD) elif color == WHITE: - curwnd.attron(curses.color_pair(curses.COLOR_WHITE) | curses.A_BOLD); + curwnd.attron(curses.color_pair(curses.COLOR_WHITE) | curses.A_BOLD) def highvideo(): if game.options & OPTION_COLOR: @@ -3525,13 +3606,13 @@ def imove(icourse=None, noattack=False): # Move out game.quad[game.sector.i][game.sector.j] = '.' for m in range(icourse.moves): - icourse.next() + icourse.nexttok() w = icourse.sector() if icourse.origin.quadrant() != icourse.location.quadrant(): newquadrant(noattack) break - elif check_collision(icourse, w): - print "Collision detected" + elif check_collision(w): + print("Collision detected") break else: game.sector = w @@ -3612,7 +3693,7 @@ def getcourse(isprobe): navmode = "manual" key = "IHEOL" break - key = scanner.next() + key = scanner.nexttok() if key == "IHEOL": proutn(_("Manual or automatic- ")) iprompt = True @@ -3620,11 +3701,11 @@ def getcourse(isprobe): elif key == "IHALPHA": if scanner.sees("manual"): navmode = "manual" - key = scanner.next() + key = scanner.nexttok() break elif scanner.sees("automatic"): navmode = "automatic" - key = scanner.next() + key = scanner.nexttok() break else: huh() @@ -3646,21 +3727,21 @@ def getcourse(isprobe): proutn(_("Destination sector or quadrant§or- ")) scanner.chew() iprompt = True - key = scanner.next() + key = scanner.nexttok() if key != "IHREAL": huh() raise TrekError xi = int(round(scanner.real))-1 - key = scanner.next() + key = scanner.nexttok() if key != "IHREAL": huh() raise TrekError xj = int(round(scanner.real))-1 - key = scanner.next() + key = scanner.nexttok() if key == "IHREAL": # both quadrant and sector specified xk = int(round(scanner.real))-1 - key = scanner.next() + key = scanner.nexttok() if key != "IHREAL": huh() raise TrekError @@ -3699,13 +3780,13 @@ def getcourse(isprobe): proutn(_("X and Y displacements- ")) scanner.chew() iprompt = True - key = scanner.next() + key = scanner.nexttok() itemp = "verbose" if key != "IHREAL": huh() raise TrekError delta.j = scanner.real - key = scanner.next() + key = scanner.nexttok() if key != "IHREAL": huh() raise TrekError @@ -3748,7 +3829,7 @@ class course: self.step = 0 def arrived(self): return self.location.roundtogrid() == self.final - def next(self): + def nexttok(self): "Next step on course." self.step += 1 self.nextlocation = self.location + self.increment @@ -3794,7 +3875,7 @@ def impulse(): scanner.chew() return # Make sure enough time is left for the trip - game.optime = course.dist/0.095 + game.optime = course.distance/0.095 if game.optime >= game.state.remtime: prout(_("First Officer Spock- \"Captain, our speed under impulse")) prout(_("power is only 0.95 sectors per stardate. Are you sure")) @@ -3806,9 +3887,9 @@ def impulse(): game.ididit = True if game.alldone: return - power = 20.0 + 100.0*course.dist + power = 20.0 + 100.0*course.distance game.energy -= power - game.optime = course.dist/0.095 + game.optime = course.distance/0.095 if game.energy <= 0: finish(FNRG) return @@ -3844,7 +3925,7 @@ def warp(wcourse, involuntary): skip(1) prout(_("Engineering to bridge--")) if not game.shldup or 0.5*wcourse.power(game.warpfac) > game.energy: - iwarp = (game.energy/(wcourse.dist+0.05)) ** 0.333333333 + iwarp = (game.energy/(wcourse.distance+0.05)) ** 0.333333333 if iwarp <= 0: prout(_("We can't do it, Captain. We don't have enough energy.")) else: @@ -3892,7 +3973,7 @@ def warp(wcourse, involuntary): look = wcourse.moves while look > 0: look -= 1 - wcourse.next() + wcourse.nexttok() w = wcourse.sector() if not w.valid_sector(): break @@ -3901,7 +3982,7 @@ def warp(wcourse, involuntary): twarp = False wcourse.reset() # Activate Warp Engines and pay the cost - imove(course, noattack=False) + imove(wcourse, noattack=False) if game.alldone: return game.energy -= wcourse.power(game.warpfac) @@ -3922,7 +4003,7 @@ def warp(wcourse, involuntary): def setwarp(): "Change the warp factor." while True: - key=scanner.next() + key=scanner.nexttok() if key != "IHEOL": break scanner.chew() @@ -4108,7 +4189,7 @@ def probe(): else: prout(_("Uhura- \"The previous probe is still reporting data, Sir.\"")) return - key = scanner.next() + key = scanner.nexttok() if key == "IHEOL": if game.nprobes == 1: prout(_("1 probe left.")) @@ -4120,7 +4201,7 @@ def probe(): game.isarmed = False if key == "IHALPHA" and scanner.token == "armed": game.isarmed = True - key = scanner.next() + key = scanner.nexttok() elif key == "IHEOL": proutn(_("Arm NOVAMAX warhead? ")) game.isarmed = ja() @@ -4205,9 +4286,9 @@ def mayday(): finish(FMATERIALIZE) return game.quad[game.sector.i][game.sector.j]=game.ship - textcolor(GREEN); + textcolor(GREEN) prout(_("succeeds.")) - textcolor(DEFAULT); + textcolor(DEFAULT) dock(False) skip(1) prout(_("Lt. Uhura- \"Captain, we made it!\"")) @@ -4472,7 +4553,7 @@ def beam(): skip(1) prouts("WWHOOOIIIIIRRRRREEEE.E.E. . . . . . .") skip(2) - if withprob(0.98): + if not withprob(0.98): prouts("BOOOIIIOOOIIOOOOIIIOIING . . .") skip(2) prout(_("Scotty- \"Oh my God! I've lost them.\"")) @@ -4961,7 +5042,7 @@ def sectscan(goodScan, i, j): "docked":CYAN, "dead":BROWN}[game.condition]) if game.quad[i][j] != game.ship: - highvideo(); + highvideo() proutn("%c " % game.quad[i][j]) textcolor(DEFAULT) else: @@ -5023,7 +5104,7 @@ def status(req=0): def request(): "Request specified status data, a historical relic from slow TTYs." requests = ("da","co","po","ls","wa","en","to","sh","kl","sy", "ti") - while scanner.next() == "IHEOL": + while scanner.nexttok() == "IHEOL": proutn(_("Information desired? ")) scanner.chew() if scanner.token in requests: @@ -5067,21 +5148,21 @@ def eta(): prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR.")) skip(1) return - if scanner.next() != "IHREAL": + if scanner.nexttok() != "IHREAL": prompt = True scanner.chew() proutn(_("Destination quadrant and/or sector? ")) - if scanner.next()!="IHREAL": + if scanner.nexttok()!="IHREAL": huh() return w1.j = int(scanner.real-0.5) - if scanner.next() != "IHREAL": + if scanner.nexttok() != "IHREAL": huh() return w1.i = int(scanner.real-0.5) - if scanner.next() == "IHREAL": + if scanner.nexttok() == "IHREAL": w2.j = int(scanner.real-0.5) - if scanner.next() != "IHREAL": + if scanner.nexttok() != "IHREAL": huh() return w2.i = int(scanner.real-0.5) @@ -5105,7 +5186,7 @@ def eta(): while True: scanner.chew() proutn(_("Time or arrival date? ")) - if scanner.next()=="IHREAL": + if scanner.nexttok()=="IHREAL": ttime = scanner.real if ttime > game.state.date: ttime -= game.state.date # Actually a star date @@ -5119,7 +5200,7 @@ def eta(): break scanner.chew() proutn(_("Warp factor? ")) - if scanner.next()== "IHREAL": + if scanner.nexttok()== "IHREAL": wfl = True twarp = scanner.real if twarp<1.0 or twarp > 10.0: @@ -5137,7 +5218,7 @@ def eta(): if not wfl: return proutn(_("New warp factor to try? ")) - if scanner.next() == "IHREAL": + if scanner.nexttok() == "IHREAL": wfl = True twarp = scanner.real if twarp<1.0 or twarp > 10.0: @@ -5170,7 +5251,7 @@ def eta(): (scheduled(FCDBAS) 10.0: @@ -5196,14 +5277,13 @@ def freeze(boss): "Save game." if boss: scanner.push("emsave.trk") - key = scanner.next() + key = scanner.nexttok() if key == "IHEOL": proutn(_("File name: ")) - key = scanner.next() + key = scanner.nexttok() if key != "IHALPHA": huh() return - scanner.chew() if '.' not in scanner.token: scanner.token += ".trk" try: @@ -5211,21 +5291,21 @@ def freeze(boss): except IOError: prout(_("Can't freeze game as file %s") % scanner.token) return - cPickle.dump(game, fp) + pickle.dump(game, fp) fp.close() + scanner.chew() def thaw(): "Retrieve saved game." global game - game.passwd[0] = '\0' - key = scanner.next() + game.passwd = None + key = scanner.nexttok() if key == "IHEOL": proutn(_("File name: ")) - key = scanner.next() + key = scanner.nexttok() if key != "IHALPHA": huh() return True - scanner.chew() if '.' not in scanner.token: scanner.token += ".trk" try: @@ -5233,8 +5313,9 @@ def thaw(): except IOError: prout(_("Can't thaw game in %s") % scanner.token) return - game = cPickle.load(fp) + game = pickle.load(fp) fp.close() + scanner.chew() return False # I used to find planets @@ -5356,10 +5437,14 @@ def setup(): game.instar = 0 for i in range(GALSIZE): for j in range(GALSIZE): - k = randrange(1, QUADSIZE**2/10+1) + # Can't have more stars per quadrant than fit in one decimal digit, + # if we do the chart representation will break. + k = randrange(1, min(10, QUADSIZE**2/10)) game.instar += k game.state.galaxy[i][j].stars = k # Locate star bases in galaxy + if game.idebug: + prout("=== Allocating %d bases" % game.inbase) for i in range(game.inbase): while True: while True: @@ -5382,6 +5467,8 @@ def setup(): prout("=== Saving base #%d, close to #%d" % (i, j)) if not contflag: break + if game.idebug: + prout("=== Placing base #%d in quadrant %s" % (i, w)) game.state.baseq.append(w) game.state.galaxy[w.i][w.j].starbase = game.state.chart[w.i][w.j].starbase = True # Position ordinary Klingon Battle Cruisers @@ -5497,7 +5584,7 @@ def setup(): prout(_("%d stardates.") % int(game.intime)) proutn(_("%d starbases in ") % game.inbase) for i in range(game.inbase): - proutn(`game.state.baseq[i]`) + proutn(repr(game.state.baseq[i])) proutn(" ") skip(2) proutn(_("The Enterprise is currently in Quadrant %s") % game.quadrant) @@ -5524,9 +5611,9 @@ def choose(): scanner.chew() # if not scanner.inqueue: # Can start with command line options proutn(_("Would you like a regular, tournament, or saved game? ")) - scanner.next() + scanner.nexttok() if scanner.sees("tournament"): - while scanner.next() == "IHEOL": + while scanner.nexttok() == "IHEOL": proutn(_("Type in tournament number-")) if scanner.real == 0: scanner.chew() @@ -5549,10 +5636,10 @@ def choose(): return True if scanner.sees("regular"): break - proutn(_("What is \"%s\"?") % scanner.token) + proutn(_("What is \"%s\"? ") % scanner.token) scanner.chew() while game.length==0 or game.skill==SKILL_NONE: - if scanner.next() == "IHALPHA": + if scanner.nexttok() == "IHALPHA": if scanner.sees("short"): game.length = 1 elif scanner.sees("medium"): @@ -5580,10 +5667,10 @@ def choose(): elif game.skill == SKILL_NONE: proutn(_("Are you a Novice, Fair, Good, Expert, or Emeritus player? ")) # Choose game options -- added by ESR for SST2K - if scanner.next() != "IHALPHA": + if scanner.nexttok() != "IHALPHA": scanner.chew() proutn(_("Choose your game style (plain, almy, fancy or just press enter): ")) - scanner.next() + scanner.nexttok() 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) @@ -5714,7 +5801,7 @@ def newqad(): prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!")) # Put in THING if needed if thing == game.quadrant: - Enemy(type='?', loc=dropin(), + Enemy(etype='?', loc=dropin(), power=randreal(6000,6500.0)+250.0*game.skill) if not damaged(DSRSENS): skip(1) @@ -5731,7 +5818,7 @@ def newqad(): w.j = withprob(0.5) * (QUADSIZE-1) if game.quad[w.i][w.j] == '.': break - game.tholian = Enemy(type='T', loc=w, + game.tholian = Enemy(etype='T', loc=w, power=randrange(100, 500) + 25.0*game.skill) # Reserve unoccupied corners if game.quad[0][0]=='.': @@ -5767,7 +5854,7 @@ def setpassword(): while True: scanner.chew() proutn(_("Please type in a secret password- ")) - scanner.next() + scanner.nexttok() game.passwd = scanner.token if game.passwd != None: break @@ -5836,12 +5923,12 @@ def listCommands(): def helpme(): "Browse on-line help." - key = scanner.next() + key = scanner.nexttok() while True: if key == "IHEOL": setwnd(prompt_window) proutn(_("Help on what command? ")) - key = scanner.next() + key = scanner.nexttok() setwnd(message_window) if key == "IHEOL": return @@ -5899,7 +5986,7 @@ def makemoves(): setwnd(prompt_window) clrscr() proutn("COMMAND> ") - if scanner.next() == "IHEOL": + if scanner.nexttok() == "IHEOL": if game.options & OPTION_CURSES: makechart() continue @@ -5916,12 +6003,12 @@ def makemoves(): abandon_passed = True if cmd == scanner.token.upper() or (not abandon_passed \ and cmd.startswith(scanner.token.upper())): - break; + break if cmd == "": listCommands() continue else: - break; + break if cmd == "SRSCAN": # srscan srscan() elif cmd == "STATUS": # status @@ -5994,7 +6081,7 @@ def makemoves(): elif cmd == "EMEXIT": # Emergency exit clrscr() # Hide screen freeze(True) # forced save - raise SystemExit,1 # And quick exit + raise SystemExit(1) # And quick exit elif cmd == "PROBE": probe() # Launch probe if game.ididit: @@ -6073,7 +6160,7 @@ def crmena(stars, enemy, loctype, w): buf += _("Quadrant ") elif loctype == "sector": buf += _("Sector ") - return buf + `w` + return buf + repr(w) def crmshp(): "Emit our ship name." @@ -6100,7 +6187,7 @@ class sstscanner: self.token = None self.real = 0.0 self.inqueue = [] - def next(self): + def nexttok(self): # Get a token from the user self.real = 0.0 self.token = '' @@ -6151,12 +6238,12 @@ class sstscanner: return int(round(scanner.real)) def getcoord(self): s = Coord() - scanner.next() + scanner.nexttok() if scanner.type != "IHREAL": huh() return None s.i = scanner.int()-1 - scanner.next() + scanner.nexttok() if scanner.type != "IHREAL": huh() return None @@ -6169,7 +6256,7 @@ def ja(): "Yes-or-no confirmation." scanner.chew() while True: - scanner.next() + scanner.nexttok() if scanner.token == 'y': return True if scanner.token == 'n': @@ -6209,7 +6296,7 @@ def debugme(): for i in range(NDEVICES): proutn("Kill %s?" % device[i]) scanner.chew() - key = scanner.next() + key = scanner.nexttok() if key == "IHALPHA" and scanner.sees("y"): game.damage[i] = 10.0 proutn("Examine/change events? ") @@ -6240,7 +6327,7 @@ def debugme(): proutn("never") proutn("? ") scanner.chew() - key = scanner.next() + key = scanner.nexttok() if key == 'n': unschedule(i) scanner.chew() @@ -6249,7 +6336,7 @@ def debugme(): if i == FENSLV or i == FREPRO: scanner.chew() proutn("In quadrant- ") - key = scanner.next() + key = scanner.nexttok() # "IHEOL" says to leave coordinates as they are if key != "IHEOL": if key != "IHREAL": @@ -6257,7 +6344,7 @@ def debugme(): unschedule(i) continue w.i = int(round(scanner.real)) - key = scanner.next() + key = scanner.nexttok() if key != "IHREAL": prout("Event %d canceled, no y coordinate." % (i)) unschedule(i) @@ -6275,8 +6362,7 @@ if __name__ == '__main__': try: global line, thing, game game = None - thing = Coord() - thing.angry = False + thing = Thingy() game = Gamestate() game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY) if os.getenv("TERM"): @@ -6285,20 +6371,22 @@ if __name__ == '__main__': game.options |= OPTION_TTY seed = int(time.time()) (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:txV") + replay = False for (switch, val) in options: if switch == '-r': try: replayfp = open(val, "r") except IOError: sys.stderr.write("sst: can't open replay file %s\n" % val) - raise SystemExit, 1 + raise SystemExit(1) try: line = replayfp.readline().strip() - (leader, key, seed) = line.split() + (leader, __, seed) = line.split() seed = eval(seed) sys.stderr.write("sst2k: seed set to %s\n" % seed) line = replayfp.readline().strip() arguments += line.split()[2:] + replay = True except ValueError: sys.stderr.write("sst: replay file %s is ill-formed\n"% val) raise SystemExit(1) @@ -6312,11 +6400,11 @@ if __name__ == '__main__': elif switch == '-x': game.idebug = True elif switch == '-V': - print "SST2K", version - raise SystemExit, 0 + print("SST2K", version) + raise SystemExit(0) else: sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n") - raise SystemExit, 1 + raise SystemExit(1) # where to save the input in case of bugs if "TMPDIR" in os.environ: tmpdir = os.environ['TMPDIR'] @@ -6330,6 +6418,7 @@ if __name__ == '__main__': if logfp: logfp.write("# seed %s\n" % seed) logfp.write("# options %s\n" % " ".join(arguments)) + logfp.write("# SST2K version %s\n" % version) logfp.write("# recorded by %s@%s on %s\n" % \ (getpass.getuser(),socket.gethostname(),time.ctime())) random.seed(seed) @@ -6347,6 +6436,8 @@ if __name__ == '__main__': game.alldone = False else: makemoves() + if replay: + break skip(1) stars() skip(1) @@ -6364,10 +6455,10 @@ if __name__ == '__main__': prout(_("May the Great Bird of the Galaxy roost upon your home planet.")) finally: ioend() - raise SystemExit, 0 + raise SystemExit(0) except KeyboardInterrupt: if logfp: logfp.close() - print "" + print("") # End.