X-Git-Url: https://jxself.org/git/?p=super-star-trek.git;a=blobdiff_plain;f=sst.py;h=691eff84dbb4e2f179528a3ecbce5becc9cc9795;hp=957ddfbd14e36d745ef5c8138133f51cc4144576;hb=2a1e7baaa229ba188baa2cf8b35cc6ec1485f35b;hpb=b8ffe91a83c83c29cc1a574e3fc2d857d582df33 diff --git a/sst.py b/sst.py index 957ddfb..691eff8 100755 --- a/sst.py +++ b/sst.py @@ -13,7 +13,7 @@ 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.0" +version="2.1" docpath = (".", "../doc", "/usr/share/doc/sst") @@ -56,9 +56,9 @@ class TrekError(Exception): pass class JumpOut(Exception): - pass + pass -class coord: +class Coord: def __init__(self, x=None, y=None): self.i = x self.j = y @@ -75,28 +75,28 @@ 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: @@ -112,7 +112,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 @@ -122,10 +122,10 @@ class coord: return "%s - %s" % (self.i+1, self.j+1) __repr__ = __str__ -class planet: +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" @@ -133,7 +133,7 @@ class planet: def __str__(self): return self.name -class quadrant: +class Quadrant: def __init__(self): self.stars = 0 self.planet = None @@ -144,7 +144,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 @@ -159,7 +159,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 @@ -176,13 +176,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_unused, j_unused: quadrant()) + self.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant()) # the starchart - self.chart = fill2d(GALSIZE, lambda i_unused, j_unused: 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 @@ -256,10 +256,10 @@ NEVENTS = 12 # when we implement stateful events def findevent(evtype): return game.future[evtype] -class enemy: +class Enemy: def __init__(self, type=None, loc=None, power=None): self.type = type - self.location = coord() + self.location = Coord() if loc: self.move(loc) self.power = power # enemy energy level @@ -277,25 +277,25 @@ 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 i = NEVENTS while i > 0: i -= 1 - self.future.append(event()) + self.future.append(Event()) self.passwd = None; # Self Destruct password self.enemies = [] self.quadrant = None # where we are in the large @@ -363,6 +363,8 @@ class gamestate: self.cryprob = 0.0 # probability that crystal will work self.probe = None # object holding probe course info self.height = 0.0 # height of orbit around planet + self.score = 0.0 # overall score + self.perdate = 0.0 # rate of kills self.idebug = False # Debugging instrumentation enabled? def recompute(self): # Stas thinks this should be (C expression): @@ -420,7 +422,7 @@ 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): @@ -506,7 +508,7 @@ 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: @@ -661,7 +663,7 @@ def moveklings(): for enemy in game.enemies: if enemy.type in ('K', 'R'): movebaddy(enemy) - game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist)) + sortenemies() def movescom(iq, avoid): "Commander movement helper." @@ -687,7 +689,7 @@ def movescom(iq, avoid): game.klhere -= 1 if game.condition != "docked": newcnd() - game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist)) + sortenemies() # check for a helpful planet for i in range(game.inplan): if game.state.planets[i].quadrant == game.state.kscmdr and \ @@ -705,7 +707,7 @@ def movescom(iq, avoid): 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") @@ -726,7 +728,7 @@ def supercommander(): unschedule(FSCMOVE) return sc = game.state.kscmdr - for base in game.state.baseq: + for (i, base) in enumerate(game.state.baseq): basetbl.append((i, (base - sc).distance())) if game.state.baseq > 1: basetbl.sort(lambda x, y: cmp(x[1], y[1])) @@ -826,7 +828,7 @@ def movetholian(): "Move the Tholian." if not game.tholian or game.justin: return - tid = coord() + tid = Coord() if game.tholian.location.i == 0 and game.tholian.location.j == 0: tid.i = 0; tid.j = QUADSIZE-1 elif game.tholian.location.i == 0 and game.tholian.location.j == QUADSIZE-1: @@ -913,7 +915,7 @@ def doshield(shraise): action = "SHUP" else: scanner.chew() - return + return if action == "SHUP": # raise shields if game.shldup: prout(_("Shields already up.")) @@ -1062,7 +1064,7 @@ def torpedo(origin, bearing, dispersion, number, nburst): 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): @@ -1071,7 +1073,7 @@ def torpedo(origin, bearing, dispersion, number, nburst): if not w.valid_sector(): break iquad=game.quad[w.i][w.j] - tracktorpedo(origin, w, step, number, nburst, iquad) + tracktorpedo(w, step, number, nburst, iquad) if iquad=='.': continue # hit something @@ -1105,7 +1107,7 @@ def torpedo(origin, bearing, dispersion, number, nburst): prout(_(" displaced by blast to Sector %s ") % bumpto) for enemy in game.enemies: enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance() - game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist)) + sortenemies() return None elif iquad in ('C', 'S', 'R', 'K'): # Hit a regular enemy # find the enemy @@ -1148,7 +1150,7 @@ def torpedo(origin, bearing, dispersion, number, nburst): game.quad[bumpto.i][bumpto.j]=iquad for enemy in game.enemies: enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance() - game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist)) + sortenemies() return None elif iquad == 'B': # Hit a base skip(1) @@ -1219,7 +1221,7 @@ def torpedo(origin, bearing, dispersion, number, nburst): return None elif iquad == 'T': # Hit a Tholian h1 = 700.0 + randrange(100) - \ - 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-angle)) + 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle)) h1 = math.fabs(h1) if h1 >= 600: game.quad[w.i][w.j] = '.' @@ -1421,7 +1423,7 @@ def attack(torps_ok): # After attack, reset average distance to enemies for enemy in game.enemies: enemy.kavgd = enemy.kdist - game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist)) + sortenemies() return def deadkl(w, type, mv): @@ -1478,11 +1480,11 @@ def targetcheck(w): if not w.valid_sector(): huh() return None - delta = coord() + 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): + if delta == Coord(0, 0): skip(1) prout(_("Spock- \"Bridge to sickbay. Dr. McCoy,")) prout(_(" I recommend an immediate review of")) @@ -1634,7 +1636,7 @@ def checkshctrl(rpow): def hittem(hits): "Register a phaser hit on Klingons and Romulans." kk = 0 - w = coord() + w = Coord() skip(1) for (k, wham) in enumerate(hits): if wham==0: @@ -1968,8 +1970,8 @@ def events(): i=0 fintim = game.state.date + game.optime; yank=0 ictbeam = False; istract = False - w = coord(); hold = coord() - ev = event(); ev2 = event() + w = Coord(); hold = Coord() + ev = Event(); ev2 = Event() def tractorbeam(yank): "Tractor-beaming cases merge here." @@ -2175,13 +2177,13 @@ def events(): for ibq in game.state.baseq: for cmdr in game.state.kcmdr: if ibq == cmdr and ibq != game.quadrant and ibq != game.state.kscmdr: - raise ibq + raise JumpOut else: # no match found -- try later schedule(FBATTAK, expran(0.3*game.intime)) unschedule(FCDBAS) continue - except coord: + except JumpOut: pass # commander + starbase combination found -- launch attack game.battle = ibq @@ -2322,7 +2324,7 @@ def events(): 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 @@ -2411,7 +2413,7 @@ def wait(): def nova(nov): "Star goes nova." 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) + newc = Coord(); neighbor = Coord(); bump = Coord(0, 0) if withprob(0.05): # Wow! We've supernova'ed supernova(game.quadrant) @@ -2425,7 +2427,7 @@ 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): @@ -2491,7 +2493,7 @@ def nova(nov): finish(FNOVA) return # add in course nova contributes to kicking starship - bump += (game.sector-hits[mm]).sgn() + bump += (game.sector-hits[-1]).sgn() elif iquad == 'K': # kill klingon deadkl(neighbor, iquad, neighbor) elif iquad in ('C','S','R'): # Damage/destroy big enemies @@ -2502,7 +2504,7 @@ def nova(nov): if game.enemies[ll].power <= 0.0: deadkl(neighbor, iquad, neighbor) break - newc = neighbor + neighbor - hits[mm] + newc = neighbor + neighbor - hits[-1] proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged")) if not newc.valid_sector(): # can't leave quadrant @@ -2545,7 +2547,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 @@ -2570,7 +2572,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): @@ -2662,7 +2664,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) @@ -2690,11 +2691,9 @@ def kaboom(): skip(1) if len(game.enemies) != 0: whammo = 25.0 * game.energy - l=1 - while l <= len(game.enemies): + for l in range(len(game.enemies)): if game.enemies[l].power*game.enemies[l].kdist <= whammo: deadkl(game.enemies[l].location, game.quad[game.enemies[l].location.i][game.enemies[l].location.j], game.enemies[l].location) - l += 1 finish(FDILITHIUM) def killrate(): @@ -2918,11 +2917,10 @@ def finish(ifin): def score(): "Compute player's score." timused = game.state.date - game.indate - iskill = game.skill if (timused == 0 or (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0) and timused < 5.0: timused = 5.0 - perdate = killrate() - ithperd = 500*perdate + 0.5 + game.perdate = killrate() + ithperd = 500*game.perdate + 0.5 iwon = 0 if game.gamewon: iwon = 100*game.skill @@ -2932,7 +2930,7 @@ def score(): klship = 1 else: klship = 2 - iscore = 10*(game.inkling - game.state.remkl) \ + game.score = 10*(game.inkling - game.state.remkl) \ + 50*(game.incom - len(game.state.kcmdr)) \ + ithperd + iwon \ + 20*(game.inrom - game.state.nromrem) \ @@ -2940,7 +2938,7 @@ def score(): - game.state.nromrem \ - badpoints() if not game.alive: - iscore -= 200 + game.score -= 200 skip(2) prout(_("Your score --")) if game.inrom - game.state.nromrem: @@ -2960,7 +2958,7 @@ def score(): (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem))) if ithperd: prout(_("%6.2f Klingons per stardate %5d") % - (perdate, ithperd)) + (game.perdate, ithperd)) if game.state.starkl: prout(_("%6d stars destroyed by your action %5d") % (game.state.starkl, -5*game.state.starkl)) @@ -2996,7 +2994,7 @@ def score(): elif game.skill == SKILL_EMERITUS: proutn(_("Emeritus game")) prout(" %5d" % iwon) skip(1) - prout(_("TOTAL SCORE %5d") % iscore) + prout(_("TOTAL SCORE %5d") % game.score) def plaque(): "Emit winner's commemmorative plaque." @@ -3052,8 +3050,8 @@ def plaque(): timestring = time.ctime() fp.write(_(" This day of %.6s %.4s, %.8s\n\n") % (timestring+4, timestring+20, timestring+11)) - fp.write(_(" Your score: %d\n\n") % iscore) - fp.write(_(" Klingons per stardate: %.2f\n") % perdate) + fp.write(_(" Your score: %d\n\n") % game.score) + fp.write(_(" Klingons per stardate: %.2f\n") % game.perdate) fp.close() # Code from io.c begins here @@ -3160,16 +3158,11 @@ def skip(i): "Skip i lines. Pause game if this would cause a scrolling event." for dummy in range(i): if game.options & OPTION_CURSES: - (y, x) = curwnd.getyx() - (my, mx) = curwnd.getmaxyx() - if curwnd == message_window and y >= my - 2: - pause_game() - clrscr() - else: - try: - curwnd.move(y+1, 0) - except curses.error: - pass + (y, x) = curwnd.getyx() + try: + curwnd.move(y+1, 0) + except curses.error: + pass else: global linecount linecount += 1 @@ -3181,6 +3174,11 @@ def skip(i): def proutn(line): "Utter a line with no following line feed." if game.options & OPTION_CURSES: + (y, x) = curwnd.getyx() + (my, mx) = curwnd.getmaxyx() + if curwnd == message_window and y >= my - 2: + pause_game() + clrscr() curwnd.addstr(line) curwnd.refresh() else: @@ -3347,7 +3345,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: @@ -3409,7 +3407,7 @@ def prstat(txt, data): 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 @@ -3532,7 +3530,7 @@ def imove(icourse=None, noattack=False): if icourse.origin.quadrant() != icourse.location.quadrant(): newquadrant(noattack) break - elif check_collision(icourse, w): + elif check_collision(w): print "Collision detected" break else: @@ -3544,7 +3542,7 @@ def imove(icourse=None, noattack=False): finald = (w-enemy.location).distance() enemy.kavgd = 0.5 * (finald + enemy.kdist) enemy.kdist = finald - game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist)) + sortenemies() if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova: attack(torps_ok=False) for enemy in game.enemies: @@ -3597,7 +3595,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")) @@ -3639,7 +3637,7 @@ def getcourse(isprobe): prout(_("(Manual movement assumed.)")) navmode = "manual" break - delta = coord() + delta = Coord() if navmode == "automatic": while key == "IHEOL": if isprobe: @@ -3739,7 +3737,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)) @@ -3890,8 +3888,10 @@ def warp(wcourse, involuntary): twarp = True if blooey or twarp: # If time warp or engine damage, check path - # If it is obstructed, don't do warp or damage - for m_unused in range(wcourse.moves): + # If it is obstructed, don't do warp or damage + look = wcourse.moves + while look > 0: + look -= 1 wcourse.next() w = wcourse.sector() if not w.valid_sector(): @@ -3901,7 +3901,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) @@ -4189,7 +4189,7 @@ def mayday(): elif m == 2: proutn(_("2nd")) elif m == 3: proutn(_("3rd")) proutn(_(" attempt to re-materialize ") + crmshp()) - game.quad[ix][iy]=('-','o','O')[m-1] + game.quad[game.sector.i][game.sector.j]=('-','o','O')[m-1] textcolor(RED) warble() if randreal() > probf: @@ -4198,13 +4198,13 @@ def mayday(): textcolor(DEFAULT) curses.delay_output(500) if m > 3: - game.quad[ix][iy]='?' + game.quad[game.sector.i][game.sector.j]='?' game.alive = False drawmaps(1) setwnd(message_window) finish(FMATERIALIZE) return - game.quad[ix][iy]=game.ship + game.quad[game.sector.i][game.sector.j]=game.ship textcolor(GREEN); prout(_("succeeds.")) textcolor(DEFAULT); @@ -4789,7 +4789,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] @@ -4872,7 +4872,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: @@ -5061,7 +5061,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.")) @@ -5203,7 +5203,6 @@ def freeze(boss): if key != "IHALPHA": huh() return - scanner.chew() if '.' not in scanner.token: scanner.token += ".trk" try: @@ -5213,10 +5212,12 @@ def freeze(boss): return cPickle.dump(game, fp) fp.close() + scanner.chew() def thaw(): "Retrieve saved game." - game.passwd[0] = '\0' + global game + game.passwd = None key = scanner.next() if key == "IHEOL": proutn(_("File name: ")) @@ -5224,7 +5225,6 @@ def thaw(): if key != "IHALPHA": huh() return True - scanner.chew() if '.' not in scanner.token: scanner.token += ".trk" try: @@ -5234,6 +5234,7 @@ def thaw(): return game = cPickle.load(fp) fp.close() + scanner.chew() return False # I used to find planets @@ -5309,7 +5310,7 @@ device = ( def setup(): "Prepare to play, set up cosmos." - w = coord() + w = Coord() # Decide how many of everything if choose(): return # frozen game @@ -5329,15 +5330,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 @@ -5407,7 +5419,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: @@ -5495,6 +5507,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 @@ -5507,8 +5521,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": @@ -5534,7 +5549,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": @@ -5628,7 +5643,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." @@ -5670,7 +5689,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') @@ -5695,7 +5714,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) @@ -5706,13 +5725,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]=='.': @@ -5723,7 +5742,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('*') @@ -5760,54 +5779,55 @@ def setpassword(): # 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: @@ -5825,7 +5845,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() @@ -5869,8 +5890,6 @@ def helpme(): def makemoves(): "Command-interpretation loop." - clrscr() - setwnd(message_window) while True: # command loop drawmaps(1) while True: # get a command @@ -5890,16 +5909,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 @@ -6067,7 +6089,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 @@ -6128,7 +6150,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() @@ -6192,8 +6214,8 @@ def debugme(): game.damage[i] = 10.0 proutn("Examine/change events? ") if ja(): - ev = event() - w = coord() + ev = Event() + w = Coord() legends = { FSNOVA: "Supernova ", FTBEAM: "T Beam ", @@ -6253,9 +6275,9 @@ if __name__ == '__main__': try: global line, thing, game game = None - thing = coord() + thing = Coord() thing.angry = False - game = gamestate() + game = Gamestate() game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY) if os.getenv("TERM"): game.options |= OPTION_CURSES @@ -6347,3 +6369,5 @@ if __name__ == '__main__': if logfp: logfp.close() print "" + +# End.