X-Git-Url: https://jxself.org/git/?p=super-star-trek.git;a=blobdiff_plain;f=sst.py;h=22a02919b78fe66be09d52e508f2cc9e0c1ead37;hp=ca6206db557b57a7b16f73e7850fa2a0519fcbda;hb=6e6032d311be62b5afa823aebf8c035c50dedbae;hpb=a949773474265e7f431068ecf85054dcf6a8eb5a diff --git a/sst.py b/sst.py index ca6206d..22a0291 100755 --- a/sst.py +++ b/sst.py @@ -124,6 +124,14 @@ class Coord: return "%s - %s" % (self.i+1, self.j+1) __repr__ = __str__ +class Thingy(Coord): + "Do not anger the Space Thingy!" + def __init__(self): + Coord.__init__(self) + self.angered = False + def angry(self): + self.angered = True + class Planet: def __init__(self): self.name = None # string-valued if inhabited @@ -265,6 +273,8 @@ class Enemy: def __init__(self, etype=None, loc=None, power=None): self.type = etype self.location = Coord() + self.kdist = None + self.kavgd = None if loc: self.move(loc) self.power = power # enemy energy level @@ -371,6 +381,7 @@ class Gamestate: self.score = 0.0 # overall score self.perdate = 0.0 # rate of kills self.idebug = False # Debugging instrumentation enabled? + self.statekscmdr = None # No SuperCommander coordinates yet. def recompute(self): # Stas thinks this should be (C expression): # game.state.remkl + len(game.state.kcmdr) > 0 ? @@ -378,7 +389,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 @@ -513,7 +524,8 @@ 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: @@ -523,7 +535,7 @@ def movebaddy(enemy): dist1 = enemy.kdist 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 @@ -632,7 +644,7 @@ def movebaddy(enemy): if success: goto = look if game.idebug: - proutn(`goto`) + proutn(repr(goto)) else: break # done early if game.idebug: @@ -656,7 +668,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) @@ -681,7 +693,7 @@ 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 @@ -689,8 +701,7 @@ def movescom(iq, avoid): unschedule(FSCDBAS) for enemy in game.enemies: if enemy.type == 'S': - break - enemy.move(None) + enemy.move(None) game.klhere -= 1 if game.condition != "docked": newcnd() @@ -712,7 +723,10 @@ 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") @@ -868,16 +882,16 @@ def movetholian(): 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) @@ -939,14 +953,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 @@ -1077,16 +1091,18 @@ def torpedo(origin, bearing, dispersion, number, nburst): # Loop to move a single torpedo setwnd(message_window) for step in range(1, QUADSIZE*2): - if not track.next(): break + if not track.next(): + break w = track.sector() if not w.valid_sector(): break - iquad=game.quad[w.i][w.j] + iquad = game.quad[w.i][w.j] tracktorpedo(w, step, number, nburst, iquad) if iquad == '.': continue # hit something - if not damaged(DSRSENS) or game.condition == "docked": + 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) @@ -1098,7 +1114,7 @@ def torpedo(origin, bearing, dispersion, number, nburst): 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(): @@ -1106,7 +1122,7 @@ def torpedo(origin, bearing, dispersion, number, nburst): 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 @@ -1126,40 +1142,43 @@ def torpedo(origin, bearing, dispersion, number, nburst): return None for enemy in game.enemies: if w == enemy.location: - break - kp = math.fabs(enemy.power) - h1 = 700.0 + randrange(100) - \ - 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle)) - h1 = math.fabs(h1) - if kp < h1: - h1 = kp - if enemy.power < 0: - enemy.power -= -h1 - else: - enemy.power -= h1 - if enemy.power == 0: - deadkl(w, iquad, w) - return None - proutn(crmena(True, iquad, "sector", w)) - displacement = course(track.bearing+randreal(-2.4,2.4), distance=2**0.5) - displacement.next() - bumpto = displacement.sector() - if not bumpto.valid_sector(): - prout(_(" damaged but not destroyed.")) - return - if game.quad[bumpto.i][bumpto.j] == ' ': - prout(_(" buffeted into black hole.")) - deadkl(w, iquad, bumpto) - if game.quad[bumpto.i][bumpto.j] != '.': - prout(_(" damaged but not destroyed.")) + kp = math.fabs(enemy.power) + h1 = 700.0 + randrange(100) - \ + 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle)) + h1 = math.fabs(h1) + if kp < h1: + h1 = kp + if enemy.power < 0: + enemy.power -= -h1 + else: + enemy.power -= h1 + if enemy.power == 0: + deadkl(w, iquad, w) + return None + proutn(crmena(True, iquad, "sector", w)) + displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5) + displacement.next() + bumpto = displacement.sector() + if not bumpto.valid_sector(): + prout(_(" damaged but not destroyed.")) + return + if game.quad[bumpto.i][bumpto.j] == ' ': + prout(_(" buffeted into black hole.")) + deadkl(w, iquad, bumpto) + if game.quad[bumpto.i][bumpto.j] != '.': + prout(_(" damaged but not destroyed.")) + else: + prout(_(" damaged-- displaced by blast to Sector %s ")%bumpto) + enemy.location = bumpto + game.quad[w.i][w.j] = '.' + game.quad[bumpto.i][bumpto.j] = iquad + for enemy in game.enemies: + enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance() + sortenemies() + break else: - prout(_(" damaged-- displaced by blast to Sector %s ")%bumpto) - enemy.location = bumpto - game.quad[w.i][w.j]='.' - game.quad[bumpto.i][bumpto.j]=iquad - for enemy in game.enemies: - enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance() - sortenemies() + prout("Internal error, no enemy where expected!") + raise SystemExit, 1 return None elif iquad == 'B': # Hit a base skip(1) @@ -1218,7 +1237,7 @@ def torpedo(origin, bearing, dispersion, number, nburst): # Stas Sergeev added the possibility that # you can shove the Thingy and piss it off. # It then becomes an enemy and may fire at you. - thing.angry = True + thing.angry() return None elif iquad == ' ': # Black hole skip(1) @@ -1255,6 +1274,7 @@ def torpedo(origin, bearing, dispersion, number, nburst): return None break skip(1) + setwnd(message_window) prout(_("Torpedo missed.")) return None @@ -1287,7 +1307,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 @@ -1297,7 +1317,9 @@ def attack(torps_ok): return attempt = False ihurt = False - hitmax=0.0; hittot=0.0; chgfac=1.0 + hitmax = 0.0 + hittot = 0.0 + chgfac = 1.0 where = "neither" if game.idebug: prout("=== ATTACK!") @@ -1312,7 +1334,7 @@ def attack(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 @@ -1332,7 +1354,7 @@ def attack(torps_ok): r *= 0.25 if enemy.power < 500: r *= 0.25 - if enemy.type == 'T' or (enemy.type == '?' and not thing.angry): + 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 \ @@ -1346,7 +1368,7 @@ def attack(torps_ok): 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 @@ -1491,7 +1513,7 @@ def targetcheck(w): huh() return None delta = Coord() - # FIXME: C code this was translated from is wacky -- why the sign reversal? + # 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): @@ -1645,14 +1667,14 @@ def checkshctrl(rpow): def hittem(hits): "Register a phaser hit on Klingons and Romulans." - kk = 0 w = Coord() skip(1) - for (k, wham) in enumerate(hits): - if wham==0: + kk = 0 + for wham in hits: + if wham == 0: continue dustfac = randreal(0.9, 1.0) - hit = wham*math.pow(dustfac,game.enemies[kk].kdist) + hit = wham*math.pow(dustfac, game.enemies[kk].kdist) kpini = game.enemies[kk].power kp = math.fabs(kpini) if PHASEFAC*hit < kp: @@ -1670,8 +1692,8 @@ 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: @@ -1683,7 +1705,7 @@ def hittem(hits): 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 @@ -1693,10 +1715,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): @@ -1722,15 +1750,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() @@ -1774,18 +1802,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: @@ -1794,11 +1822,11 @@ 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: @@ -1815,7 +1843,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 @@ -1870,7 +1898,7 @@ def phasers(): 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): @@ -1979,11 +2007,13 @@ def events(): "Run through the event queue looking for things to do." i = 0 fintim = game.state.date + game.optime - yank=0 + 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." @@ -2025,8 +2055,8 @@ def events(): else: prout(_("(Shields not currently useable.)")) newqad() - # Adjust finish time to time of tractor beaming - fintim = game.state.date+game.optime + # Adjust finish time to time of tractor beaming? + # fintim = game.state.date+game.optime attack(torps_ok=False) if not game.state.kcmdr: unschedule(FTBEAM) @@ -2105,7 +2135,7 @@ def events(): finish(FDEPLETE) return # Any crew left alive? - if game.state.crew <=0: + if game.state.crew <= 0: finish(FCREW) return # Is life support adequate? @@ -2149,7 +2179,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 \ @@ -2301,7 +2331,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 @@ -2332,7 +2362,7 @@ def events(): if q.klingons <= 0: q.status = "secure" continue - if game.state.remkl >=MAXKLGAME: + if game.state.remkl >= MAXKLGAME: continue # full right now # reproduce one Klingon w = ev.quadrant @@ -2443,7 +2473,7 @@ def nova(nov): start = hits.pop() for offset.i in range(-1, 1+1): for offset.j in range(-1, 1+1): - if offset.j==0 and offset.i==0: + if offset.j == 0 and offset.i == 0: continue neighbor = start + offset if not neighbor.valid_sector(): @@ -2470,7 +2500,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 @@ -3162,7 +3192,8 @@ def pause_game(): global linecount sys.stdout.write('\n') proutn(prompt) - raw_input() + if not replayfp: + raw_input() sys.stdout.write('\n' * rows) linecount = 0 @@ -3191,6 +3222,9 @@ def proutn(line): if curwnd == message_window and y >= my - 2: pause_game() clrscr() + # Uncomment this to debug curses problems + if logfp: + logfp.write("#curses: at %s proutn(%s)\n" % ((y, x), repr(line))) curwnd.addstr(line) curwnd.refresh() else: @@ -3240,8 +3274,31 @@ def setwnd(wnd): "Change windows -- OK for this to be a no-op in tty mode." global curwnd if game.options & OPTION_CURSES: + # Uncomment this to debug curses problems + if logfp: + if wnd == fullscreen_window: + legend = "fullscreen" + elif wnd == srscan_window: + legend = "srscan" + elif wnd == report_window: + legend = "report" + elif wnd == status_window: + legend = "status" + elif wnd == lrscan_window: + legend = "lrscan" + elif wnd == message_window: + legend = "message" + elif wnd == prompt_window: + legend = "prompt" + else: + legend = "unknown" + logfp.write("#curses: setwnd(%s)\n" % legend) curwnd = wnd - curses.curs_set(wnd == fullscreen_window or wnd == message_window or wnd == prompt_window) + # Some curses implementations get confused when you try this. + try: + curses.curs_set(wnd in (fullscreen_window, message_window, prompt_window)) + except curses.error: + pass def clreol(): "Clear to end of line -- can be a no-op in tty mode" @@ -3806,7 +3863,7 @@ def impulse(): scanner.chew() return # Make sure enough time is left for the trip - game.optime = course.dist/0.095 + game.optime = course.distance/0.095 if game.optime >= game.state.remtime: prout(_("First Officer Spock- \"Captain, our speed under impulse")) prout(_("power is only 0.95 sectors per stardate. Are you sure")) @@ -3818,9 +3875,9 @@ def impulse(): game.ididit = True if game.alldone: return - power = 20.0 + 100.0*course.dist + power = 20.0 + 100.0*course.distance game.energy -= power - game.optime = course.dist/0.095 + game.optime = course.distance/0.095 if game.energy <= 0: finish(FNRG) return @@ -3856,7 +3913,7 @@ def warp(wcourse, involuntary): skip(1) prout(_("Engineering to bridge--")) if not game.shldup or 0.5*wcourse.power(game.warpfac) > game.energy: - iwarp = (game.energy/(wcourse.dist+0.05)) ** 0.333333333 + iwarp = (game.energy/(wcourse.distance+0.05)) ** 0.333333333 if iwarp <= 0: prout(_("We can't do it, Captain. We don't have enough energy.")) else: @@ -6287,8 +6344,7 @@ if __name__ == '__main__': try: global line, thing, game game = None - thing = Coord() - thing.angry = False + thing = Thingy() game = Gamestate() game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY) if os.getenv("TERM"): @@ -6297,6 +6353,7 @@ if __name__ == '__main__': game.options |= OPTION_TTY seed = int(time.time()) (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:txV") + replay = False for (switch, val) in options: if switch == '-r': try: @@ -6306,11 +6363,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) @@ -6342,6 +6400,7 @@ if __name__ == '__main__': if logfp: logfp.write("# seed %s\n" % seed) logfp.write("# options %s\n" % " ".join(arguments)) + logfp.write("# SST2K version %s\n" % version) logfp.write("# recorded by %s@%s on %s\n" % \ (getpass.getuser(),socket.gethostname(),time.ctime())) random.seed(seed) @@ -6359,6 +6418,8 @@ if __name__ == '__main__': game.alldone = False else: makemoves() + if replay: + break skip(1) stars() skip(1)