X-Git-Url: https://jxself.org/git/?p=super-star-trek.git;a=blobdiff_plain;f=src%2Fsst.py;h=fb665de93505b70bac785dd26773c0439b87477f;hp=d30cab27310b4eaf34a80e03da5617544232c3d5;hb=0116120e7c8552ac5869ce52facbdcc390575b4d;hpb=fe17a8a96e60187ab5cce6d2eac24e81d4d2406f diff --git a/src/sst.py b/src/sst.py index d30cab2..fb665de 100644 --- a/src/sst.py +++ b/src/sst.py @@ -172,6 +172,13 @@ your score. Docking at a starbase replenishes your crew. Also, the nav subsystem (enabling automatic course setting) can be damaged separately from the main computer (which handles weapons targeting, ETA calculation, and self-destruct). + +After these features were added, I translated this into Python and added +more: + +9. A long-range scan is done silently whenever you call CHART; thus +the LRSCAN command is no longer needed. (Controlled by OPTION_AUTOSCAN +and turned off if game type is "plain" or "almy".) """ import os,sys,math,curses,time,atexit,readline,cPickle,random,getopt,copy @@ -262,6 +269,8 @@ class coord: def __hash__(self): return hash((x, y)) def __str__(self): + if self.x == None or self.y == None: + return "Nowhere" return "%s - %s" % (self.x+1, self.y+1) __repr__ = __str__ @@ -342,15 +351,16 @@ OPTION_TTY = 0x00000001 # old interface OPTION_CURSES = 0x00000002 # new interface OPTION_IOMODES = 0x00000003 # cover both interfaces OPTION_PLANETS = 0x00000004 # planets and mining -OPTION_THOLIAN = 0x00000008 # Tholians and their webs -OPTION_THINGY = 0x00000010 # Space Thingy can shoot back -OPTION_PROBE = 0x00000020 # deep-space probes +OPTION_THOLIAN = 0x00000008 # Tholians and their webs (UT 1979 version) +OPTION_THINGY = 0x00000010 # Space Thingy can shoot back (Stas, 2005) +OPTION_PROBE = 0x00000020 # deep-space probes (DECUS version, 1980) OPTION_SHOWME = 0x00000040 # bracket Enterprise in chart -OPTION_RAMMING = 0x00000080 # enemies may ram Enterprise -OPTION_MVBADDY = 0x00000100 # more enemies can move -OPTION_BLKHOLE = 0x00000200 # black hole may timewarp you -OPTION_BASE = 0x00000400 # bases have good shields -OPTION_WORLDS = 0x00000800 # logic for inhabited worlds +OPTION_RAMMING = 0x00000080 # enemies may ram Enterprise (Almy) +OPTION_MVBADDY = 0x00000100 # more enemies can move (Almy) +OPTION_BLKHOLE = 0x00000200 # black hole may timewarp you (Stas, 2005) +OPTION_BASE = 0x00000400 # bases have good shields (Stas, 2005) +OPTION_WORLDS = 0x00000800 # logic for inhabited worlds (ESR, 2006) +OPTION_AUTOSCAN = 0x00001000 # automatic LRSCAN before CHART (ESR, 2006) OPTION_PLAIN = 0x01000000 # user chose plain game OPTION_ALMY = 0x02000000 # user chose Almy variant @@ -405,21 +415,29 @@ NEVENTS = 12 # def findevent(evtype): return game.future[evtype] +class enemy: + def __init__(self, loc=None, power=None): + if loc: + self.kloc = loc + else: + self.kloc = coord() # enemy sector location + self.kpower = power # enemy energy levels + self.kdist = self.kavgd = distance(game.sector, e.kloc) + def __repr__(self): + return "<%s=%f>" % (self.kloc, self.kpower) # For debugging + 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.quad = fill2d(QUADSIZE, lambda i, j: IHDOT) # contents of our quadrant - self.kpower = fill2d(QUADSIZE, lambda i, j: 0.0) # enemy energy levels - self.kdist = fill2d(QUADSIZE, lambda i, j: 0.0) # enemy distances - self.kavgd = fill2d(QUADSIZE, lambda i, j: 0.0) # average distances 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.ks = fill2d(QUADSIZE, lambda i, j: coord()) # enemy sector locations + self.enemies = [] self.quadrant = None # where we are in the large self.sector = None # where we are in the small self.tholian = None # coordinates of Tholian @@ -471,7 +489,7 @@ class gamestate: self.nenhere = 0 # number of enemies in quadrant self.irhere = 0 # Romulans in quadrant self.isatb = 0 # =1 if super commander is attacking base - self.tourn = 0 # tournament number + self.tourn = None # tournament number self.proben = 0 # number of moves for probe self.nprobes = 0 # number of probes available self.inresor = 0.0 # initial resources @@ -615,20 +633,20 @@ def tryexit(look, ienm, loccom, irun): if game.battle == game.quadrant: return False # don't leave if over 1000 units of energy - if game.kpower[loccom] > 1000.0: + if game.enemies[loccom].kpower > 1000.0: return False # print escape message and move out of quadrant. # we know this if either short or long range sensors are working if not damaged(DSRSENS) or not damaged(DLRSENS) or \ game.condition == docked: - crmena(True, ienm, "sector", game.ks[loccom]) + crmena(True, ienm, "sector", game.enemies[loccom].kloc) prout(_(" escapes to Quadrant %s (and regains strength).") % q) # handle local matters related to escape - game.quad[game.ks[loccom].x][game.ks[loccom].y] = IHDOT - game.ks[loccom] = game.ks[game.nenhere] - game.kavgd[loccom] = game.kavgd[game.nenhere] - game.kpower[loccom] = game.kpower[game.nenhere] - game.kdist[loccom] = game.kdist[game.nenhere] + game.quad[game.enemies[loccom].kloc.x][game.enemies[loccom].kloc.y] = IHDOT + game.enemies[loccom].kloc = game.enemies[game.nenhere].kloc + game.enemies[loccom].kavgd = game.enemies[game.nenhere].kavgd + game.enemies[loccom].kpower = game.enemies[game.nenhere].kpower + game.enemies[loccom].kdist = game.enemies[game.nenhere].kdist game.klhere -= 1 game.nenhere -= 1 if game.condition != docked: @@ -702,17 +720,17 @@ def movebaddy(com, loccom, ienm): else: nbaddys = game.comhere + game.ishere - dist1 = game.kdist[loccom] + dist1 = game.enemies[loccom].kdist mdist = int(dist1 + 0.5); # Nearest integer distance # If SC, check with spy to see if should hi-tail it if ienm==IHS and \ - (game.kpower[loccom] <= 500.0 or (game.condition=="docked" and not damaged(DPHOTON))): + (game.enemies[loccom].kpower <= 500.0 or (game.condition=="docked" and not damaged(DPHOTON))): irun = True motion = -QUADSIZE else: # decide whether to advance, retreat, or hold position - forces = game.kpower[loccom]+100.0*game.nenhere+400*(nbaddys-1) + forces = game.enemies[loccom].kpower+100.0*game.nenhere+400*(nbaddys-1) if not game.shldup: forces += 1000; # Good for enemy if shield is down! if not damaged(DPHASER) or not damaged(DPHOTON): @@ -748,9 +766,9 @@ def movebaddy(com, loccom, ienm): motion = game.skill # calculate preferred number of steps if motion < 0: - msteps = -motion + nsteps = -motion else: - msteps = motion + nsteps = motion if motion > 0 and nsteps > mdist: nsteps = mdist; # don't overshoot if nsteps > QUADSIZE: @@ -840,13 +858,13 @@ def movebaddy(com, loccom, ienm): game.quad[next.x][next.y] = ienm if next != com: # it moved - game.ks[loccom] = next - game.kdist[loccom] = game.kavgd[loccom] = distance(game.sector, next) + game.enemies[loccom].kloc = next + game.enemies[loccom].kdist = game.enemies[loccom].kavgd = distance(game.sector, next) if not damaged(DSRSENS) or game.condition == docked: proutn("***") cramen(ienm) proutn(_(" from Sector %s") % com) - if game.kdist[loccom] < dist1: + if game.enemies[loccom].kdist < dist1: proutn(_(" advances to ")) else: proutn(_(" retreats to ")) @@ -860,13 +878,13 @@ def moveklings(): # and do move if game.comhere: for i in range(game.nenhere): - w = game.ks[i] + w = game.enemies[i].kloc if game.quad[w.x][w.y] == IHC: movebaddy(w, i, IHC) break if game.ishere: for i in range(game.nenhere): - w = game.ks[i] + w = game.enemies[i].kloc if game.quad[w.x][w.y] == IHS: movebaddy(w, i, IHS) break @@ -875,7 +893,7 @@ def moveklings(): # commander(s) do. if game.skill >= SKILL_EXPERT and (game.options & OPTION_MVBADDY): for i in range(game.nenhere): - w = game.ks[i] + w = game.enemies[i].kloc if game.quad[w.x][w.y] == IHK or game.quad[w.x][w.y] == IHR: movebaddy(w, i, game.quad[w.x][w.y]) sortklings(); @@ -905,13 +923,13 @@ def movescom(iq, avoid): game.ientesc = False unschedule(FSCDBAS) for i in range(game.nenhere): - if game.quad[game.ks[i].x][game.ks[i].y] == IHS: + if game.quad[game.enemies[i].kloc.x][game.enemies[i].kloc.y] == IHS: break - game.quad[game.ks[i].x][game.ks[i].y] = IHDOT - game.ks[i] = game.ks[game.nenhere] - game.kdist[i] = game.kdist[game.nenhere] - game.kavgd[i] = game.kavgd[game.nenhere] - game.kpower[i] = game.kpower[game.nenhere] + game.quad[game.enemies[i].kloc.x][game.enemies[i].kloc.y] = IHDOT + game.enemies[i].kloc = game.enemies[game.nenhere].kloc + game.enemies[i].kdist = game.enemies[game.nenhere].kdist + game.enemies[i].kavgd = game.enemies[game.nenhere].kavgd + game.enemies[i].kpower = game.enemies[game.nenhere].kpower game.klhere -= 1 game.nenhere -= 1 if game.condition!=docked: @@ -1090,7 +1108,7 @@ def movetholian(): if game.quad[game.tholian.x][game.tholian.y]==IHDOT: game.quad[game.tholian.x][game.tholian.y] = IHWEB game.quad[game.tholian.x][game.tholian.y] = IHT - game.ks[game.nenhere] = game.tholian + game.enemies[game.nenhere].kloc = game.tholian # check to see if all holes plugged for i in range(QUADSIZE): @@ -1285,7 +1303,7 @@ def ram(ibumpd, ienm, w): proutn(_(" rammed by ")) else: proutn(_(" rams ")) - crmena(False, ienm, sector, w) + crmena(False, ienm, "sector", w) if ibumpd: proutn(_(" (original position)")) skip(1) @@ -1386,26 +1404,26 @@ def torpedo(course, r, incoming, i, n): shoved = True elif iquad in (IHC, IHS): # Hit a commander if withprob(0.05): - crmena(True, iquad, sector, w) + crmena(True, iquad, "sector", w) prout(_(" uses anti-photon device;")) prout(_(" torpedo neutralized.")) return None elif iquad in (IHR, IHK): # Hit a regular enemy # find the enemy for ll in range(game.nenhere): - if w == game.ks[ll]: + if w == game.enemies[ll].kloc: break - kp = math.fabs(game.kpower[ll]) + kp = math.fabs(game.enemies[ll].kpower) h1 = 700.0 + randrange(100) - \ 1000.0 * distance(w, incoming) * math.fabs(math.sin(bullseye-angle)) h1 = math.fabs(h1) if kp < h1: h1 = kp - if game.kpower[ll] < 0: - game.kpower[ll] -= -h1 + if game.enemies[ll].kpower < 0: + game.enemies[ll].kpower -= -h1 else: - game.kpower[ll] -= h1 - if game.kpower[ll] == 0: + game.enemies[ll].kpower -= h1 + if game.enemies[ll].kpower == 0: deadkl(w, iquad, w) return None crmena(True, iquad, "sector", w) @@ -1430,7 +1448,7 @@ def torpedo(course, r, incoming, i, n): prout(_(" damaged but not destroyed.")) return None proutn(_(" damaged--")) - game.ks[ll] = jw + game.enemies[ll].kloc = jw shoved = True break elif iquad == IHB: # Hit a base @@ -1449,7 +1467,7 @@ def torpedo(course, r, incoming, i, n): newcnd() return None elif iquad == IHP: # Hit a planet - crmena(True, iquad, sector, w) + crmena(True, iquad, "sector", w) prout(_(" destroyed.")) game.state.nplankl += 1 game.state.galaxy[game.quadrant.x][game.quadrant.y].planet = None @@ -1462,7 +1480,7 @@ def torpedo(course, r, incoming, i, n): finish(FDPLANET) return None elif iquad == IHW: # Hit an inhabited world -- very bad! - crmena(True, iquad, sector, w) + crmena(True, iquad, "sector", w) prout(_(" destroyed.")) game.state.nworldkl += 1 game.state.galaxy[game.quadrant.x][game.quadrant.y].planet = None @@ -1480,7 +1498,7 @@ def torpedo(course, r, incoming, i, n): if withprob(0.9): nova(w) else: - crmena(True, IHSTAR, sector, w) + crmena(True, IHSTAR, "sector", w) prout(_(" unaffected by photon blast.")) return None elif iquad == IHQUEST: # Hit a thingy @@ -1506,7 +1524,7 @@ def torpedo(course, r, incoming, i, n): return None elif iquad == IHBLANK: # Black hole skip(1) - crmena(True, IHBLANK, sector, w) + crmena(True, IHBLANK, "sector", w) prout(_(" swallows torpedo.")) return None elif iquad == IHWEB: # hit the web @@ -1523,7 +1541,7 @@ def torpedo(course, r, incoming, i, n): deadkl(w, iquad, w) return None skip(1) - crmena(True, IHT, sector, w) + crmena(True, IHT, "sector", w) if withprob(0.05): prout(_(" survives photon blast.")) return None @@ -1536,7 +1554,7 @@ def torpedo(course, r, incoming, i, n): else: # Problem! skip(1) proutn("Don't know how to handle torpedo collision with ") - crmena(True, iquad, sector, w) + crmena(True, iquad, "sector", w) skip(1) return None break @@ -1547,7 +1565,7 @@ def torpedo(course, r, incoming, i, n): game.quad[jw.x][jw.y]=iquad prout(_(" displaced by blast to Sector %s ") % jw) for ll in range(game.nenhere): - game.kdist[ll] = game.kavgd[ll] = distance(game.sector,game.ks[ll]) + game.enemies[ll].kdist = game.enemies[ll].kavgd = distance(game.sector,game.enemies[ll].kloc) sortklings() return None skip(1) @@ -1556,8 +1574,6 @@ def torpedo(course, r, incoming, i, n): def fry(hit): # critical-hit resolution - ktr=1 - # a critical hit occured if hit < (275.0-25.0*game.skill)*randreal(1.0, 1.5): return ncrit = int(1.0 + hit/(500.0+randreal(100))) @@ -1573,17 +1589,14 @@ def fry(hit): cdam.append(j) extradm = (hit*game.damfac)/(ncrit*randreal(75, 100)) game.damage[j] += extradm - if loop1 > 0: - for loop2 in range(loop1): - if j == cdam[loop2]: - break - if loop2 < loop1: - continue - ktr += 1 - if ktr==3: - skip(1) - proutn(_(" and ")) + skipcount = 0 + for (i, j) in enumerate(cdam): proutn(device[j]) + if skipcount % 3 == 2 and i < len(cdam)-1: + skip() + skipcount += 1 + if i < len(cdam)-1: + proutn(_(" and ")) prout(_(" damaged.")) if damaged(DSHIELD) and game.shldup: prout(_("***Shields knocked down.")) @@ -1623,16 +1636,16 @@ def attack(torps_ok): if game.skill <= SKILL_FAIR: where = "sector" for loop in range(game.nenhere): - if game.kpower[loop] < 0: + if game.enemies[loop].kpower < 0: continue; # too weak to attack # compute hit strength and diminish shield power r = randreal() # Increase chance of photon torpedos if docked or enemy energy low if game.condition == "docked": r *= 0.25 - if game.kpower[loop] < 500: + if game.enemies[loop].kpower < 500: r *= 0.25; - jay = game.ks[loop] + jay = game.enemies[loop].kloc iquad = game.quad[jay.x][jay.y] if iquad==IHT or (iquad==IHQUEST and not iqengry): continue @@ -1648,8 +1661,8 @@ def attack(torps_ok): continue; # Don't waste the effort! attempt = True; # Attempt to attack dustfac = 0.8 + randreal(0.5) - hit = game.kpower[loop]*math.pow(dustfac,game.kavgd[loop]) - game.kpower[loop] *= 0.75 + hit = game.enemies[loop].kpower*math.pow(dustfac,game.enemies[loop].kavgd) + game.enemies[loop].kpower *= 0.75 else: # Enemy uses photon torpedo course = 1.90985*math.atan2(game.sector.y-jay.y, jay.x-game.sector.x) hit = 0 @@ -1660,7 +1673,7 @@ def attack(torps_ok): attempt = True prout(" ") r = (randreal()+randreal())*0.5 - 0.5 - r += 0.002*game.kpower[loop]*r + r += 0.002*game.enemies[loop].kpower*r hit = torpedo(course, r, jay, 1, 1) if (game.state.remkl + game.state.remcom + game.state.nscrem)==0: finish(FWON); # Klingons did themselves in! @@ -1738,14 +1751,14 @@ def attack(torps_ok): game.state.crew -= icas # After attack, reset average distance to enemies for loop in range(game.nenhere): - game.kavgd[loop] = game.kdist[loop] + game.enemies[loop].kavgd = game.enemies[loop].kdist sortklings() return; def deadkl(w, type, mv): # kill a Klingon, Tholian, Romulan, or Thingy # Added mv to allow enemy to "move" before dying - crmena(True, type, sector, mv) + crmena(True, type, "sector", mv) # Decide what kind of enemy it is and update appropriately if type == IHR: # chalk up a Romulan @@ -1797,16 +1810,16 @@ def deadkl(w, type, mv): if is_scheduled(FCDBAS) and game.battle == game.quadrant and type==IHC: unschedule(FCDBAS) for i in range(game.nenhere): - if game.ks[i] == w: + if game.enemies[i].kloc == w: for j in range(i, game.nenhere): - game.ks[j] = game.ks[j+1] - game.kpower[j] = game.kpower[j+1] - game.kavgd[j] = game.kdist[j] = game.kdist[j+1] - game.ks[game.nenhere].x = 0 - game.ks[game.nenhere].y = 0 - game.kdist[game.nenhere] = 0 - game.kavgd[game.nenhere] = 0 - game.kpower[game.nenhere] = 0 + game.enemies[j].kloc = game.enemies[j+1].kloc + game.enemies[j].kpower = game.enemies[j+1].kpower + game.enemies[j].kavgd = game.enemies[j].kdist = game.enemies[j+1].kdist + game.enemies[game.nenhere].kloc.x = 0 + game.enemies[game.nenhere].kloc.y = 0 + game.enemies[game.nenhere].kdist = 0 + game.enemies[game.nenhere].kavgd = 0 + game.enemies[game.nenhere].kpower = 0 game.nenhere -= 1 break break @@ -1978,26 +1991,25 @@ def checkshctrl(rpow): return True; def hittem(hits): - # register a phaser hit on Klingons and Romulans - nenhr2 = game.nenhere; kk=1 + # register a phaser hit on Klingons and Romulans + nenhr2 = game.nenhere; kk=0 w = coord() skip(1) - for k in range(nenhr2): - wham = hits[k] + for (k, wham) in enumerate(hits): if wham==0: continue dustfac = randreal(0.9, 1.0) - hit = wham*math.pow(dustfac,game.kdist[kk]) - kpini = game.kpower[kk] + hit = wham*math.pow(dustfac,game.enemies[kk].kdist) + kpini = game.enemies[kk].kpower kp = math.fabs(kpini) if PHASEFAC*hit < kp: kp = PHASEFAC*hit - if game.kpower[kk] < 0: - game.kpower[kk] -= -kp + if game.enemies[kk].kpower < 0: + game.enemies[kk].kpower -= -kp else: - game.kpower[kk] -= kp - kpow = game.kpower[kk] - w = game.ks[kk] + game.enemies[kk].kpower -= kp + kpow = game.enemies[kk].kpower + w = game.enemies[kk].kloc if hit > 0.005: if not damaged(DSRSENS): boom(w) @@ -2016,14 +2028,15 @@ def hittem(hits): finish(FWON); if game.alldone: return - kk -= 1; # don't do the increment + 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: prout(_("***Mr. Spock- \"Captain, the vessel at Sector %s")%w) prout(_(" has just lost its firepower.\"")) - game.kpower[kk] = -kpow + game.enemies[kk].kpower = -kpow kk += 1 - return; + return def phasers(): # fire phasers @@ -2114,7 +2127,7 @@ def phasers(): chew() if not kz: for i in range(game.nenhere): - irec += math.fabs(game.kpower[i])/(PHASEFAC*math.pow(0.90,game.kdist[i]))*randreal(1.01, 1.06) + 1.0 + irec += math.fabs(game.enemies[i].kpower)/(PHASEFAC*math.pow(0.90,game.enemies[i].kdist))*randreal(1.01, 1.06) + 1.0 kz=1 proutn(_("%d units required. ") % irec) chew() @@ -2150,7 +2163,7 @@ def phasers(): hits.append(0.0) if powrem <= 0: continue - hits[i] = math.fabs(game.kpower[i])/(PHASEFAC*math.pow(0.90,game.kdist[i])) + hits[i] = math.fabs(game.enemies[i].kpower)/(PHASEFAC*math.pow(0.90,game.enemies[i].kdist)) over = randreal(1.01, 1.06) * hits[i] temp = powrem powrem -= hits[i] + over @@ -2187,7 +2200,7 @@ def phasers(): elif automode == "MANUAL": rpow = 0.0 for k in range(game.nenhere): - aim = game.ks[k] + aim = game.enemies[k].kloc ienm = game.quad[aim.x][aim.y] if msgflag: proutn(_("Energy available= %.2f") % (avail-0.006)) @@ -2206,7 +2219,7 @@ def phasers(): if key == IHEOL: chew() if itarg and k > kz: - irec=(abs(game.kpower[k])/(PHASEFAC*math.pow(0.9,game.kdist[k]))) * randreal(1.01, 1.06) + 1.0 + irec=(abs(game.enemies[k].kpower)/(PHASEFAC*math.pow(0.9,game.enemies[k].kdist))) * randreal(1.01, 1.06) + 1.0 kz = k proutn("(") if not damaged(DCOMPTR): @@ -2215,7 +2228,7 @@ def phasers(): proutn("??") proutn(") ") proutn(_("units to fire at ")) - crmena(False, ienm, sector, aim) + crmena(False, ienm, "sector", aim) proutn("- ") key = scan() if key == IHALPHA and isit("no"): @@ -2554,10 +2567,9 @@ def events(): game.iseenit = True announce() skip(1) - proutn(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") % game.battle) + prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") % game.battle) prout(_(" reports that it is under attack and that it can")) - proutn(_(" hold out only until stardate %d") % (int(scheduled(FCDBAS)))) - prout(".\"") + prout(_(" hold out only until stardate %d.\"") % (int(scheduled(FCDBAS)))) if cancelrest(): return elif evcode == FSCDBAS: # Supercommander destroys base @@ -2712,7 +2724,7 @@ def events(): q.klingons += 1 if game.quadrant == w: game.klhere += 1 - newkling(game.klhere) + game.enemies.append(newkling()) # recompute time left game.recompute() # report the disaster if we can @@ -2794,7 +2806,7 @@ def nova(nov): return # handle initial nova game.quad[nov.x][nov.y] = IHDOT - crmena(False, IHSTAR, sector, nov) + crmena(False, IHSTAR, "sector", nov) prout(_(" novas.")) game.state.galaxy[game.quadrant.x][game.quadrant.y].stars -= 1 game.state.starkl += 1 @@ -2829,13 +2841,13 @@ def nova(nov): hits[top2][2]=scratch.y game.state.galaxy[game.quadrant.x][game.quadrant.y].stars -= 1 game.state.starkl += 1 - crmena(True, IHSTAR, sector, scratch) + crmena(True, IHSTAR, "sector", scratch) prout(_(" novas.")) game.quad[scratch.x][scratch.y] = IHDOT elif iquad == IHP: # Destroy planet game.state.galaxy[game.quadrant.x][game.quadrant.y].planet = None game.state.nplankl += 1 - crmena(True, IHP, sector, scratch) + crmena(True, IHP, "sector", scratch) prout(_(" destroyed.")) game.iplnet.pclass = "destroyed" game.iplnet = None @@ -2854,7 +2866,7 @@ def nova(nov): invalidate(game.base) game.state.basekl += 1 newcnd() - crmena(True, IHB, sector, scratch) + crmena(True, IHB, "sector", scratch) prout(_(" destroyed.")) game.quad[scratch.x][scratch.y] = IHDOT elif iquad in (IHE, IHF): # Buffet ship @@ -2882,15 +2894,15 @@ def nova(nov): deadkl(scratch,iquad, scratch) elif iquad in (IHC,IHS,IHR): # Damage/destroy big enemies for ll in range(game.nenhere): - if game.ks[ll] == scratch: + if game.enemies[ll].kloc == scratch: break - game.kpower[ll] -= 800.0 # If firepower is lost, die - if game.kpower[ll] <= 0.0: + game.enemies[ll].kpower -= 800.0 # If firepower is lost, die + if game.enemies[ll].kpower <= 0.0: deadkl(scratch, iquad, scratch) break newc.x = scratch.x + scratch.x - hits[mm][1] newc.y = scratch.y + scratch.y - hits[mm][2] - crmena(True, iquad, sector, scratch) + crmena(True, iquad, "sector", scratch) proutn(_(" damaged")) if not VALID_SECTOR(newc.x, newc.y): # can't leave quadrant @@ -2899,7 +2911,7 @@ def nova(nov): iquad1 = game.quad[newc.x][newc.y] if iquad1 == IHBLANK: proutn(_(", blasted into ")) - crmena(False, IHBLANK, sector, newc) + crmena(False, IHBLANK, "sector", newc) skip(1) deadkl(scratch, iquad, newc) break @@ -2910,8 +2922,8 @@ def nova(nov): proutn(_(", buffeted to Sector %s") % newc) game.quad[scratch.x][scratch.y] = IHDOT game.quad[newc.x][newc.y] = iquad - game.ks[ll] = newc - game.kdist[ll] = game.kavgd[ll] = distance(game.sector, newc) + game.enemies[ll].kloc = newc + game.enemies[ll].kdist = game.enemies[ll].kavgd = distance(game.sector, newc) skip(1) if top == top2: break @@ -3109,8 +3121,8 @@ def kaboom(): whammo = 25.0 * game.energy l=1 while l <= game.nenhere: - if game.kpower[l]*game.kdist[l] <= whammo: - deadkl(game.ks[l], game.quad[game.ks[l].x][game.ks[l].y], game.ks[l]) + if game.enemies[l].kpower*game.enemies[l].kdist <= whammo: + deadkl(game.enemies[l].kloc, game.quad[game.enemies[l].kloc.x][game.enemies[l].kloc.y], game.enemies[l].kloc) l += 1 finish(FDILITHIUM) @@ -3631,13 +3643,15 @@ def prout(line): def prouts(line): "print slowly!" for c in line: - time.sleep(0.03) + if not replayfp or replayfp.closed: # Don't slow down replays + time.sleep(0.03) proutn(c) if game.options & OPTION_CURSES: wrefresh(curwnd) else: sys.stdout.flush() - time.sleep(0.03) + if not replayfp or replayfp.closed: + time.sleep(0.03) def cgetline(): "Get a line of input." @@ -3648,6 +3662,7 @@ def cgetline(): if replayfp and not replayfp.closed: while True: line = replayfp.readline() + proutn(line) if line == '': prout("*** Replay finished") replayfp.close() @@ -3655,7 +3670,7 @@ def cgetline(): elif line[0] != "#": break else: - line = raw_input("COMMAND> ") + line = raw_input() if logfp: logfp.write(line + "\n") return line @@ -3748,7 +3763,7 @@ def drawmaps(mode): setwnd(lrscan_window) lrscan_window.clear() lrscan_window.move(0, 0) - lrscan() + lrscan(silent=False) def put_srscan_sym(w, sym): "Emit symbol for short-range scan." @@ -3853,14 +3868,14 @@ def imove(novapush): game.quad[game.sector.x][game.sector.y] = game.ship if game.nenhere: for m in range(game.nenhere): - finald = distance(w, game.ks[m]) - game.kavgd[m] = 0.5 * (finald+game.kdist[m]) - game.kdist[m] = finald + finald = distance(w, game.enemies[m].kloc) + game.enemies[m].kavgd = 0.5 * (finald+game.enemies[m].kdist) + game.enemies[m].kdist = finald sortklings() if not game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova: attack(False) for m in range(game.nenhere): - game.kavgd[m] = game.kdist[m] + game.enemies[m].kavgd = game.enemies[m].kdist newcnd() drawmaps(0) setwnd(message_window) @@ -3900,8 +3915,8 @@ def imove(novapush): if game.nenhere != 0 and not novapush: newcnd() for m in range(game.nenhere): - finald = distance(w, game.ks[m]) - game.kavgd[m] = 0.5 * (finald + game.kdist[m]) + finald = distance(w, game.enemies[m].kloc) + game.enemies[m].kavgd = 0.5 * (finald + game.enemies[m].kdist) # # Stas Sergeev added the condition # that attacks only happen if Klingons @@ -5211,7 +5226,7 @@ def deathray(): prouts(_("Sulu- \"Captain! It's working!\"")) skip(2) while game.nenhere > 0: - deadkl(game.ks[1], game.quad[game.ks[1].x][game.ks[1].y],game.ks[1]) + deadkl(game.enemies[1].kloc, game.quad[game.enemies[1].kloc.x][game.enemies[1].kloc.y],game.enemies[1].kloc) prout(_("Ensign Chekov- \"Congratulations, Captain!\"")) if (game.state.remkl + game.state.remcom + game.state.nscrem) == 0: finish(FWON) @@ -5363,30 +5378,34 @@ def report(): (i, (_("s"), "")[i==1])) skip(1) -def lrscan(): +def lrscan(silent): # long-range sensor scan if damaged(DLRSENS): # Now allow base's sensors if docked if game.condition != "docked": - prout(_("LONG-RANGE SENSORS DAMAGED.")) + if not silent: + prout(_("LONG-RANGE SENSORS DAMAGED.")) return - prout(_("Starbase's long-range scan")) - else: + if not silent: + prout(_("Starbase's long-range scan")) + elif not silent: prout(_("Long-range scan")) for x in range(game.quadrant.x-1, game.quadrant.x+2): - proutn(" ") + if not silent: + proutn(" ") for y in range(game.quadrant.y-1, game.quadrant.y+2): if not VALID_QUADRANT(x, y): - proutn(" -1") + if not silent: + proutn(" -1") else: if not damaged(DRADIO): game.state.galaxy[x][y].charted = True game.state.chart[x][y].klingons = game.state.galaxy[x][y].klingons game.state.chart[x][y].starbase = game.state.galaxy[x][y].starbase game.state.chart[x][y].stars = game.state.galaxy[x][y].stars - if game.state.galaxy[x][y].supernova: + if not silent and game.state.galaxy[x][y].supernova: proutn(" ***") - else: + elif not silent: proutn(" %3d" % (game.state.chart[x][y].klingons*100 + game.state.chart[x][y].starbase * 10 + game.state.chart[x][y].stars)) prout(" ") @@ -5420,6 +5439,8 @@ def rechart(): def chart(): # display the star chart chew() + if (game.options & OPTION_AUTOSCAN): + lrscan(silent=True) if not damaged(DRADIO): rechart() if game.lastchart < game.state.date and game.condition == "docked": @@ -5979,10 +6000,10 @@ def setup(needprompt): break game.state.kscmdr = w game.state.galaxy[w.x][w.y].klingons += 1 - # Place thing (in tournament game, thingx == -1, don't want one!) + # Place thing (in tournament game, we don't want one!) global thing - if thing == None: - thing = randplace(GALSIZE) + if game.tourn is None: + thing = randplace(GALSIZE) skip(2) game.state.snap = False if game.skill == SKILL_NOVICE: @@ -6154,13 +6175,9 @@ def newcnd(): if not game.alive: game.condition="dead" -def newkling(i): - # drop new Klingon into current quadrant - pi = dropin(IHK) - game.ks[i] = pi - game.kdist[i] = game.kavgd[i] = distance(game.sector, pi) - game.kpower[i] = randreal(300, 450) + 25.0*game.skill - return pi +def newkling(): + # drop new Klingon into current quadrant + return enemy(loc=dropin(IHK), power=randreal(300, 450) + 25.0*game.skill) def newqad(shutup): # set up a new state of quadrant, for when we enter or re-enter it @@ -6192,32 +6209,30 @@ def newqad(shutup): game.nenhere = game.klhere + game.irhere # Position Starship game.quad[game.sector.x][game.sector.y] = game.ship + game.enemies = [] if q.klingons: - w.x = w.y = 0 # quiet a gcc warning # Position ordinary Klingons for i in range(game.klhere): - w = newkling(i) + game.enemies.append(newkling()) # If we need a commander, promote a Klingon for i in range(game.state.remcom): if game.state.kcmdr[i] == game.quadrant: - break - - if i <= game.state.remcom: - game.quad[w.x][w.y] = IHC - game.kpower[game.klhere] = randreal(950, 1350) + 50.0*game.skill - game.comhere = True + e = game.enemies[game.klhere-1] + game.quad[e.kloc.x][e.kloc.y] = IHC + e.kpower = randreal(950,1350) + 50.0*game.skill + game.comhere = True + break # If we need a super-commander, promote a Klingon if game.quadrant == game.state.kscmdr: - game.quad[game.ks[0].x][game.ks[0].y] = IHS - game.kpower[0] = randreal(1175.0, 1575.0) + 125.0*game.skill + e = game.enemies[0] + game.quad[e.kloc.x][e.kloc.y] = IHS + e.kpower = randreal(1175.0, 1575.0) + 125.0*game.skill game.iscate = (game.state.remkl > 1) game.ishere = True # Put in Romulans if needed for i in range(game.klhere, game.nenhere): - w = dropin(IHR) - game.ks[i] = w - game.kdist[i] = game.kavgd[i] = distance(game.sector, w) - game.kpower[i] = randreal(400.0, 850.0) + 50.0*game.skill + game.enemies.append(enemy(loc=dropin(IHR), + power=randreal(400.0,850.0)+50.0*game.skill)) # If quadrant needs a starbase, put it in if q.starbase: game.base = dropin(IHB) @@ -6231,9 +6246,8 @@ def newqad(shutup): # Check for condition newcnd() # And finally the stars - for i in range(q.stars): + for i in range(q.stars): dropin(IHSTAR) - # Check for RNZ if game.irhere > 0 and game.klhere == 0: game.neutz = True @@ -6246,15 +6260,12 @@ def newqad(shutup): prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!")) if shutup==0: # Put in THING if needed - global thing if thing == game.quadrant: - w = dropin(IHQUEST) - thing = randplace(GALSIZE) + e = enemy(dropin(IHQUEST)) + e.kdist = e.kavgd = distance(game.sector, e.kloc) + e.kpower = randreal(6000,6500.0)+250.0*game.skill + games.enemies.append(e) game.nenhere += 1 - game.ks[game.nenhere] = w - game.kdist[game.nenhere] = game.kavgd[game.nenhere] = \ - distance(game.sector, w) - game.kpower[game.nenhere] = randreal(6000,6500.0)+250.0*game.skill if not damaged(DSRSENS): skip(1) prout(_("Mr. Spock- \"Captain, this is most unusual.")) @@ -6271,11 +6282,9 @@ def newqad(shutup): if game.quad[game.tholian.x][game.tholian.y] == IHDOT: break game.quad[game.tholian.x][game.tholian.y] = IHT + game.enemies.append(loc=game.tholian, + power=randrange(100, 500) + 25.0*game.skill) game.nenhere += 1 - game.ks[game.nenhere] = game.tholian - game.kdist[game.nenhere] = game.kavgd[game.nenhere] = \ - distance(game.sector, game.tholian) - game.kpower[game.nenhere] = randrange(100, 500) + 25.0*game.skill # Reserve unoccupied corners if game.quad[0][0]==IHDOT: game.quad[0][0] = 'X' @@ -6308,24 +6317,24 @@ def sortklings(): return while True: sw = False - for j in range(game.nenhere): - if game.kdist[j] > game.kdist[j+1]: + for j in range(game.nenhere-1): + if game.enemies[j].kdist > game.enemies[j+1].kdist: sw = True - t = game.kdist[j] - game.kdist[j] = game.kdist[j+1] - game.kdist[j+1] = t - t = game.kavgd[j] - game.kavgd[j] = game.kavgd[j+1] - game.kavgd[j+1] = t - k = game.ks[j].x - game.ks[j].x = game.ks[j+1].x - game.ks[j+1].x = k - k = game.ks[j].y - game.ks[j].y = game.ks[j+1].y - game.ks[j+1].y = k - t = game.kpower[j] - game.kpower[j] = game.kpower[j+1] - game.kpower[j+1] = t + t = game.enemies[j].kdist + game.enemies[j].kdist = game.enemies[j+1].kdist + game.enemies[j+1].kdist = t + t = game.enemies[j].kavgd + game.enemies[j].kavgd = game.enemies[j+1].kavgd + game.enemies[j+1].kavgd = t + k = game.enemies[j].kloc.x + game.enemies[j].kloc.x = game.enemies[j+1].kloc.x + game.enemies[j+1].kloc.x = k + k = game.enemies[j].kloc.y + game.enemies[j].kloc.y = game.enemies[j+1].kloc.y + game.enemies[j+1].kloc.y = k + t = game.enemies[j].kpower + game.enemies[j].kpower = game.enemies[j+1].kpower + game.enemies[j+1].kpower = t if not sw: break @@ -6475,6 +6484,7 @@ def makemoves(): chew() setwnd(prompt_window) clrscr() + proutn("COMMAND> ") if scan() == IHEOL: if game.options & OPTION_CURSES: makechart() @@ -6500,7 +6510,7 @@ def makemoves(): elif cmd == "REQUEST": # status request request() elif cmd == "LRSCAN": # long range scan - lrscan() + lrscan(silent=False) elif cmd == "PHASERS": # phasers phasers() if game.ididit: @@ -6829,84 +6839,89 @@ def debugme(): atover(True) if __name__ == '__main__': - global line, thing, game, idebug, iqengry - game = citem = aaitem = inqueue = None - line = '' - thing = coord() - iqengry = False - game = gamestate() - idebug = 0 - game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_SHOWME | OPTION_PLAIN | OPTION_ALMY) - # Disable curses mode until the game logic is working. - # if os.getenv("TERM"): - # game.options |= OPTION_CURSES | OPTION_SHOWME - # else: - game.options |= OPTION_TTY - seed = int(time.time()) - (options, arguments) = getopt.getopt(sys.argv[1:], "r:tx") - for (switch, val) in options: - if switch == '-r': - try: - replayfp = open(val, "r") - except IOError: - sys.stderr.write("sst: can't open replay file %s\n" % val) - raise SystemExit, 1 - try: - line = replayfp.readline().strip() - (leader, key, seed) = line.split() - seed = eval(seed) - sys.stderr.write("sst2k: seed set to %s\n" % seed) - line = replayfp.readline().strip() - arguments += line.split()[2:] - except ValueError: - sys.stderr.write("sst: replay file %s is ill-formed\n"% val) - os.exit(1) - game.options |= OPTION_TTY - game.options &=~ OPTION_CURSES - elif switch == '-t': - game.options |= OPTION_TTY - game.options &=~ OPTION_CURSES - elif switch == '-x': - idebug = True - else: - sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n") - os.exit(0) - # where to save the input in case of bugs try: - logfp = open("/usr/tmp/sst-input.log", "w") - except IOError: - sys.stderr.write("sst: warning, can't open logfile\n") - if logfp: - logfp.write("# seed %s\n" % seed) - logfp.write("# options %s\n" % " ".join(arguments)) - random.seed(seed) - iostart() - if arguments: - inqueue = arguments - else: - inqueue = None - while True: # Play a game - setwnd(fullscreen_window) - clrscr() - prelim() - setup(needprompt=not inqueue) - if game.alldone: - score() - game.alldone = False - else: - makemoves() - skip(1) - stars() - skip(1) - if game.tourn and game.alldone: - proutn(_("Do you want your score recorded?")) - if ja() == True: - chew2() - freeze(False) - chew() - proutn(_("Do you want to play again? ")) - if not ja(): - break - skip(1) - prout(_("May the Great Bird of the Galaxy roost upon your home planet.")) - raise SystemExit, 0 + global line, thing, game, idebug, iqengry + game = citem = aaitem = inqueue = None + line = '' + thing = coord() + iqengry = False + game = gamestate() + idebug = 0 + game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY) + # Disable curses mode until the game logic is working. + # if os.getenv("TERM"): + # game.options |= OPTION_CURSES | OPTION_SHOWME + # else: + game.options |= OPTION_TTY + seed = int(time.time()) + (options, arguments) = getopt.getopt(sys.argv[1:], "r:tx") + for (switch, val) in options: + if switch == '-r': + try: + replayfp = open(val, "r") + except IOError: + sys.stderr.write("sst: can't open replay file %s\n" % val) + raise SystemExit, 1 + try: + line = replayfp.readline().strip() + (leader, key, seed) = line.split() + seed = eval(seed) + sys.stderr.write("sst2k: seed set to %s\n" % seed) + line = replayfp.readline().strip() + arguments += line.split()[2:] + except ValueError: + sys.stderr.write("sst: replay file %s is ill-formed\n"% val) + raise SystemExit(1) + game.options |= OPTION_TTY + game.options &=~ OPTION_CURSES + elif switch == '-t': + game.options |= OPTION_TTY + game.options &=~ OPTION_CURSES + elif switch == '-x': + idebug = True + else: + sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n") + raise SystemExit, 1 + # where to save the input in case of bugs + try: + logfp = open("/usr/tmp/sst-input.log", "w") + except IOError: + sys.stderr.write("sst: warning, can't open logfile\n") + if logfp: + logfp.write("# seed %s\n" % seed) + logfp.write("# options %s\n" % " ".join(arguments)) + random.seed(seed) + iostart() + if arguments: + inqueue = arguments + else: + inqueue = None + while True: # Play a game + setwnd(fullscreen_window) + clrscr() + prelim() + setup(needprompt=not inqueue) + if game.alldone: + score() + game.alldone = False + else: + makemoves() + skip(1) + stars() + skip(1) + if game.tourn and game.alldone: + proutn(_("Do you want your score recorded?")) + if ja() == True: + chew2() + freeze(False) + chew() + proutn(_("Do you want to play again? ")) + if not ja(): + break + skip(1) + prout(_("May the Great Bird of the Galaxy roost upon your home planet.")) + raise SystemExit, 0 + except KeyboardInterrupt: + print"" + pass +