X-Git-Url: https://jxself.org/git/?p=super-star-trek.git;a=blobdiff_plain;f=sst.py;h=ee6b58a2347e7f2999c26a10795c15598a5dcc6d;hp=0ceee43cb96fc5a64510968da1eb7e9e8eced891;hb=c36101676b6d3eff229ca7fe7fcba2729a2791e0;hpb=70b24716c08b339efe521907e18822bba3afdb30 diff --git a/sst.py b/sst.py old mode 100644 new mode 100755 index 0ceee43..ee6b58a --- a/sst.py +++ b/sst.py @@ -13,9 +13,12 @@ on how to modify (and how not to modify!) this code. """ import os, sys, math, curses, time, readline, cPickle, random, copy, gettext, getpass +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 @@ -50,17 +53,20 @@ LIGHTMAGENTA = 13 YELLOW = 14 WHITE = 15 -class TrekError: +class TrekError(Exception): pass -class coord: +class JumpOut(Exception): + pass + +class Coord: def __init__(self, x=None, y=None): 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): @@ -70,28 +76,29 @@ class coord: def __ne__(self, other): return other == None or self.i != other.i or self.j != other.j def __add__(self, other): - return coord(self.i+other.i, self.j+other.j) + return Coord(self.i+other.i, self.j+other.j) def __sub__(self, other): - return coord(self.i-other.i, self.j-other.j) + return Coord(self.i-other.i, self.j-other.j) def __mul__(self, other): - return coord(self.i*other, self.j*other) + return Coord(self.i*other, self.j*other) def __rmul__(self, other): - return coord(self.i*other, self.j*other) + return Coord(self.i*other, self.j*other) def __div__(self, other): - return coord(self.i/other, self.j/other) + return Coord(self.i/other, self.j/other) def __mod__(self, other): - return coord(self.i % other, self.j % other) + return Coord(self.i % other, self.j % other) def __rdiv__(self, other): - return coord(self.i/other, self.j/other) + return Coord(self.i/other, self.j/other) def roundtogrid(self): - return coord(int(round(self.i)), int(round(self.j))) + 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) def sgn(self): - s = coord() + s = Coord() if self.i == 0: s.i = 0 else: @@ -107,7 +114,7 @@ class coord: def sector(self): return self.roundtogrid() % QUADSIZE def scatter(self): - s = coord() + s = Coord() s.i = self.i + randrange(-1, 2) s.j = self.j + randrange(-1, 2) return s @@ -117,10 +124,18 @@ class coord: return "%s - %s" % (self.i+1, self.j+1) __repr__ = __str__ -class planet: +class Thingy(Coord): + "Do not anger the Space Thingy!" + def __init__(self): + Coord.__init__(self) + self.angered = False + def angry(self): + self.angered = True + +class Planet: def __init__(self): self.name = None # string-valued if inhabited - self.quadrant = coord() # quadrant located + self.quadrant = Coord() # quadrant located 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" @@ -128,7 +143,7 @@ class planet: def __str__(self): return self.name -class quadrant: +class Quadrant: def __init__(self): self.stars = 0 self.planet = None @@ -139,7 +154,7 @@ class quadrant: self.charted = False self.status = "secure" # Could be "secure", "distressed", "enslaved" -class page: +class Page: def __init__(self): self.stars = None self.starbase = None @@ -154,7 +169,7 @@ def fill2d(size, fillfun): lst[i].append(fillfun(i, j)) return lst -class snapshot: +class Snapshot: def __init__(self): self.snap = False # snapshot taken self.crew = 0 # crew complement @@ -171,13 +186,13 @@ class snapshot: self.remtime = 0 # remaining time self.baseq = [] # Base quadrant coordinates self.kcmdr = [] # Commander quadrant coordinates - self.kscmdr = coord() # Supercommander quadrant coordinates + self.kscmdr = Coord() # Supercommander quadrant coordinates # the galaxy - self.galaxy = fill2d(GALSIZE, lambda i, j: quadrant()) + self.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant()) # the starchart - self.chart = fill2d(GALSIZE, lambda i, j: page()) + self.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page()) -class event: +class Event: def __init__(self): self.date = None # A real number self.quadrant = None # A coord structure @@ -203,23 +218,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 @@ -228,8 +243,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) @@ -249,12 +266,13 @@ 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 - self.location = coord() +class Enemy: + def __init__(self, etype=None, loc=None, power=None): + self.type = etype + self.location = Coord() if loc: self.move(loc) self.power = power # enemy energy level @@ -272,24 +290,26 @@ class enemy: game.quad[self.location.i][self.location.j] = self.type self.kdist = self.kavgd = (game.sector - loc).distance() else: - self.location = coord() + self.location = Coord() self.kdist = self.kavgd = None game.enemies.remove(self) return motion def __repr__(self): return "<%s,%s.%f>" % (self.type, self.location, self.power) # For debugging -class gamestate: +class Gamestate: def __init__(self): self.options = None # Game options - self.state = snapshot() # A snapshot structure - self.snapsht = snapshot() # Last snapshot taken for time-travel purposes + self.state = Snapshot() # A snapshot structure + self.snapsht = Snapshot() # Last snapshot taken for time-travel purposes self.quad = None # contents of our quadrant self.damage = [0.0] * NDEVICES # damage encountered - self.future = [] # future events - for i in range(NEVENTS): - self.future.append(event()) - self.passwd = None; # Self Destruct password + self.future = [] # future events + i = NEVENTS + while i > 0: + i -= 1 + self.future.append(Event()) + 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 @@ -356,6 +376,9 @@ class gamestate: self.cryprob = 0.0 # probability that crystal will work self.probe = None # object holding probe course info self.height = 0.0 # height of orbit around planet + self.score = 0.0 # overall score + self.perdate = 0.0 # rate of kills + self.idebug = False # Debugging instrumentation enabled? def recompute(self): # Stas thinks this should be (C expression): # game.state.remkl + len(game.state.kcmdr) > 0 ? @@ -363,7 +386,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 @@ -412,13 +435,13 @@ def welcoming(iq): def tryexit(enemy, look, irun): "A bad guy attempts to bug out." - iq = coord() + iq = Coord() 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': @@ -435,7 +458,7 @@ def tryexit(enemy, look, irun): 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).") % q)) + (_(" escapes to Quadrant %s (and regains strength).") % iq)) # handle local matters related to escape enemy.move(None) game.klhere -= 1 @@ -444,19 +467,19 @@ 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[n] = iq + game.state.kcmdr.append(iq) break - return True; # success + return True # success # The bad-guy movement algorithm: # @@ -498,7 +521,8 @@ def tryexit(enemy, look, irun): def movebaddy(enemy): "Tactical movement for the bad guys." - next = 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: @@ -506,9 +530,9 @@ def movebaddy(enemy): else: nbaddys = (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant) dist1 = enemy.kdist - mdist = int(dist1 + 0.5); # Nearest integer distance + mdist = int(dist1 + 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 @@ -516,7 +540,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 @@ -535,12 +559,12 @@ def movebaddy(enemy): 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 ! + if game.condition == "docked" and (game.options & OPTION_BASE): # protected by base -- back off ! motion -= game.skill*(2.0-randreal()**2) - if idebug: + if game.idebug: proutn("=== MOTION = %d, FORCES = %1.2f, " % (motion, forces)) # don't move if no motion - if motion==0: + if motion == 0: return # Limit motion according to skill if abs(motion) > game.skill: @@ -551,12 +575,12 @@ 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 - if idebug: + nsteps = 1 # This shouldn't be necessary + if game.idebug: proutn("NSTEPS = %d:" % nsteps) # Compute preferred values of delta X and Y m = game.sector - enemy.location @@ -565,13 +589,13 @@ def movebaddy(enemy): if 2.0 * abs(m.j) < abs(game.sector.i-enemy.location.i): m.j = 0 m = (motion * m).sgn() - next = enemy.location + goto = enemy.location # main move loop for ll in range(nsteps): - if idebug: + if game.idebug: proutn(" %d" % (ll+1)) # Check if preferred position available - look = next + m + look = goto + m if m.i < 0: krawli = 1 else: @@ -581,7 +605,7 @@ 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: @@ -589,14 +613,14 @@ def movebaddy(enemy): return if krawli == m.i or m.j == 0: break - look.i = next.i + krawli + 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 krawlj == m.j or m.i == 0: break - look.j = next.j + krawlj + look.j = goto.j + krawlj krawlj = -krawlj elif (game.options & OPTION_RAMMING) and game.quad[look.i][look.j] != '.': # See if enemy should ram ship @@ -605,35 +629,35 @@ def movebaddy(enemy): collision(rammed=True, enemy=enemy) return if krawli != m.i and m.j != 0: - look.i = next.i + krawli + look.i = goto.i + krawli krawli = -krawli elif krawlj != m.j and m.i != 0: - look.j = next.j + krawlj + look.j = goto.j + krawlj krawlj = -krawlj else: - break; # we have failed + break # we have failed else: success = True if success: - next = look - if idebug: - proutn(`next`) + goto = look + if game.idebug: + proutn(repr(goto)) else: - break; # done early - if idebug: + break # done early + if game.idebug: skip(1) - if enemy.move(next): + 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." % next) + prout("Sector %s." % goto) def moveklings(): "Sequence Klingon tactical movement." - if idebug: + if game.idebug: prout("== MOVCOM") # Figure out which Klingon is the commander (or Supercommander) # and do move @@ -641,7 +665,7 @@ def moveklings(): for enemy in game.enemies: if enemy.type == 'C': movebaddy(enemy) - if game.state.kscmdr==game.quadrant: + if game.state.kscmdr == game.quadrant: for enemy in game.enemies: if enemy.type == 'S': movebaddy(enemy) @@ -653,7 +677,7 @@ def moveklings(): for enemy in game.enemies: if enemy.type in ('K', 'R'): movebaddy(enemy) - game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist)) + sortenemies() def movescom(iq, avoid): "Commander movement helper." @@ -666,10 +690,10 @@ 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: @@ -679,7 +703,7 @@ def movescom(iq, avoid): game.klhere -= 1 if game.condition != "docked": newcnd() - game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist)) + sortenemies() # check for a helpful planet for i in range(game.inplan): if game.state.planets[i].quadrant == game.state.kscmdr and \ @@ -693,13 +717,16 @@ 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 idebug: + if game.idebug: prout("== SUPERCOMMANDER") # Decide on being active or passive avoid = ((game.incom - len(game.state.kcmdr) + game.inkling - game.state.remkl)/(game.state.date+0.01-game.indate) < 0.1*game.skill*(game.skill+1.0) or \ @@ -718,16 +745,16 @@ def supercommander(): unschedule(FSCMOVE) return sc = game.state.kscmdr - for base in game.state.baseq: + for (i, base) in enumerate(game.state.baseq): basetbl.append((i, (base - sc).distance())) if game.state.baseq > 1: - basetbl.sort(lambda x, y: cmp(x[1]. y[1])) + basetbl.sort(lambda x, y: cmp(x[1], y[1])) # look for nearest base without a commander, no Enterprise, and # 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 @@ -740,7 +767,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 @@ -753,7 +780,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 @@ -798,13 +825,13 @@ def supercommander(): if not game.resting: return prout(_("Mr. Spock- \"Captain, shall we cancel the rest period?\"")) - if ja() == False: + 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 idebug and \ + if not game.idebug and \ (withprob(0.8) or \ (not communicating()) or \ not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].charted): @@ -818,47 +845,51 @@ def movetholian(): "Move the Tholian." if not game.tholian or game.justin: return - id = coord() + tid = Coord() if game.tholian.location.i == 0 and game.tholian.location.j == 0: - id.i = 0; id.j = QUADSIZE-1 + tid.i = 0 + tid.j = QUADSIZE-1 elif game.tholian.location.i == 0 and game.tholian.location.j == QUADSIZE-1: - id.i = QUADSIZE-1; id.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: - id.i = QUADSIZE-1; id.j = 0 + tid.i = QUADSIZE-1 + tid.j = 0 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == 0: - id.i = 0; id.j = 0 + tid.i = 0 + tid.j = 0 else: # something is wrong! game.tholian.move(None) prout("***Internal error: Tholian in a bad spot.") return # do nothing if we are blocked - if game.quad[id.i][id.j] not in ('.', '#'): + if game.quad[tid.i][tid.j] not in ('.', '#'): return here = copy.copy(game.tholian.location) - delta = (id - game.tholian.location).sgn() + delta = (tid - game.tholian.location).sgn() # move in x axis - while here.i != id.i: + 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 != id.j: + 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) @@ -885,27 +916,27 @@ 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() == True: + if ja(): action = "NRG" elif damaged(DSHIELD): prout(_("Shields damaged and down.")) return elif game.shldup: proutn(_("Shields are up. Do you want them down? ")) - if ja() == True: + if ja(): action = "SHDN" else: scanner.chew() return else: proutn(_("Shields are down. Do you want them up? ")) - if ja() == True: + if ja(): action = "SHUP" else: scanner.chew() - return + return if action == "SHUP": # raise shields if game.shldup: prout(_("Shields already up.")) @@ -920,14 +951,14 @@ 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 @@ -994,12 +1025,12 @@ def randdevice(): ) assert(sum(weights) == 1000) idx = randrange(1000) - sum = 0 + wsum = 0 for (i, w) in enumerate(weights): - sum += w - if idx < sum: + 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." @@ -1019,16 +1050,17 @@ def collision(rammed, enemy): proutn(_(" (original position)")) skip(1) deadkl(enemy.location, enemy.type, game.sector) - proutn("***" + crmship() + " heavily damaged.") + proutn("***" + crmshp() + " heavily damaged.") icas = randrange(10, 30) - prout(_("***Sickbay reports %d casualties"), icas) + prout(_("***Sickbay reports %d casualties") % icas) game.casual += icas game.state.crew -= icas # In the pre-SST2K version, all devices got equiprobably damaged, # which was silly. Instead, pick up to half the devices at # random according to our weighting table, ncrits = randrange(NDEVICES/2) - for m in range(ncrits): + while ncrits > 0: + ncrits -= 1 dev = randdevice() if game.damage[dev] < 0: continue @@ -1046,57 +1078,59 @@ 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) ac = bearing + 0.25*dispersion # dispersion is a random variable bullseye = (15.0 - bearing)*0.5235988 track = course(bearing=ac, distance=QUADSIZE, origin=cartesian(origin)) - bumpto = coord(0, 0) + bumpto = Coord(0, 0) # Loop to move a single torpedo setwnd(message_window) for step in range(1, QUADSIZE*2): - if not track.next(): break + if not track.next(): + break w = track.sector() if not w.valid_sector(): break - iquad=game.quad[w.i][w.j] - tracktorpedo(origin, w, step, number, nburst, iquad) - if iquad=='.': + iquad = game.quad[w.i][w.j] + tracktorpedo(w, step, number, nburst, 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 = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5) displacement.next() 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() - game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist)) + sortenemies() return None elif iquad in ('C', 'S', 'R', 'K'): # Hit a regular enemy # find the enemy @@ -1121,7 +1155,7 @@ def torpedo(origin, bearing, dispersion, number, nburst): 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 = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5) displacement.next() bumpto = displacement.sector() if not bumpto.valid_sector(): @@ -1135,17 +1169,17 @@ def torpedo(origin, bearing, dispersion, number, nburst): 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 + 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() - game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist)) + sortenemies() 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 @@ -1198,8 +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 - shoved = True + thing.angry() return None elif iquad == ' ': # Black hole skip(1) @@ -1211,7 +1244,7 @@ def torpedo(origin, bearing, dispersion, number, nburst): return None elif iquad == 'T': # Hit a Tholian h1 = 700.0 + randrange(100) - \ - 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-angle)) + 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle)) h1 = math.fabs(h1) if h1 >= 600: game.quad[w.i][w.j] = '.' @@ -1237,7 +1270,7 @@ def torpedo(origin, bearing, dispersion, number, nburst): break skip(1) prout(_("Torpedo missed.")) - return None; + return None def fry(hit): "Critical-hit resolution." @@ -1247,11 +1280,12 @@ def fry(hit): proutn(_("***CRITICAL HIT--")) # Select devices and cause damage cdam = [] - for loop1 in range(ncrit): + 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)) @@ -1267,7 +1301,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 @@ -1275,10 +1309,13 @@ 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 idebug: + if game.idebug: prout("=== ATTACK!") # Tholian gets to move before attacking if game.tholian: @@ -1288,10 +1325,10 @@ 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: + 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 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 == game.quadrant and not thing.angered): return # set up partial hits if attack happens during shield status change pfac = 1.0/game.inshld @@ -1303,33 +1340,33 @@ 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 - course = 1.90985*math.atan2(game.sector.j-enemy.location.j, enemy.location.i-game.sector.i) + pcourse = 1.90985*math.atan2(game.sector.j-enemy.location.j, enemy.location.i-game.sector.i) hit = 0 proutn(_("***TORPEDO INCOMING")) if not damaged(DSRSENS): @@ -1338,19 +1375,19 @@ def attack(torps_ok): prout(" ") dispersion = (randreal()+randreal())*0.5 - 0.5 dispersion += 0.002*enemy.power*dispersion - hit = torpedo(enemy.location, course, dispersion, number=1, nburst=1) - if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0: - finish(FWON); # Klingons did themselves in! + 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.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": - propr *= 2.1 + if game.condition == "docked": + propor *= 2.1 if propor < 0.1: propor = 0.1 hitsh = propor*chgfac*hit+1.0 @@ -1412,23 +1449,23 @@ def attack(torps_ok): # After attack, reset average distance to enemies for enemy in game.enemies: enemy.kavgd = enemy.kdist - game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist)) + sortenemies() return -def deadkl(w, type, mv): +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 @@ -1454,7 +1491,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 @@ -1469,11 +1506,11 @@ def targetcheck(w): if not w.valid_sector(): 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); - if delta == coord(0, 0): + delta = Coord() + # 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,")) prout(_(" I recommend an immediate review of")) @@ -1484,7 +1521,7 @@ def targetcheck(w): def torps(): "Launch photon torpedo salvo." - course = [] + tcourse = [] game.ididit = False if damaged(DPHOTON): prout(_("Photon tubes damaged.")) @@ -1522,21 +1559,21 @@ def torps(): 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": + 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]) - course.append(course[0]) + tcourse.append(tcourse[0]) i += 1 break scanner.push(scanner.token) target.append(scanner.getcoord()) if target[-1] == None: return - course.append(targetcheck(target[-1])) - if course[-1] == None: + tcourse.append(targetcheck(target[-1])) + if tcourse[-1] == None: return scanner.chew() if len(target) == 0: @@ -1547,8 +1584,8 @@ def torps(): target.append(scanner.getcoord()) if target[-1] == None: return - course.append(targetcheck(target[-1])) - if course[-1] == None: + tcourse.append(targetcheck(target[-1])) + if tcourse[-1] == None: return game.ididit = True # Loop for moving torpedoes @@ -1572,11 +1609,11 @@ def torps(): break if game.shldup or game.condition == "docked": dispersion *= 1.0 + 0.0001*game.shield - torpedo(game.sector, course[i], dispersion, number=i, nburst=n) + torpedo(game.sector, tcourse[i], dispersion, number=i, nburst=n) 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); + if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)<=0: + finish(FWON) def overheat(rpow): "Check for phasers overheating." @@ -1620,18 +1657,17 @@ 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." - nenhr2 = len(game.enemies); kk=0 - w = coord() + w = Coord() skip(1) - for (k, wham) in enumerate(hits): - if wham==0: + for (kk, wham) in enumerate(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: @@ -1649,20 +1685,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 @@ -1672,10 +1708,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): @@ -1701,15 +1743,15 @@ 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.next() 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() @@ -1753,18 +1795,18 @@ def phasers(): key = scanner.next() 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": + if key != "IHREAL": return rpow = scanner.real if rpow > avail: @@ -1773,15 +1815,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.next() 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() @@ -1794,7 +1836,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 @@ -1843,13 +1885,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): @@ -1867,7 +1909,7 @@ def phasers(): 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: @@ -1881,7 +1923,7 @@ def phasers(): prout(_("Available energy exceeded -- try again.")) scanner.chew() return - key = scanner.next(); # scan for next value + key = scanner.next() # scan for next value k += 1 if rpow == 0.0: # zero energy -- abort @@ -1912,7 +1954,7 @@ def phasers(): prout(_("Shields raised.")) else: game.shldup = False - overheat(rpow); + overheat(rpow) # Code from events,c begins here. @@ -1948,7 +1990,7 @@ def cancelrest(): if game.resting: skip(1) proutn(_("Mr. Spock- \"Captain, shall we cancel the rest period?\"")) - if ja() == True: + if ja(): game.resting = False game.optime = 0.0 return True @@ -1956,11 +1998,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." @@ -2041,7 +2087,7 @@ def events(): game.isatb = 0 else: game.battle.invalidate() - if idebug: + if game.idebug: prout("=== EVENTS from %.2f to %.2f:" % (game.state.date, fintim)) for i in range(1, NEVENTS): if i == FSNOVA: proutn("=== Supernova ") @@ -2070,7 +2116,7 @@ def events(): for l in range(1, NEVENTS): if game.future[l].date < datemin: evcode = l - if idebug: + if game.idebug: prout("== Event %d fires" % evcode) datemin = game.future[l].date xtime = datemin-game.state.date @@ -2078,11 +2124,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? @@ -2126,7 +2172,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 \ @@ -2164,15 +2210,15 @@ 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 ibq + 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)) unschedule(FCDBAS) continue - except coord: + except JumpOut: pass # commander + starbase combination found -- launch attack game.battle = ibq @@ -2200,7 +2246,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: @@ -2268,7 +2314,7 @@ def events(): break else: # can't seem to find one; ignore this call - if idebug: + if game.idebug: prout("=== Couldn't find location for distress event.") continue # got one!! Schedule its enslavement @@ -2278,7 +2324,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 @@ -2309,11 +2355,11 @@ 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 - m = coord() + m = Coord() if game.klhere >= MAXKLQUAD: try: # this quadrant not ok, pick an adjacent one @@ -2325,10 +2371,10 @@ def events(): # check for this quad ok (not full & no snova) if q.klingons >= MAXKLQUAD or q.supernova: continue - raise "FOUNDIT" + raise JumpOut else: continue # search for eligible quadrant failed - except "FOUNDIT": + except JumpOut: w = m # deliver the child game.state.remkl += 1 @@ -2365,7 +2411,7 @@ def wait(): return if delay >= game.state.remtime or len(game.enemies) != 0: proutn(_("Are you sure? ")) - if ja() == False: + if not ja(): return # Alternate resting periods (events) with attacks game.resting = True @@ -2401,8 +2447,8 @@ def wait(): def nova(nov): "Star goes nova." - course = (0.0, 10.5, 12.0, 1.5, 9.0, 0.0, 3.0, 7.5, 6.0, 4.5) - newc = coord(); neighbor = coord(); bump = coord(0, 0) + ncourse = (0.0, 10.5, 12.0, 1.5, 9.0, 0.0, 3.0, 7.5, 6.0, 4.5) + newc = Coord(); neighbor = Coord(); bump = Coord(0, 0) if withprob(0.05): # Wow! We've supernova'ed supernova(game.quadrant) @@ -2416,11 +2462,11 @@ def nova(nov): hits = [nov] kount = 0 while hits: - offset = coord() + offset = Coord() 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(): @@ -2447,7 +2493,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 @@ -2482,7 +2528,7 @@ def nova(nov): finish(FNOVA) return # add in course nova contributes to kicking starship - bump += (game.sector-hits[mm]).sgn() + bump += (game.sector-hits[-1]).sgn() elif iquad == 'K': # kill klingon deadkl(neighbor, iquad, neighbor) elif iquad in ('C','S','R'): # Damage/destroy big enemies @@ -2493,7 +2539,7 @@ def nova(nov): if game.enemies[ll].power <= 0.0: deadkl(neighbor, iquad, neighbor) break - newc = neighbor + neighbor - hits[mm] + newc = neighbor + neighbor - hits[-1] proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged")) if not newc.valid_sector(): # can't leave quadrant @@ -2515,17 +2561,17 @@ def nova(nov): game.enemies[ll].move(newc) # Starship affected by nova -- kick it away. dist = kount*0.1 - direc = course[3*(bump.i+1)+bump.j+2] + direc = ncourse[3*(bump.i+1)+bump.j+2] if direc == 0.0: dist = 0.0 if dist == 0.0: return - course = course(bearing=direc, distance=dist) - game.optime = course.time(warp=4) + scourse = course(bearing=direc, distance=dist) + game.optime = scourse.time(warp=4) skip(1) prout(_("Force of nova displaces starship.")) - imove(course, noattack=True) - game.optime = course.time(warp=4) + imove(scourse, noattack=True) + game.optime = scourse.time(warp=4) return def supernova(w): @@ -2536,7 +2582,7 @@ def supernova(w): else: # Scheduled supernova -- select star at random. stars = 0 - nq = coord() + nq = Coord() for nq.i in range(GALSIZE): for nq.j in range(GALSIZE): stars += game.state.galaxy[nq.i][nq.j].stars @@ -2550,9 +2596,9 @@ def supernova(w): break if num <=0: break - if idebug: + if game.idebug: proutn("=== Super nova here?") - if ja() == True: + if ja(): nq = game.quadrant if not nq == game.quadrant or game.justin: # it isn't here, or we just entered (treat as enroute) @@ -2561,7 +2607,7 @@ def supernova(w): prout(_("Message from Starfleet Command Stardate %.2f") % game.state.date) prout(_(" Supernova in Quadrant %s; caution advised.") % nq) else: - ns = coord() + ns = Coord() # we are in the quadrant! num = randrange(game.state.galaxy[nq.i][nq.j].stars) + 1 for ns.i in range(QUADSIZE): @@ -2653,7 +2699,6 @@ def selfdestruct(): prout(_("SELF-DESTRUCT-SEQUENCE-WILL-BE-ABORTED")) skip(1) scanner.next() - scanner.chew() if game.passwd != scanner.token: prouts(_("PASSWORD-REJECTED;")) skip(1) @@ -2681,11 +2726,9 @@ def kaboom(): skip(1) if len(game.enemies) != 0: whammo = 25.0 * game.energy - l=1 - while l <= len(game.enemies): + for l in range(len(game.enemies)): if game.enemies[l].power*game.enemies[l].kdist <= whammo: deadkl(game.enemies[l].location, game.quad[game.enemies[l].location.i][game.enemies[l].location.j], game.enemies[l].location) - l += 1 finish(FDILITHIUM) def killrate(): @@ -2766,12 +2809,12 @@ def finish(ifin): prout(_("Now you can retire and write your own Star Trek game!")) skip(1) elif game.skill >= SKILL_EXPERT: - if game.thawed and not idebug: + if game.thawed and not game.idebug: prout(_("You cannot get a citation, so...")) else: proutn(_("Do you want your Commodore Emeritus Citation printed? ")) scanner.chew() - if ja() == True: + if ja(): igotit = True # Only grant long life if alive (original didn't!) skip(1) @@ -2909,11 +2952,10 @@ def finish(ifin): def score(): "Compute player's score." timused = game.state.date - game.indate - iskill = game.skill if (timused == 0 or (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0) and timused < 5.0: timused = 5.0 - perdate = killrate() - ithperd = 500*perdate + 0.5 + game.perdate = killrate() + ithperd = 500*game.perdate + 0.5 iwon = 0 if game.gamewon: iwon = 100*game.skill @@ -2923,7 +2965,7 @@ def score(): klship = 1 else: klship = 2 - iscore = 10*(game.inkling - game.state.remkl) \ + game.score = 10*(game.inkling - game.state.remkl) \ + 50*(game.incom - len(game.state.kcmdr)) \ + ithperd + iwon \ + 20*(game.inrom - game.state.nromrem) \ @@ -2931,7 +2973,7 @@ def score(): - game.state.nromrem \ - badpoints() if not game.alive: - iscore -= 200 + game.score -= 200 skip(2) prout(_("Your score --")) if game.inrom - game.state.nromrem: @@ -2951,7 +2993,7 @@ def score(): (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem))) if ithperd: prout(_("%6.2f Klingons per stardate %5d") % - (perdate, ithperd)) + (game.perdate, ithperd)) if game.state.starkl: prout(_("%6d stars destroyed by your action %5d") % (game.state.starkl, -5*game.state.starkl)) @@ -2987,7 +3029,7 @@ def score(): elif game.skill == SKILL_EMERITUS: proutn(_("Emeritus game")) prout(" %5d" % iwon) skip(1) - prout(_("TOTAL SCORE %5d") % iscore) + prout(_("TOTAL SCORE %5d") % game.score) def plaque(): "Emit winner's commemmorative plaque." @@ -3043,8 +3085,8 @@ def plaque(): timestring = time.ctime() fp.write(_(" This day of %.6s %.4s, %.8s\n\n") % (timestring+4, timestring+20, timestring+11)) - fp.write(_(" Your score: %d\n\n") % iscore) - fp.write(_(" Klingons per stardate: %.2f\n") % perdate) + fp.write(_(" Your score: %d\n\n") % game.score) + fp.write(_(" Klingons per stardate: %.2f\n") % game.perdate) fp.close() # Code from io.c begins here @@ -3066,7 +3108,7 @@ def iostart(): "for some recent versions of python2, the following enables UTF8" "for the older ones we probably need to set C locale, and the python3" "has no problems at all" - if sys.version_info.major < 3: + if sys.version_info[0] < 3: import locale locale.setlocale(locale.LC_ALL, "") gettext.bindtextdomain("sst", "/usr/local/share/locale") @@ -3083,16 +3125,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() @@ -3144,24 +3186,18 @@ def pause_game(): sys.stdout.write('\n') proutn(prompt) raw_input() - for j in range(rows): - sys.stdout.write('\n') + sys.stdout.write('\n' * rows) linecount = 0 def skip(i): "Skip i lines. Pause game if this would cause a scrolling event." for dummy in range(i): if game.options & OPTION_CURSES: - (y, x) = curwnd.getyx() - (my, mx) = curwnd.getmaxyx() - if curwnd == message_window and y >= my - 2: - pause_game() - clrscr() - else: - try: - curwnd.move(y+1, 0) - except curses.error: - pass + (y, x) = curwnd.getyx() + try: + curwnd.move(y+1, 0) + except curses.error: + pass else: global linecount linecount += 1 @@ -3173,6 +3209,14 @@ def skip(i): def proutn(line): "Utter a line with no following line feed." if game.options & OPTION_CURSES: + (y, x) = curwnd.getyx() + (my, mx) = curwnd.getmaxyx() + if curwnd == message_window and y >= my - 2: + pause_game() + clrscr() + # 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: @@ -3222,6 +3266,25 @@ 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) @@ -3235,47 +3298,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: @@ -3339,7 +3402,7 @@ def warble(): #nosound() pass -def tracktorpedo(origin, w, step, i, n, iquad): +def tracktorpedo(w, step, i, n, iquad): "Torpedo-track animation." if not game.options & OPTION_CURSES: if step == 1: @@ -3399,9 +3462,9 @@ def prstat(txt, data): # Code from moving.c begins here -def imove(course=None, noattack=False): +def imove(icourse=None, noattack=False): "Movement execution for warp, impulse, supernova, and tractor-beam events." - w = coord() + w = Coord() def newquadrant(noattack): # Leaving quadrant -- allow final enemy attack @@ -3422,17 +3485,17 @@ def imove(course=None, noattack=False): kinks = 0 while True: kink = False - if course.final.i < 0: - course.final.i = -course.final.i + if icourse.final.i < 0: + icourse.final.i = -icourse.final.i kink = True - if course.final.j < 0: - course.final.j = -course.final.j + if icourse.final.j < 0: + icourse.final.j = -icourse.final.j kink = True - if course.final.i >= GALSIZE*QUADSIZE: - course.final.i = (GALSIZE*QUADSIZE*2) - course.final.i + if icourse.final.i >= GALSIZE*QUADSIZE: + icourse.final.i = (GALSIZE*QUADSIZE*2) - icourse.final.i kink = True - if course.final.j >= GALSIZE*QUADSIZE: - course.final.j = (GALSIZE*QUADSIZE*2) - course.final.j + if icourse.final.j >= GALSIZE*QUADSIZE: + icourse.final.j = (GALSIZE*QUADSIZE*2) - icourse.final.j kink = True if kink: kinks += 1 @@ -3451,8 +3514,8 @@ def imove(course=None, noattack=False): # Compute final position in new quadrant if trbeam: # Don't bother if we are to be beamed return - game.quadrant = course.final.quadrant() - game.sector = course.final.sector() + game.quadrant = icourse.final.quadrant() + game.sector = icourse.final.sector() skip(1) prout(_("Entering Quadrant %s.") % game.quadrant) game.quad[game.sector.i][game.sector.j] = game.ship @@ -3464,7 +3527,7 @@ def imove(course=None, noattack=False): iquad = game.quad[h.i][h.j] if iquad != '.': # object encountered in flight path - stopegy = 50.0*course.distance/game.optime + stopegy = 50.0*icourse.distance/game.optime if iquad in ('T', 'K', 'C', 'S', 'R', '?'): for enemy in game.enemies: if enemy.location == game.sector: @@ -3514,14 +3577,14 @@ def imove(course=None, noattack=False): if game.state.date+game.optime >= scheduled(FTBEAM): trbeam = True game.condition = "red" - course.distance = course.distance*(scheduled(FTBEAM)-game.state.date)/game.optime + 0.1 + icourse.distance = icourse.distance*(scheduled(FTBEAM)-game.state.date)/game.optime + 0.1 game.optime = scheduled(FTBEAM) - game.state.date + 1e-5 # Move out game.quad[game.sector.i][game.sector.j] = '.' - for m in range(course.moves): - course.next() - w = course.sector() - if course.origin.quadrant() != course.location.quadrant(): + for m in range(icourse.moves): + icourse.next() + w = icourse.sector() + if icourse.origin.quadrant() != icourse.location.quadrant(): newquadrant(noattack) break elif check_collision(w): @@ -3536,7 +3599,7 @@ def imove(course=None, noattack=False): finald = (w-enemy.location).distance() enemy.kavgd = 0.5 * (finald + enemy.kdist) enemy.kdist = finald - game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist)) + sortenemies() if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova: attack(torps_ok=False) for enemy in game.enemies: @@ -3589,7 +3652,7 @@ def getcourse(isprobe): dquad = copy.copy(game.quadrant) navmode = "unspecified" itemp = "curt" - dsect = coord() + dsect = Coord() iprompt = False if game.landed and not isprobe: prout(_("Dummy! You can't leave standard orbit until you")) @@ -3631,7 +3694,7 @@ def getcourse(isprobe): prout(_("(Manual movement assumed.)")) navmode = "manual" break - delta = coord() + delta = Coord() if navmode == "automatic": while key == "IHEOL": if isprobe: @@ -3731,7 +3794,7 @@ class course: self.origin = cartesian(game.quadrant, game.sector) else: self.origin = cartesian(game.quadrant, origin) - self.increment = coord(-math.sin(self.angle), math.cos(self.angle)) + self.increment = Coord(-math.sin(self.angle), math.cos(self.angle)) bigger = max(abs(self.increment.i), abs(self.increment.j)) self.increment /= bigger self.moves = int(round(10*self.distance*bigger)) @@ -3793,7 +3856,7 @@ def impulse(): prout(_("First Officer Spock- \"Captain, our speed under impulse")) prout(_("power is only 0.95 sectors per stardate. Are you sure")) proutn(_("we dare spend the time?\" ")) - if ja() == False: + if not ja(): return # Activate impulse engines and pay the cost imove(course, noattack=False) @@ -3807,7 +3870,7 @@ def impulse(): finish(FNRG) return -def warp(course, involuntary): +def warp(wcourse, involuntary): "ove under warp drive." blooey = False; twarp = False if not involuntary: # Not WARPX entry @@ -3824,21 +3887,21 @@ def warp(course, involuntary): prout(_(" is repaired, I can only give you warp 4.\"")) return # Read in course and distance - if course==None: + if wcourse==None: try: - course = getcourse(isprobe=False) + wcourse = getcourse(isprobe=False) except TrekError: return # Make sure starship has enough energy for the trip # Note: this formula is slightly different from the C version, # and lets you skate a bit closer to the edge. - if course.power(game.warpfac) >= game.energy: + if wcourse.power(game.warpfac) >= game.energy: # Insufficient power for trip game.ididit = False skip(1) prout(_("Engineering to bridge--")) - if not game.shldup or 0.5*power > game.energy: - iwarp = (game.energy/(course.dist+0.05)) ** 0.333333333 + if not game.shldup or 0.5*wcourse.power(game.warpfac) > game.energy: + iwarp = (game.energy/(wcourse.dist+0.05)) ** 0.333333333 if iwarp <= 0: prout(_("We can't do it, Captain. We don't have enough energy.")) else: @@ -3852,7 +3915,7 @@ def warp(course, involuntary): prout(_("We haven't the energy to go that far with the shields up.")) return # Make sure enough time is left for the trip - game.optime = course.time(game.warpfac) + game.optime = wcourse.time(game.warpfac) if game.optime >= 0.8*game.state.remtime: skip(1) prout(_("First Officer Spock- \"Captain, I compute that such")) @@ -3860,7 +3923,7 @@ def warp(course, involuntary): (100.0*game.optime/game.state.remtime)) prout(_(" percent of our")) proutn(_(" remaining time. Are you sure this is wise?\" ")) - if ja() == False: + if not ja(): game.ididit = False game.optime=0 return @@ -3868,38 +3931,40 @@ def warp(course, involuntary): if game.warpfac > 6.0: # Decide if engine damage will occur # ESR: Seems wrong. Probability of damage goes *down* with distance? - prob = course.distance*(6.0-game.warpfac)**2/66.666666666 + prob = wcourse.distance*(6.0-game.warpfac)**2/66.666666666 if prob > randreal(): blooey = True - course.distance = randreal(course.distance) + wcourse.distance = randreal(wcourse.distance) # Decide if time warp will occur - if 0.5*course.distance*math.pow(7.0,game.warpfac-10.0) > randreal(): + if 0.5*wcourse.distance*math.pow(7.0,game.warpfac-10.0) > randreal(): twarp = True - if idebug and game.warpfac==10 and not twarp: + if game.idebug and game.warpfac==10 and not twarp: blooey = False proutn("=== Force time warp? ") - if ja() == True: + if ja(): twarp = True if blooey or twarp: # If time warp or engine damage, check path - # If it is obstructed, don't do warp or damage - for m in range(course.moves): - course.next() - w = course.sector() + # If it is obstructed, don't do warp or damage + look = wcourse.moves + while look > 0: + look -= 1 + wcourse.next() + w = wcourse.sector() if not w.valid_sector(): break if game.quad[w.i][w.j] != '.': blooey = False twarp = False - course.reset() + wcourse.reset() # Activate Warp Engines and pay the cost - imove(course, noattack=False) + imove(wcourse, noattack=False) if game.alldone: return - game.energy -= course.power(game.warpfac) + game.energy -= wcourse.power(game.warpfac) if game.energy <= 0: finish(FNRG) - game.optime = course.time(game.warpfac) + game.optime = wcourse.time(game.warpfac) if twarp: timwrp() if blooey: @@ -4107,7 +4172,7 @@ def probe(): else: prout(_("%d probes left") % game.nprobes) proutn(_("Are you sure you want to fire a probe? ")) - if ja() == False: + if not ja(): return game.isarmed = False if key == "IHALPHA" and scanner.token == "armed": @@ -4181,7 +4246,7 @@ def mayday(): elif m == 2: proutn(_("2nd")) elif m == 3: proutn(_("3rd")) proutn(_(" attempt to re-materialize ") + crmshp()) - game.quad[ix][iy]=('-','o','O')[m-1] + game.quad[game.sector.i][game.sector.j]=('-','o','O')[m-1] textcolor(RED) warble() if randreal() > probf: @@ -4190,16 +4255,16 @@ def mayday(): textcolor(DEFAULT) curses.delay_output(500) if m > 3: - game.quad[ix][iy]='?' + game.quad[game.sector.i][game.sector.j]='?' game.alive = False drawmaps(1) setwnd(message_window) finish(FMATERIALIZE) return - game.quad[ix][iy]=game.ship - textcolor(GREEN); + game.quad[game.sector.i][game.sector.j]=game.ship + textcolor(GREEN) prout(_("succeeds.")) - textcolor(DEFAULT); + textcolor(DEFAULT) dock(False) skip(1) prout(_("Lt. Uhura- \"Captain, we made it!\"")) @@ -4322,15 +4387,15 @@ def survey(): continue if (game.state.planets[i].known != "unknown" \ and not game.state.planets[i].inhabited) \ - or idebug: + or game.idebug: iknow = True - if idebug and game.state.planets[i].known=="unknown": + if game.idebug and game.state.planets[i].known=="unknown": proutn("(Unknown) ") proutn(_("Quadrant %s") % game.state.planets[i].quadrant) proutn(_(" class ")) proutn(game.state.planets[i].pclass) proutn(" ") - if game.state.planets[i].crystals != present: + if game.state.planets[i].crystals != "present": proutn(_("no ")) prout(_("dilithium crystals present.")) if game.state.planets[i].known=="shuttle_down": @@ -4402,7 +4467,7 @@ def beam(): if not damaged(DSHUTTL) and (game.iplnet.known=="shuttle_down" or game.iscraft == "onship"): skip(1) proutn(_("Spock- \"May I suggest the shuttle craft, Sir?\" ")) - if ja() == True: + if ja(): shuttle() return if not game.inorbit: @@ -4420,7 +4485,7 @@ def beam(): prout(_("Spock- \"Captain, I fail to see the logic in")) prout(_(" exploring a planet with no dilithium crystals.")) proutn(_(" Are you sure this is wise?\" ")) - if ja() == False: + if not ja(): scanner.chew() return if not (game.options & OPTION_PLAIN): @@ -4436,14 +4501,14 @@ def beam(): if game.iplnet.known == "shuttle_down": prout(_(" Although the Galileo shuttle craft may still be on a surface.")) proutn(_(" Are you sure this is wise?\" ")) - if ja() == False: + if not ja(): 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: + if ja(): scanner.chew() return prout(_("Your crew hides the Galileo to prevent capture by aliens.")) @@ -4526,7 +4591,7 @@ def usecrystals(): prout(_(" raw dilithium crystals into the ship's power")) prout(_(" system may risk a severe explosion.")) proutn(_(" Are you sure this is wise?\" ")) - if ja() == False: + if not ja(): scanner.chew() return skip(1) @@ -4595,7 +4660,7 @@ def shuttle(): int(100*game.optime/game.state.remtime)) prout(_("remaining time.")) proutn(_("Are you sure this is wise?\" ")) - if ja() == False: + if not ja(): game.optime = 0.0 return if game.landed: @@ -4604,7 +4669,7 @@ def shuttle(): # Galileo on ship! if not damaged(DTRANSP): proutn(_("Spock- \"Would you rather use the transporter?\" ")) - if ja() == True: + if ja(): beam() return proutn(_("Shuttle crew")) @@ -4673,7 +4738,7 @@ def deathray(): prout(_("Spock- \"Captain, the 'Experimental Death Ray'")) prout(_(" is highly unpredictible. Considering the alternatives,")) proutn(_(" are you sure this is wise?\" ")) - if ja() == False: + if not ja(): return prout(_("Spock- \"Acknowledged.\"")) skip(1) @@ -4737,7 +4802,6 @@ def deathray(): finish(FDRAY) return if r <= 0.75: - intj prouts(_("Sulu- \"Captain! It's --WHAT?!?!\"")) skip(2) proutn(_("Spock- \"I believe the word is")) @@ -4782,7 +4846,7 @@ def attackreport(curt): def report(): # report on general game status scanner.chew() - s1 = "" and game.thawed and _("thawed ") + s1 = (game.thawed and _("thawed ")) or "" s2 = {1:"short", 2:"medium", 4:"long"}[game.length] s3 = (None, _("novice"), _("fair"), _("good"), _("expert"), _("emeritus"))[game.skill] @@ -4865,7 +4929,7 @@ def lrscan(silent): if not silent: proutn(" ") for y in range(game.quadrant.j-1, game.quadrant.j+2): - if not coord(x, y).valid_quadrant(): + if not Coord(x, y).valid_quadrant(): if not silent: proutn(" -1") else: @@ -4954,7 +5018,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: @@ -5054,7 +5118,7 @@ def srscan(): def eta(): "Use computer to get estimated time of arrival for a warp jump." - w1 = coord(); w2 = coord() + w1 = Coord(); w2 = Coord() prompt = False if damaged(DCOMPTR): prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR.")) @@ -5196,7 +5260,6 @@ def freeze(boss): if key != "IHALPHA": huh() return - scanner.chew() if '.' not in scanner.token: scanner.token += ".trk" try: @@ -5206,10 +5269,12 @@ def freeze(boss): return cPickle.dump(game, fp) fp.close() + scanner.chew() def thaw(): - "Retrieve saved game." - game.passwd[0] = '\0' + "Retrieve saved game." + global game + game.passwd = None key = scanner.next() if key == "IHEOL": proutn(_("File name: ")) @@ -5217,7 +5282,6 @@ def thaw(): if key != "IHALPHA": huh() return True - scanner.chew() if '.' not in scanner.token: scanner.token += ".trk" try: @@ -5227,6 +5291,7 @@ def thaw(): return game = cPickle.load(fp) fp.close() + scanner.chew() return False # I used to find planets @@ -5302,7 +5367,7 @@ device = ( def setup(): "Prepare to play, set up cosmos." - w = coord() + w = Coord() # Decide how many of everything if choose(): return # frozen game @@ -5322,15 +5387,26 @@ def setup(): for i in range(NDEVICES): game.damage[i] = 0.0 # Set up assorted game parameters - game.battle = coord() + game.battle = Coord() game.state.date = game.indate = 100.0 * randreal(20, 51) game.nkinks = game.nhelp = game.casual = game.abandoned = 0 game.iscate = game.resting = game.imine = game.icrystl = game.icraft = False game.isatb = game.state.nplankl = 0 - game.state.starkl = game.state.basekl = 0 + game.state.starkl = game.state.basekl = game.state.nworldkl = 0 game.iscraft = "onship" game.landed = False game.alive = True + + # the galaxy + game.state.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant()) + # the starchart + game.state.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page()) + + game.state.planets = [] # Planet information + game.state.baseq = [] # Base quadrant coordinates + game.state.kcmdr = [] # Commander quadrant coordinates + game.statekscmdr = Coord() # Supercommander quadrant coordinates + # Starchart is functional but we've never seen it game.lastchart = FOREVER # Put stars in the galaxy @@ -5355,11 +5431,11 @@ def setup(): distq = (w - game.state.baseq[j]).distance() if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75): contflag = True - if idebug: + if game.idebug: prout("=== Abandoning base #%d at %s" % (i, w)) break elif distq < 6.0 * (BASEMAX+1-game.inbase): - if idebug: + if game.idebug: prout("=== Saving base #%d, close to #%d" % (i, j)) if not contflag: break @@ -5400,7 +5476,7 @@ def setup(): w = randplace(GALSIZE) if game.state.galaxy[w.i][w.j].planet == None: break - new = planet() + new = Planet() new.quadrant = w new.crystals = "absent" if (game.options & OPTION_WORLDS) and i < NINHAB: @@ -5488,6 +5564,8 @@ def setup(): if game.state.nscrem: prout(_(" YOU'LL NEED IT.")) waitfor() + clrscr() + setwnd(message_window) newqad() if len(game.enemies) - (thing == game.quadrant) - (game.tholian != None): game.shldup = True @@ -5500,8 +5578,9 @@ def choose(): game.tourn = game.length = 0 game.thawed = False game.skill = SKILL_NONE - if not scanner.inqueue: # Can start with command line options - proutn(_("Would you like a regular, tournament, or saved game? ")) + scanner.chew() +# if not scanner.inqueue: # Can start with command line options + proutn(_("Would you like a regular, tournament, or saved game? ")) scanner.next() if scanner.sees("tournament"): while scanner.next() == "IHEOL": @@ -5527,7 +5606,7 @@ 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": @@ -5577,7 +5656,7 @@ def choose(): game.options &=~ OPTION_COLOR setpassword() if game.passwd == "debug": - idebug = True + game.idebug = True prout("=== Debug mode enabled.") # Use parameters to generate initial values of things game.damfac = 0.5 * game.skill @@ -5621,7 +5700,11 @@ def newcnd(): def newkling(): "Drop new Klingon into current quadrant." - return enemy('K', loc=dropin(), power=randreal(300,450)+25.0*game.skill) + return Enemy('K', loc=dropin(), power=randreal(300,450)+25.0*game.skill) + +def sortenemies(): + "Sort enemies by distance so 'nearest' is meaningful." + game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist)) def newqad(): "Set up a new state of quadrant, for when we enter or re-enter it." @@ -5663,7 +5746,7 @@ def newqad(): game.iscate = (game.state.remkl > 1) # Put in Romulans if needed for i in range(q.romulans): - enemy('R', loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill) + Enemy('R', loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill) # If quadrant needs a starbase, put it in if q.starbase: game.base = dropin('B') @@ -5688,7 +5771,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(type='?', loc=dropin(), power=randreal(6000,6500.0)+250.0*game.skill) if not damaged(DSRSENS): skip(1) @@ -5699,13 +5782,13 @@ def newqad(): if (game.skill < SKILL_GOOD and withprob(0.02)) or \ (game.skill == SKILL_GOOD and withprob(0.05)) or \ (game.skill > SKILL_GOOD and withprob(0.08)): - w = coord() + w = Coord() while True: w.i = withprob(0.5) * (QUADSIZE-1) 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(type='T', loc=w, power=randrange(100, 500) + 25.0*game.skill) # Reserve unoccupied corners if game.quad[0][0]=='.': @@ -5716,7 +5799,7 @@ def newqad(): game.quad[QUADSIZE-1][0] = 'X' if game.quad[QUADSIZE-1][QUADSIZE-1]=='.': game.quad[QUADSIZE-1][QUADSIZE-1] = 'X' - game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist)) + sortenemies() # And finally the stars for i in range(q.stars): dropin('*') @@ -5747,59 +5830,61 @@ def setpassword(): break else: game.passwd = "" - for i in range(3): - game.passwd += chr(ord('a')+randrange(26)) + game.passwd += chr(ord('a')+randrange(26)) + game.passwd += chr(ord('a')+randrange(26)) + game.passwd += chr(ord('a')+randrange(26)) # Code from sst.c begins here -commands = { - "SRSCAN": OPTION_TTY, - "STATUS": OPTION_TTY, - "REQUEST": OPTION_TTY, - "LRSCAN": OPTION_TTY, - "PHASERS": 0, - "TORPEDO": 0, - "PHOTONS": 0, - "MOVE": 0, - "SHIELDS": 0, - "DOCK": 0, - "DAMAGES": 0, - "CHART": 0, - "IMPULSE": 0, - "REST": 0, - "WARP": 0, - "SCORE": 0, - "SENSORS": OPTION_PLANETS, - "ORBIT": OPTION_PLANETS, - "TRANSPORT": OPTION_PLANETS, - "MINE": OPTION_PLANETS, - "CRYSTALS": OPTION_PLANETS, - "SHUTTLE": OPTION_PLANETS, - "PLANETS": OPTION_PLANETS, - "REPORT": 0, - "COMPUTER": 0, - "COMMANDS": 0, - "EMEXIT": 0, - "PROBE": OPTION_PROBE, - "SAVE": 0, - "FREEZE": 0, # Synonym for SAVE - "ABANDON": 0, - "DESTRUCT": 0, - "DEATHRAY": 0, - "DEBUG": 0, - "MAYDAY": 0, - "SOS": 0, # Synonym for MAYDAY - "CALL": 0, # Synonym for MAYDAY - "QUIT": 0, - "HELP": 0, -} +commands = [ + ("SRSCAN", OPTION_TTY), + ("STATUS", OPTION_TTY), + ("REQUEST", OPTION_TTY), + ("LRSCAN", OPTION_TTY), + ("PHASERS", 0), + ("TORPEDO", 0), + ("PHOTONS", 0), + ("MOVE", 0), + ("SHIELDS", 0), + ("DOCK", 0), + ("DAMAGES", 0), + ("CHART", 0), + ("IMPULSE", 0), + ("REST", 0), + ("WARP", 0), + ("SCORE", 0), + ("SENSORS", OPTION_PLANETS), + ("ORBIT", OPTION_PLANETS), + ("TRANSPORT", OPTION_PLANETS), + ("MINE", OPTION_PLANETS), + ("CRYSTALS", OPTION_PLANETS), + ("SHUTTLE", OPTION_PLANETS), + ("PLANETS", OPTION_PLANETS), + ("REPORT", 0), + ("COMPUTER", 0), + ("COMMANDS", 0), + ("EMEXIT", 0), + ("PROBE", OPTION_PROBE), + ("SAVE", 0), + ("FREEZE", 0), # Synonym for SAVE + ("ABANDON", 0), + ("DESTRUCT", 0), + ("DEATHRAY", 0), + ("DEBUG", 0), + ("MAYDAY", 0), + ("SOS", 0), # Synonym for MAYDAY + ("CALL", 0), # Synonym for MAYDAY + ("QUIT", 0), + ("HELP", 0), + ("", 0), +] def listCommands(): "Generate a list of legal commands." prout(_("LEGAL COMMANDS ARE:")) emitted = 0 - for key in commands: - if not commands[key] or (commands[key] & game.options): + for (key, opt) in commands: + if not opt or (opt & game.options): proutn("%-12s " % key) emitted += 1 if emitted % 5 == 4: @@ -5817,7 +5902,8 @@ def helpme(): setwnd(message_window) if key == "IHEOL": return - if scanner.token.upper() in commands or scanner.token == "ABBREV": + cmds = map(lambda x: x[0], commands) + if scanner.token.upper() in cmds or scanner.token.upper() == "ABBREV": break skip(1) listCommands() @@ -5861,8 +5947,6 @@ def helpme(): def makemoves(): "Command-interpretation loop." - clrscr() - setwnd(message_window) while True: # command loop drawmaps(1) while True: # get a command @@ -5882,16 +5966,19 @@ def makemoves(): clrscr() setwnd(message_window) clrscr() - 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 prefix '%s': %s" % (scanner.token, " ".join(candidates))) - else: + abandon_passed = False + for (cmd, opt) in commands: + # commands after ABANDON cannot be abbreviated + if cmd == "ABANDON": + abandon_passed = True + if cmd == scanner.token.upper() or (not abandon_passed \ + and cmd.startswith(scanner.token.upper())): + break + if cmd == "": listCommands() continue + else: + break if cmd == "SRSCAN": # srscan srscan() elif cmd == "STATUS": # status @@ -5909,7 +5996,7 @@ def makemoves(): if game.ididit: hitme = True elif cmd == "MOVE": # move under warp - warp(course=None, involuntary=False) + warp(wcourse=None, involuntary=False) elif cmd == "SHIELDS": # shields doshield(shraise=False) if game.ididit: @@ -5964,7 +6051,7 @@ def makemoves(): elif cmd == "EMEXIT": # Emergency exit clrscr() # Hide screen freeze(True) # forced save - raise SysExit,1 # And quick exit + raise SystemExit,1 # And quick exit elif cmd == "PROBE": probe() # Launch probe if game.ididit: @@ -6013,7 +6100,7 @@ def makemoves(): break if game.alldone: break - if idebug: + if game.idebug: prout("=== Ending") def cramen(type): @@ -6059,7 +6146,7 @@ def expran(avrage): def randplace(size): "Choose a random location." - w = coord() + w = Coord() w.i = randrange(size) w.j = randrange(size) return w @@ -6120,7 +6207,7 @@ class sstscanner: # Round token value to nearest integer return int(round(scanner.real)) def getcoord(self): - s = coord() + s = Coord() scanner.next() if scanner.type != "IHREAL": huh() @@ -6132,7 +6219,7 @@ class sstscanner: return None s.j = scanner.int()-1 return s - def __repr__(str): + def __repr__(self): return "" % (scanner.token, scanner.type, scanner.inqueue) def ja(): @@ -6156,26 +6243,26 @@ def huh(): def debugme(): "Access to the internals for debugging." proutn("Reset levels? ") - if ja() == True: + if ja(): if game.energy < game.inenrg: game.energy = game.inenrg game.shield = game.inshld game.torps = game.intorps game.lsupres = game.inlsr proutn("Reset damage? ") - if ja() == True: + if ja(): for i in range(NDEVICES): if game.damage[i] > 0.0: game.damage[i] = 0.0 proutn("Toggle debug flag? ") - if ja() == True: - idebug = not idebug - if idebug: + if ja(): + game.idebug = not game.idebug + if game.idebug: prout("Debug output ON") else: prout("Debug output OFF") proutn("Cause selective damage? ") - if ja() == True: + if ja(): for i in range(NDEVICES): proutn("Kill %s?" % device[i]) scanner.chew() @@ -6183,9 +6270,9 @@ def debugme(): if key == "IHALPHA" and scanner.sees("y"): game.damage[i] = 10.0 proutn("Examine/change events? ") - if ja() == True: - ev = event() - w = coord() + if ja(): + ev = Event() + w = Coord() legends = { FSNOVA: "Supernova ", FTBEAM: "T Beam ", @@ -6236,26 +6323,25 @@ def debugme(): ev.quadrant = w scanner.chew() proutn("Induce supernova here? ") - if ja() == True: + if ja(): game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova = True atover(True) if __name__ == '__main__': import getopt, socket try: - global line, thing, game, idebug + global line, thing, game game = None - thing = coord() - thing.angry = False - game = gamestate() - idebug = 0 + thing = Thingy() + game = Gamestate() game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY) if os.getenv("TERM"): game.options |= OPTION_CURSES else: game.options |= OPTION_TTY seed = int(time.time()) - (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:tx") + (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:txV") + replay = False for (switch, val) in options: if switch == '-r': try: @@ -6265,11 +6351,12 @@ if __name__ == '__main__': 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) @@ -6281,7 +6368,10 @@ if __name__ == '__main__': game.options |= OPTION_TTY game.options &=~ OPTION_CURSES elif switch == '-x': - idebug = True + game.idebug = True + elif switch == '-V': + print "SST2K", version + raise SystemExit, 0 else: sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n") raise SystemExit, 1 @@ -6315,12 +6405,14 @@ if __name__ == '__main__': game.alldone = False else: makemoves() + if replay: + break skip(1) stars() skip(1) if game.tourn and game.alldone: proutn(_("Do you want your score recorded?")) - if ja() == True: + if ja(): scanner.chew() scanner.push("\n") freeze(False) @@ -6337,3 +6429,5 @@ if __name__ == '__main__': if logfp: logfp.close() print "" + +# End.