#!/usr/bin/env python3 """ sst.py -- Super Star Trek 2K SST2K is a Python translation of a C translation of a FORTRAN original dating back to 1973. Beautiful Python it is not, but it works. Translation by Eric S. Raymond; original game by David Matuszek and Paul Reynolds, with modifications by Don Smith, Tom Almy, Stas Sergeev, and Eric S. Raymond. See the doc/HACKING file in the distribution for designers notes and advice on how to modify (and how not to modify!) this code. """ import os, sys, math, curses, time, readline, pickle, random, copy, gettext, getpass version = "2.1" docpath = (".", "../doc", "/usr/share/doc/sst") def _(st): return gettext.gettext(st) GALSIZE = 8 # Galaxy size in quadrants NINHAB = (GALSIZE * GALSIZE // 2) # Number of inhabited worlds MAXUNINHAB = 10 # Maximum uninhabited worlds QUADSIZE = 10 # Quadrant size in sectors BASEMIN = 2 # Minimum starbases BASEMAX = (GALSIZE * GALSIZE // 12) # Maximum starbases MAXKLGAME = 127 # Maximum Klingons per game MAXKLQUAD = 9 # Maximum Klingons per quadrant FULLCREW = 428 # Crew size. BSD Trek was 387, that's wrong FOREVER = 1e30 # Time for the indefinite future MAXBURST = 3 # Max # of torps you can launch in one turn MINCMDR = 10 # Minimum number of Klingon commanders DOCKFAC = 0.25 # Repair faster when docked PHASEFAC = 2.0 # Unclear what this is, it was in the C version DEFAULT = -1 BLACK = 0 BLUE = 1 GREEN = 2 CYAN = 3 RED = 4 MAGENTA = 5 BROWN = 6 LIGHTGRAY = 7 DARKGRAY = 8 LIGHTBLUE = 9 LIGHTGREEN = 10 LIGHTCYAN = 11 LIGHTRED = 12 LIGHTMAGENTA = 13 YELLOW = 14 WHITE = 15 class TrekError(Exception): pass 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 < GALSIZE and self.j >= 0 and self.j < GALSIZE def valid_sector(self): return self.i >= 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): return self.i != None and self.j != None def __eq__(self, other): return other != None and self.i == other.i and self.j == other.j 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) def __sub__(self, other): return Coord(self.i-other.i, self.j-other.j) def __mul__(self, other): return Coord(self.i*other, self.j*other) def __rmul__(self, other): return Coord(self.i*other, self.j*other) def __div__(self, other): return Coord(self.i/other, self.j/other) def __mod__(self, other): return Coord(self.i % other, self.j % other) def __truediv__(self, other): return Coord(self.i/other, self.j/other) def roundtogrid(self): return Coord(int(round(self.i)), int(round(self.j))) def distance(self, other=None): if not other: other = Coord(0, 0) 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() if self.i == 0: s.i = 0 else: s.i = self.i / abs(self.i) if self.j == 0: s.j = 0 else: s.j = self.j / abs(self.j) return s def quadrant(self): #print "Location %s -> %s" % (self, (self / QUADSIZE).roundtogrid()) return self.roundtogrid() / QUADSIZE def sector(self): return self.roundtogrid() % QUADSIZE def scatter(self): s = Coord() s.i = self.i + randrange(-1, 2) s.j = self.j + randrange(-1, 2) return s def __str__(self): if self.i == None or self.j == None: return "Nowhere" return "%s - %s" % (self.i+1, self.j+1) __repr__ = __str__ class Thingy(Coord): "Do not anger the Space Thingy!" def __init__(self): Coord.__init__(self) self.angered = False def angry(self): self.angered = True def at(self, q): return (q.i, q.j) == (self.i, self.j) class Planet: def __init__(self): self.name = None # string-valued if inhabited 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" self.inhabited = False # is it inhabited? def __str__(self): return self.name class Quadrant: def __init__(self): self.stars = 0 self.planet = None self.starbase = False self.klingons = 0 self.romulans = 0 self.supernova = False self.charted = False self.status = "secure" # Could be "secure", "distressed", "enslaved" class Page: def __init__(self): self.stars = None self.starbase = False self.klingons = None def __repr__(self): return "<%s,%s,%s>" % (self.klingons, self.starbase, self.stars) def fill2d(size, fillfun): "Fill an empty list in 2D." lst = [] for i in range(size): lst.append([]) for j in range(size): lst[i].append(fillfun(i, j)) return lst class Snapshot: def __init__(self): self.snap = False # snapshot taken self.crew = 0 # crew complement self.remkl = 0 # remaining klingons self.nscrem = 0 # remaining super commanders self.starkl = 0 # destroyed stars self.basekl = 0 # destroyed bases self.nromrem = 0 # Romulans remaining self.nplankl = 0 # destroyed uninhabited planets self.nworldkl = 0 # destroyed inhabited planets self.planets = [] # Planet information self.date = 0.0 # stardate self.remres = 0 # remaining resources self.remtime = 0 # remaining time self.baseq = [] # Base quadrant coordinates self.kcmdr = [] # Commander quadrant coordinates self.kscmdr = Coord() # Supercommander quadrant coordinates # the galaxy self.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant()) # the starchart self.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page()) class Event: def __init__(self): self.date = None # A real number self.quadrant = None # A coord structure # game options OPTION_ALL = 0xffffffff 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 (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 (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 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 SKILL_NONE = 0 SKILL_NOVICE = 1 SKILL_FAIR = 2 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" # Define future events FSPY = 0 # Spy event happens always (no future[] entry) # can cause SC to tractor beam Enterprise FSNOVA = 1 # Supernova FTBEAM = 2 # Commander tractor beams Enterprise FSNAP = 3 # Snapshot for time warp FBATTAK = 4 # Commander attacks base FCDBAS = 5 # Commander destroys base FSCMOVE = 6 # Supercommander moves (might attack base) FSCDBAS = 7 # Supercommander destroys base FDSPROB = 8 # Move deep space probe FDISTR = 9 # Emit distress call from an inhabited world FENSLV = 10 # Inhabited word is enslaved */ FREPRO = 11 # Klingons build a ship in an enslaved system NEVENTS = 12 # Abstract out the event handling -- underlying data structures will change # when we implement stateful events def findevent(evtype): return game.future[evtype] 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 game.enemies.append(self) def move(self, loc): motion = (loc != self.location) if self.location.i is not None and self.location.j is not None: if motion: if self.type == 'T': game.quad[self.location.i][self.location.j] = '#' else: game.quad[self.location.i][self.location.j] = '.' if loc: self.location = copy.copy(loc) game.quad[self.location.i][self.location.j] = self.type self.kdist = self.kavgd = (game.sector - loc).distance() else: 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: 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 = 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.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 self.tholian = None # Tholian enemy object self.base = None # position of base in current quadrant self.battle = None # base coordinates being attacked self.plnet = None # location of planet in quadrant self.gamewon = False # Finished! self.ididit = False # action taken -- allows enemy to attack self.alive = False # we are alive (not killed) self.justin = False # just entered quadrant self.shldup = False # shields are up self.shldchg = False # shield is changing (affects efficiency) self.iscate = False # super commander is here self.ientesc = False # attempted escape from supercommander self.resting = False # rest time self.icraft = False # Kirk in Galileo self.landed = False # party on planet (true), on ship (false) self.alldone = False # game is now finished self.neutz = False # Romulan Neutral Zone self.isarmed = False # probe is armed self.inorbit = False # orbiting a planet self.imine = False # mining self.icrystl = False # dilithium crystals aboard self.iseenit = False # seen base attack report self.thawed = False # thawed game self.condition = None # "green", "yellow", "red", "docked", "dead" self.iscraft = None # "onship", "offship", "removed" self.skill = None # Player skill level self.inkling = 0 # initial number of klingons self.inbase = 0 # initial number of bases self.incom = 0 # initial number of commanders self.inscom = 0 # initial number of commanders self.inrom = 0 # initial number of commanders self.instar = 0 # initial stars self.intorps = 0 # initial/max torpedoes self.torps = 0 # number of torpedoes self.ship = 0 # ship type -- 'E' is Enterprise self.abandoned = 0 # count of crew abandoned in space self.length = 0 # length of game self.klhere = 0 # klingons here self.casual = 0 # causalties self.nhelp = 0 # calls for help self.nkinks = 0 # count of energy-barrier crossings self.iplnet = None # planet # in quadrant self.inplan = 0 # initial planets self.irhere = 0 # Romulans in quadrant self.isatb = 0 # =2 if super commander is attacking base self.tourn = None # tournament number self.nprobes = 0 # number of probes available self.inresor = 0.0 # initial resources self.intime = 0.0 # initial time self.inenrg = 0.0 # initial/max energy self.inshld = 0.0 # initial/max shield self.inlsr = 0.0 # initial life support resources self.indate = 0.0 # initial date self.energy = 0.0 # energy level self.shield = 0.0 # shield level self.warpfac = 0.0 # warp speed self.lsupres = 0.0 # life support reserves self.optime = 0.0 # time taken by current operation self.damfac = 0.0 # damage factor self.lastchart = 0.0 # time star chart was last updated 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? 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 ? # game.state.remres/(game.state.remkl + 4*len(game.state.kcmdr)) : 99 # 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. self.state.remtime = self.state.remres/(self.state.remkl + 4*len(self.state.kcmdr)) FWON = 0 FDEPLETE = 1 FLIFESUP = 2 FNRG = 3 FBATTLE = 4 FNEG3 = 5 FNOVA = 6 FSNOVAED = 7 FABANDN = 8 FDILITHIUM = 9 FMATERIALIZE = 10 FPHASER = 11 FLOST = 12 FMINING = 13 FDPLANET = 14 FPNOVA = 15 FSSC = 16 FSTRACTOR = 17 FDRAY = 18 FTRIBBLE = 19 FHOLE = 20 FCREW = 21 def withprob(p): return random.random() < p def randrange(*args): return random.randrange(*args) def randreal(*args): v = random.random() if len(args) == 1: v *= args[0] # from [0, args[0]) elif len(args) == 2: v = args[0] + v*(args[1]-args[0]) # from [args[0], args[1]) return v # Code from ai.c begins here def welcoming(iq): "Would this quadrant welcome another Klingon?" return iq.valid_quadrant() and \ not game.state.galaxy[iq.i][iq.j].supernova and \ game.state.galaxy[iq.i][iq.j].klingons < MAXKLQUAD def tryexit(enemy, look, irun): "A bad guy attempts to bug out." 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 if enemy.type == 'R': return False # Romulans cannot escape! if not irun: # avoid intruding on another commander's territory if enemy.type == 'C': if iq in game.state.kcmdr: return [] # refuse to leave if currently attacking starbase if game.battle == game.quadrant: return [] # don't leave if over 1000 units of energy if enemy.power > 1000.0: return [] oldloc = copy.copy(enemy.location) # handle local matters related to escape enemy.move(None) game.klhere -= 1 if game.condition != "docked": newcnd() # 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': game.iscate = False game.ientesc = False game.isatb = 0 schedule(FSCMOVE, 0.2777) unschedule(FSCDBAS) game.state.kscmdr = iq else: for cmdr in game.state.kcmdr: if cmdr == game.quadrant: game.state.kcmdr.append(iq) break # report move out of quadrant. return [(True, enemy, oldloc, ibq)] # The bad-guy movement algorithm: # # 1. Enterprise has "force" based on condition of phaser and photon torpedoes. # If both are operating full strength, force is 1000. If both are damaged, # force is -1000. Having shields down subtracts an additional 1000. # # 2. Enemy has forces equal to the energy of the attacker plus # 100*(K+R) + 500*(C+S) - 400 for novice through good levels OR # 346*K + 400*R + 500*(C+S) - 400 for expert and emeritus. # # Attacker Initial energy levels (nominal): # Klingon Romulan Commander Super-Commander # Novice 400 700 1200 # Fair 425 750 1250 # Good 450 800 1300 1750 # Expert 475 850 1350 1875 # Emeritus 500 900 1400 2000 # VARIANCE 75 200 200 200 # # Enemy vessels only move prior to their attack. In Novice - Good games # only commanders move. In Expert games, all enemy vessels move if there # is a commander present. In Emeritus games all enemy vessels move. # # 3. If Enterprise is not docked, an aggressive action is taken if enemy # forces are 1000 greater than Enterprise. # # Agressive action on average cuts the distance between the ship and # the enemy to 1/4 the original. # # 4. At lower energy advantage, movement units are proportional to the # advantage with a 650 advantage being to hold ground, 800 to move forward # 1, 950 for two, 150 for back 4, etc. Variance of 100. # # If docked, is reduced by roughly 1.75*game.skill, generally forcing a # retreat, especially at high skill levels. # # 5. Motion is limited to skill level, except for SC hi-tailing it out. def movebaddy(enemy): "Tactical movement for the bad guys." goto = Coord() look = Coord() irun = False # This should probably be just (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant) if game.skill >= SKILL_EXPERT: nbaddys = (((game.quadrant in game.state.kcmdr)*2 + (game.state.kscmdr==game.quadrant)*2+game.klhere*1.23+game.irhere*1.5)/2.0) else: nbaddys = (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant) old_dist = enemy.kdist mdist = int(old_dist + 0.5) # Nearest integer distance # If SC, check with spy to see if should hi-tail it if enemy.type == 'S' and \ (enemy.power <= 500.0 or (game.condition=="docked" and not damaged(DPHOTON))): irun = True motion = -QUADSIZE else: # 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! if not damaged(DPHASER) or not damaged(DPHOTON): if damaged(DPHASER): # phasers damaged forces += 300.0 else: forces -= 0.2*(game.energy - 2500.0) if damaged(DPHOTON): # photon torpedoes damaged forces += 300.0 else: forces -= 50.0*game.torps else: # phasers and photon tubes both out! forces += 1000.0 motion = 0 if forces <= 1000.0 and game.condition != "docked": # Typical situation motion = ((forces + randreal(200))/150.0) - 5.0 else: if forces > 1000.0: # Very strong -- move in for kill motion = (1.0 - randreal())**2 * old_dist + 1.0 if game.condition == "docked" and (game.options & OPTION_BASE): # protected by base -- back off ! motion -= game.skill*(2.0-randreal()**2) if game.idebug: proutn("=== MOTION = %d, FORCES = %1.2f, " % (motion, forces)) # don't move if no motion if motion == 0: return [] # Limit motion according to skill if abs(motion) > game.skill: if motion < 0: motion = -game.skill else: motion = game.skill # calculate preferred number of steps nsteps = abs(int(motion)) if motion > 0 and nsteps > mdist: nsteps = mdist # don't overshoot if nsteps > QUADSIZE: nsteps = QUADSIZE # This shouldn't be necessary if nsteps < 1: 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 if 2.0 * abs(m.i) < abs(m.j): m.i = 0 if 2.0 * abs(m.j) < abs(game.sector.i-enemy.location.i): m.j = 0 m = (motion * m).sgn() goto = enemy.location # main move loop for ll in range(nsteps): if game.idebug: proutn(" %d" % (ll+1)) # Check if preferred position available look = goto + m if m.i < 0: krawli = 1 else: krawli = -1 if m.j < 0: krawlj = 1 else: krawlj = -1 success = False attempts = 0 # Settle mysterious hang problem while attempts < 20 and not success: attempts += 1 if look.i < 0 or look.i >= QUADSIZE: if motion < 0: return tryexit(enemy, look, irun) if krawli == m.i or m.j == 0: break look.i = goto.i + krawli krawli = -krawli elif look.j < 0 or look.j >= QUADSIZE: if motion < 0: return tryexit(enemy, look, irun) if krawlj == m.j or m.i == 0: break 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 if game.quad[look.i][look.j] == game.ship and \ (enemy.type == 'C' or enemy.type == 'S'): collision(rammed=True, enemy=enemy) return [] if krawli != m.i and m.j != 0: look.i = goto.i + krawli krawli = -krawli elif krawlj != m.j and m.i != 0: look.j = goto.j + krawlj krawlj = -krawlj else: break # we have failed else: success = True if success: goto = look if game.idebug: proutn(repr(goto)) else: break # done early if game.idebug: skip(1) # Enemy moved, but is still in sector return [(False, enemy, old_dist, goto)] def moveklings(): "Sequence Klingon tactical movement." if game.idebug: prout("== MOVCOM") # Figure out which Klingon is the commander (or Supercommander) # and do move tacmoves = [] if game.quadrant in game.state.kcmdr: for enemy in game.enemies: if enemy.type == 'C': tacmoves += movebaddy(enemy) if game.state.kscmdr == game.quadrant: for enemy in game.enemies: if enemy.type == 'S': tacmoves += movebaddy(enemy) break # If skill level is high, move other Klingons and Romulans too! # Move these last so they can base their actions on what the # commander(s) do. if game.skill >= SKILL_EXPERT and (game.options & OPTION_MVBADDY): for enemy in game.enemies: if enemy.type in ('K', 'R'): tacmoves += movebaddy(enemy) return tacmoves def movescom(iq, avoid): "Commander movement helper." # Avoid quadrants with bases if we want to avoid Enterprise if not welcoming(iq) or (avoid and iq in game.state.baseq): return False if game.justin and not game.iscate: return False # do the move 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: # SC has scooted, remove him from current quadrant game.iscate = False game.isatb = 0 game.ientesc = False unschedule(FSCDBAS) for enemy in game.enemies: if enemy.type == 'S': enemy.move(None) game.klhere -= 1 if game.condition != "docked": newcnd() sortenemies() # check for a helpful planet for i in range(game.inplan): if game.state.planets[i].quadrant == game.state.kscmdr and \ game.state.planets[i].crystals == "present": # destroy the planet game.state.planets[i].pclass = "destroyed" game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].planet = None if communicating(): announce() prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports")) proutn(_(" a planet in Quadrant %s has been destroyed") % game.state.kscmdr) prout(_(" by the Super-commander.\"")) break return True # looks good! def supercommander(): "Move the Super Commander." iq = Coord() sc = Coord() ibq = Coord() idelta = Coord() basetbl = [] 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 \ (game.state.date-game.indate) < 3.0) if not game.iscate and avoid: # compute move away from Enterprise idelta = game.state.kscmdr-game.quadrant if idelta.distance() > 2.0: # circulate in space idelta.i = game.state.kscmdr.j-game.quadrant.j idelta.j = game.quadrant.i-game.state.kscmdr.i else: # compute distances to starbases if not game.state.baseq: # nothing left to do unschedule(FSCMOVE) return sc = game.state.kscmdr for (i, base) in enumerate(game.state.baseq): basetbl.append((i, (base - sc).distance())) if game.state.baseq > 1: basetbl.sort(key=lambda x: x[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): continue # if there is a commander, and no other base is appropriate, # we will take the one with the commander for cmdr in game.state.kcmdr: if base == cmdr and ifindit != 2: ifindit = 2 iwhichb = i break else: # no commander -- use this one ifindit = 1 iwhichb = i break if ifindit == 0: return # Nothing suitable -- wait until next time ibq = game.state.baseq[iwhichb] # decide how to move toward base idelta = ibq - game.state.kscmdr # Maximum movement is 1 quadrant in either or both axes idelta = idelta.sgn() # try moving in both x and y directions # there was what looked like a bug in the Almy C code here, # but it might be this translation is just wrong. iq = game.state.kscmdr + idelta if not movescom(iq, avoid): # failed -- try some other maneuvers if idelta.i == 0 or idelta.j == 0: # attempt angle move if idelta.i != 0: iq.j = game.state.kscmdr.j + 1 if not movescom(iq, avoid): iq.j = game.state.kscmdr.j - 1 movescom(iq, avoid) elif idelta.j != 0: iq.i = game.state.kscmdr.i + 1 if not movescom(iq, avoid): iq.i = game.state.kscmdr.i - 1 movescom(iq, avoid) else: # try moving just in x or y iq.j = game.state.kscmdr.j if not movescom(iq, avoid): iq.j = game.state.kscmdr.j + idelta.j iq.i = game.state.kscmdr.i movescom(iq, avoid) # check for a base if len(game.state.baseq) == 0: unschedule(FSCMOVE) else: for ibq in game.state.baseq: if ibq == game.state.kscmdr and game.state.kscmdr == game.battle: # attack the base if avoid: return # no, don't attack base! game.iseenit = False game.isatb = 1 schedule(FSCDBAS, randreal(1.0, 3.0)) if is_scheduled(FCDBAS): postpone(FSCDBAS, scheduled(FCDBAS)-game.state.date) if not communicating(): return # no warning game.iseenit = True announce() prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") \ % game.state.kscmdr) prout(_(" reports that it is under attack from the Klingon Super-commander.")) proutn(_(" It can survive until stardate %d.\"") \ % int(scheduled(FSCDBAS))) if not game.resting: return prout(_("Mr. Spock- \"Captain, shall we cancel the rest period?\"")) if not ja(): return game.resting = False game.optime = 0.0 # actually finished return # Check for intelligence report 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): return announce() prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports")) proutn(_(" the Super-commander is in Quadrant %s,") % game.state.kscmdr) return def movetholian(): "Move the Tholian." if not game.tholian or game.justin: return 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: tid.i = QUADSIZE-1 tid.j = QUADSIZE-1 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == QUADSIZE-1: tid.i = QUADSIZE-1 tid.j = 0 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.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[tid.i][tid.j] not in ('.', '#'): return here = copy.copy(game.tholian.location) delta = (tid - game.tholian.location).sgn() # move in x axis while here.i != tid.i: here.i += delta.i if game.quad[here.i][here.j] == '.': game.tholian.move(here) # move in y axis while here.j != tid.j: here.j += delta.j if game.quad[here.i][here.j] == '.': 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': return 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': return 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] = '#' dropin(' ') prout(crmena(True, 'T', "sector", game.tholian) + _(" completes web.")) game.tholian.move(None) return # Code from battle.c begins here def doshield(shraise): "Change shield status." action = "NONE" game.ididit = False if shraise: action = "SHUP" else: key = scanner.nexttok() if key == "IHALPHA": if scanner.sees("transfer"): action = "NRG" else: if damaged(DSHIELD): prout(_("Shields damaged and down.")) return if scanner.sees("up"): action = "SHUP" elif scanner.sees("down"): action = "SHDN" if action == "NONE": proutn(_("Do you wish to change shield energy? ")) 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(): action = "SHDN" else: scanner.chew() return else: proutn(_("Shields are down. Do you want them up? ")) if ja(): action = "SHUP" else: scanner.chew() return if action == "SHUP": # raise shields if game.shldup: prout(_("Shields already up.")) return game.shldup = True game.shldchg = True if game.condition != "docked": game.energy -= 50.0 prout(_("Shields raised.")) if game.energy <= 0: skip(1) prout(_("Shields raising uses up last of energy.")) finish(FNRG) return game.ididit = True return elif action == "SHDN": if not game.shldup: prout(_("Shields already down.")) return game.shldup = False game.shldchg = True prout(_("Shields lowered.")) game.ididit = True return elif action == "NRG": while scanner.nexttok() != "IHREAL": scanner.chew() proutn(_("Energy to transfer to shields- ")) nrg = scanner.real scanner.chew() if nrg == 0: return if nrg > game.energy: prout(_("Insufficient ship energy.")) return game.ididit = True if game.shield+nrg >= game.inshld: prout(_("Shield energy maximized.")) if game.shield+nrg > game.inshld: prout(_("Excess energy requested returned to ship energy")) game.energy -= game.inshld-game.shield game.shield = game.inshld return if nrg < 0.0 and game.energy-nrg > game.inenrg: # Prevent shield drain loophole skip(1) prout(_("Engineering to bridge--")) prout(_(" Scott here. Power circuit problem, Captain.")) prout(_(" I can't drain the shields.")) game.ididit = False return if game.shield+nrg < 0: prout(_("All shield energy transferred to ship.")) game.energy += game.shield game.shield = 0.0 return proutn(_("Scotty- \"")) if nrg > 0: prout(_("Transferring energy to shields.\"")) else: prout(_("Draining energy from shields.\"")) game.shield += nrg game.energy -= nrg return def randdevice(): "Choose a device to damage, at random." weights = ( 105, # DSRSENS: short range scanners 10.5% 105, # DLRSENS: long range scanners 10.5% 120, # DPHASER: phasers 12.0% 120, # DPHOTON: photon torpedoes 12.0% 25, # DLIFSUP: life support 2.5% 65, # DWARPEN: warp drive 6.5% 70, # DIMPULS: impulse engines 6.5% 145, # DSHIELD: deflector shields 14.5% 30, # DRADIO: subspace radio 3.0% 45, # DSHUTTL: shuttle 4.5% 15, # DCOMPTR: computer 1.5% 20, # NAVCOMP: navigation system 2.0% 75, # DTRANSP: transporter 7.5% 20, # DSHCTRL: high-speed shield controller 2.0% 10, # DDRAY: death ray 1.0% 30, # DDSP: deep-space probes 3.0% ) assert(sum(weights) == 1000) idx = randrange(1000) wsum = 0 for (i, w) in enumerate(weights): wsum += w if idx < wsum: return i return None # we should never get here def collision(rammed, enemy): "Collision handling for rammong events." prouts(_("***RED ALERT! RED ALERT!")) skip(1) prout(_("***COLLISION IMMINENT.")) skip(2) proutn("***") proutn(crmshp()) hardness = {'R':1.5, 'C':2.0, 'S':2.5, 'T':0.5, '?':4.0}.get(enemy.type, 1.0) if rammed: proutn(_(" rammed by ")) else: proutn(_(" rams ")) proutn(crmena(False, enemy.type, "sector", enemy.location)) if rammed: proutn(_(" (original position)")) skip(1) deadkl(enemy.location, enemy.type, game.sector) proutn("***" + crmshp() + " heavily damaged.") icas = randrange(10, 30) 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(int(NDEVICES/2)) while ncrits > 0: ncrits -= 1 dev = randdevice() if game.damage[dev] < 0: continue extradm = (10.0*hardness*randreal()+1.0)*game.damfac # Damage for at least time of travel! game.damage[dev] += game.optime + extradm game.shldup = False prout(_("***Shields are down.")) if game.state.remkl + len(game.state.kcmdr) + game.state.nscrem: announce() damagereport() else: finish(FWON) return def torpedo(origin, bearing, dispersion, number, nburst): "Let a photon torpedo fly" 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) # Loop to move a single torpedo setwnd(message_window) for step in range(1, QUADSIZE*2): if not track.nexttok(): break w = track.sector() if not w.valid_sector(): break iquad = game.quad[w.i][w.j] tracktorpedo(w, step, number, nburst, iquad) if iquad == '.': continue # hit something 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": 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.nexttok() bumpto = displacement.sector() if not bumpto.valid_sector(): return hit if game.quad[bumpto.i][bumpto.j] == ' ': finish(FHOLE) return hit 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 prout(_(" displaced by blast to Sector %s ") % bumpto) for enemy in game.enemies: enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance() sortenemies() return None elif iquad in ('C', 'S', 'R', 'K'): # Hit a regular enemy # find the enemy if iquad in ('C', 'S') and withprob(0.05): prout(crmena(True, iquad, "sector", w) + _(" uses anti-photon device;")) prout(_(" torpedo neutralized.")) return None for enemy in game.enemies: if w == enemy.location: kp = math.fabs(enemy.power) h1 = 700.0 + randrange(100) - \ 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle)) h1 = math.fabs(h1) if kp < h1: h1 = kp if enemy.power < 0: enemy.power -= -h1 else: enemy.power -= h1 if enemy.power == 0: deadkl(w, iquad, w) return None proutn(crmena(True, iquad, "sector", w)) displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5) displacement.nexttok() bumpto = displacement.sector() if not bumpto.valid_sector(): prout(_(" damaged but not destroyed.")) return if game.quad[bumpto.i][bumpto.j] == ' ': prout(_(" buffeted into black hole.")) deadkl(w, iquad, bumpto) if game.quad[bumpto.i][bumpto.j] != '.': prout(_(" damaged but not destroyed.")) else: prout(_(" damaged-- displaced by blast to Sector %s ")%bumpto) enemy.location = bumpto game.quad[w.i][w.j] = '.' game.quad[bumpto.i][bumpto.j] = iquad for enemy in game.enemies: enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance() sortenemies() break else: prout("Internal error, no enemy where expected!") raise SystemExit(1) return None elif iquad == 'B': # Hit a base skip(1) prout(_("***STARBASE DESTROYED..")) game.state.baseq = [x for x in game.state.baseq if x != game.quadrant] game.quad[w.i][w.j] = '.' game.base.invalidate() game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False game.state.chart[game.quadrant.i][game.quadrant.j].starbase = False game.state.basekl += 1 newcnd() return None elif iquad == 'P': # Hit a planet prout(crmena(True, iquad, "sector", w) + _(" destroyed.")) game.state.nplankl += 1 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None game.iplnet.pclass = "destroyed" game.iplnet = None game.plnet.invalidate() game.quad[w.i][w.j] = '.' if game.landed: # captain perishes on planet finish(FDPLANET) return None elif iquad == '@': # Hit an inhabited world -- very bad! prout(crmena(True, iquad, "sector", w) + _(" destroyed.")) game.state.nworldkl += 1 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None game.iplnet.pclass = "destroyed" game.iplnet = None game.plnet.invalidate() game.quad[w.i][w.j] = '.' if game.landed: # captain perishes on planet finish(FDPLANET) prout(_("The torpedo destroyed an inhabited planet.")) return None elif iquad == '*': # Hit a star if withprob(0.9): nova(w) else: prout(crmena(True, '*', "sector", w) + _(" unaffected by photon blast.")) return None elif iquad == '?': # Hit a thingy if not (game.options & OPTION_THINGY) or withprob(0.3): skip(1) prouts(_("AAAAIIIIEEEEEEEEAAAAAAAAUUUUUGGGGGHHHHHHHHHHHH!!!")) skip(1) prouts(_(" HACK! HACK! HACK! *CHOKE!* ")) skip(1) proutn(_("Mr. Spock-")) prouts(_(" \"Fascinating!\"")) skip(1) deadkl(w, iquad, w) else: # 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() return None elif iquad == ' ': # Black hole skip(1) prout(crmena(True, ' ', "sector", w) + _(" swallows torpedo.")) return None elif iquad == '#': # hit the web skip(1) prout(_("***Torpedo absorbed by Tholian web.")) return None elif iquad == 'T': # Hit a Tholian h1 = 700.0 + randrange(100) - \ 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] = '.' deadkl(w, iquad, w) game.tholian = None return None skip(1) proutn(crmena(True, 'T', "sector", w)) if withprob(0.05): prout(_(" survives photon blast.")) return None prout(_(" disappears.")) game.tholian.move(None) game.quad[w.i][w.j] = '#' dropin(' ') return None else: # Problem! skip(1) proutn("Don't know how to handle torpedo collision with ") proutn(crmena(True, iquad, "sector", w)) skip(1) return None break skip(1) setwnd(message_window) prout(_("Torpedo missed.")) return None def fry(hit): "Critical-hit resolution." if hit < (275.0-25.0*game.skill)*randreal(1.0, 1.5): return ncrit = int(1.0 + hit/(500.0+randreal(100))) proutn(_("***CRITICAL HIT--")) # Select devices and cause damage cdam = [] while ncrit > 0: 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")): break cdam.append(j) extradm = (hit*game.damfac)/(ncrit*randreal(75, 100)) game.damage[j] += extradm ncrit -= 1 skipcount = 0 for (i, j) in enumerate(cdam): proutn(device[j]) if skipcount % 3 == 2 and i < len(cdam)-1: skip(1) skipcount += 1 if i < len(cdam)-1: proutn(_(" and ")) prout(_(" damaged.")) if damaged(DSHIELD) and game.shldup: prout(_("***Shields knocked down.")) game.shldup = False def attack(torps_ok): # bad guy attacks us # torps_ok == False forces use of phasers in an attack # 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 where = "neither" if game.idebug: prout("=== ATTACK!") # Tholian gets to move before attacking if game.tholian: movetholian() # if you have just entered the RNZ, you'll get a warning if game.neutz: # The one chance not to be attacked 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: for (bugout, enemy, old, goto) in moveklings(): if bugout: # we know about this if either short or long range # sensors are working if damaged(DSRSENS) and damaged(DLRSENS) \ and game.condition != "docked": prout(crmena(True, enemy.type, "sector", old) + \ (_(" escapes to Quadrant %s (and regains strength).") % goto)) else: # Enemy still in-sector if enemy.move(goto): if not damaged(DSRSENS) or game.condition == "docked": proutn(_("*** %s from Sector %s") % (cramen(enemy.type), enemy.location)) if enemy.kdist < old: proutn(_(" advances to ")) else: proutn(_(" retreats to ")) prout("Sector %s." % goto) sortenemies() # if no enemies remain after movement, we're done if len(game.enemies) == 0 or (len(game.enemies) == 1 and thing.at(game.quadrant) and not thing.angered): return # set up partial hits if attack happens during shield status change pfac = 1.0/game.inshld if game.shldchg: chgfac = 0.25 + randreal(0.5) skip(1) # message verbosity control if game.skill <= SKILL_FAIR: where = "sector" for enemy in game.enemies: if enemy.power < 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 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.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) if usephasers: # Enemy uses phasers if game.condition == "docked": 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) enemy.power *= 0.75 else: # Enemy uses photon torpedo # We should be able to make the bearing() method work here 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): proutn(_(" From ") + crmena(False, enemy.type, where, enemy.location)) attempt = True prout(" ") dispersion = (randreal()+randreal())*0.5 - 0.5 dispersion += 0.002*enemy.power*dispersion hit = torpedo(enemy.location, pcourse, dispersion, number=1, nburst=1) if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0: finish(FWON) # Klingons did themselves in! if game.state.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": # shields will take hits propor = pfac * game.shield if game.condition == "docked": propor *= 2.1 if propor < 0.1: propor = 0.1 hitsh = propor*chgfac*hit+1.0 absorb = 0.8*hitsh if absorb > game.shield: absorb = game.shield game.shield -= absorb hit -= hitsh # taking a hit blasts us out of a starbase dock if game.condition == "docked": dock(False) # but the shields may take care of it if propor > 0.1 and hit < 0.005*game.energy: continue # hit from this opponent got through shields, so take damage ihurt = True proutn(_("%d unit hit") % int(hit)) if (damaged(DSRSENS) and usephasers) or game.skill<=SKILL_FAIR: proutn(_(" on the ") + crmshp()) if not damaged(DSRSENS) and usephasers: prout(_(" from ") + crmena(False, enemy.type, where, enemy.location)) skip(1) # Decide if hit is critical if hit > hitmax: hitmax = hit hittot += hit fry(hit) game.energy -= hit if game.energy <= 0: # Returning home upon your shield, not with it... finish(FBATTLE) return if not attempt and game.condition == "docked": prout(_("***Enemies decide against attacking your ship.")) percent = 100.0*pfac*game.shield+0.5 if not ihurt: # Shields fully protect ship proutn(_("Enemy attack reduces shield strength to ")) else: # Emit message if starship suffered hit(s) skip(1) proutn(_("Energy left %2d shields ") % int(game.energy)) if game.shldup: proutn(_("up ")) elif not damaged(DSHIELD): proutn(_("down ")) else: proutn(_("damaged, ")) prout(_("%d%%, torpedoes left %d") % (percent, game.torps)) # Check if anyone was hurt if hitmax >= 200 or hittot >= 500: icas = randrange(int(hittot * 0.015)) if icas >= 2: skip(1) prout(_("Mc Coy- \"Sickbay to bridge. We suffered %d casualties") % icas) prout(_(" in that last attack.\"")) game.casual += icas game.state.crew -= icas # After attack, reset average distance to enemies for enemy in game.enemies: enemy.kavgd = enemy.kdist sortenemies() return def deadkl(w, etype, mv): "Kill a Klingon, Tholian, Romulan, or Thingy." # Added mv to allow enemy to "move" before dying proutn(crmena(True, etype, "sector", mv)) # Decide what kind of enemy it is and update appropriately 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 etype == 'T': # Killed a Tholian game.tholian = None elif etype == '?': # Killed a Thingy global thing thing = None else: # Killed some type of Klingon game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1 game.klhere -= 1 if type == 'C': game.state.kcmdr.remove(game.quadrant) unschedule(FTBEAM) if game.state.kcmdr: schedule(FTBEAM, expran(1.0*game.incom/len(game.state.kcmdr))) if is_scheduled(FCDBAS) and game.battle == game.quadrant: unschedule(FCDBAS) elif type == 'K': game.state.remkl -= 1 elif type == 'S': game.state.nscrem -= 1 game.state.kscmdr.invalidate() game.isatb = 0 game.iscate = False unschedule(FSCMOVE) 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: return game.recompute() # Remove enemy ship from arrays describing local conditions for e in game.enemies: if e.location == w: e.move(None) break return def targetcheck(w): "Return None if target is invalid, otherwise return a course angle." if not w.valid_sector(): huh() return None 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")) prout(_(" the Captain's psychological profile.\"")) scanner.chew() return None return delta.bearing() def torps(): "Launch photon torpedo salvo." tcourse = [] game.ididit = False if damaged(DPHOTON): prout(_("Photon tubes damaged.")) scanner.chew() return if game.torps == 0: prout(_("No torpedoes left.")) scanner.chew() return # First, get torpedo count while True: scanner.nexttok() if scanner.token == "IHALPHA": huh() return elif scanner.token == "IHEOL" or not scanner.waiting(): prout(_("%d torpedoes left.") % game.torps) scanner.chew() proutn(_("Number of torpedoes to fire- ")) continue # Go back around to get a number else: # key == "IHREAL" n = scanner.int() if n <= 0: # abort command scanner.chew() return if n > MAXBURST: scanner.chew() prout(_("Maximum of %d torpedoes per burst.") % MAXBURST) return if n > game.torps: scanner.chew() # User requested more torps than available continue # Go back around break # All is good, go to next stage # Next, get targets target = [] for i in range(n): key = scanner.nexttok() if i == 0 and key == "IHEOL": break # no coordinate waiting, we will try prompting if i == 1 and key == "IHEOL": # direct all torpedoes at one target while i < n: target.append(target[0]) tcourse.append(tcourse[0]) i += 1 break scanner.push(scanner.token) target.append(scanner.getcoord()) if target[-1] == None: return tcourse.append(targetcheck(target[-1])) if tcourse[-1] == None: return scanner.chew() if len(target) == 0: # prompt for each one for i in range(n): proutn(_("Target sector for torpedo number %d- ") % (i+1)) scanner.chew() target.append(scanner.getcoord()) if target[-1] == None: return tcourse.append(targetcheck(target[-1])) if tcourse[-1] == None: return game.ididit = True # Loop for moving torpedoes for i in range(n): if game.condition != "docked": game.torps -= 1 dispersion = (randreal()+randreal())*0.5 -0.5 if math.fabs(dispersion) >= 0.47: # misfire! dispersion *= randreal(1.2, 2.2) if n > 0: prouts(_("***TORPEDO NUMBER %d MISFIRES") % (i+1)) else: prouts(_("***TORPEDO MISFIRES.")) skip(1) if i < n: prout(_(" Remainder of burst aborted.")) if withprob(0.2): prout(_("***Photon tubes damaged by misfire.")) game.damage[DPHOTON] = game.damfac * randreal(1.0, 3.0) break if game.shldup or game.condition == "docked": dispersion *= 1.0 + 0.0001*game.shield 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) def overheat(rpow): "Check for phasers overheating." if rpow > 1500: checkburn = (rpow-1500.0)*0.00038 if withprob(checkburn): prout(_("Weapons officer Sulu- \"Phasers overheated, sir.\"")) game.damage[DPHASER] = game.damfac* randreal(1.0, 2.0) * (1.0+checkburn) def checkshctrl(rpow): "Check shield control." skip(1) if withprob(0.998): prout(_("Shields lowered.")) return False # Something bad has happened prouts(_("***RED ALERT! RED ALERT!")) skip(2) hit = rpow*game.shield/game.inshld game.energy -= rpow+hit*0.8 game.shield -= hit*0.2 if game.energy <= 0.0: prouts(_("Sulu- \"Captain! Shield malf***********************\"")) skip(1) stars() finish(FPHASER) return True prouts(_("Sulu- \"Captain! Shield malfunction! Phaser fire contained!\"")) skip(2) prout(_("Lt. Uhura- \"Sir, all decks reporting damage.\"")) icas = randrange(int(hit*0.012)) skip(1) fry(0.8*hit) if icas: skip(1) prout(_("McCoy to bridge- \"Severe radiation burns, Jim.")) prout(_(" %d casualties so far.\"") % icas) game.casual += icas game.state.crew -= icas skip(1) prout(_("Phaser energy dispersed by shields.")) prout(_("Enemy unaffected.")) overheat(rpow) return True def hittem(hits): "Register a phaser hit on Klingons and Romulans." w = Coord() skip(1) 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) kpini = game.enemies[kk].power kp = math.fabs(kpini) if PHASEFAC*hit < kp: kp = PHASEFAC*hit if game.enemies[kk].power < 0: game.enemies[kk].power -= -kp else: game.enemies[kk].power -= kp kpow = game.enemies[kk].power w = game.enemies[kk].location if hit > 0.005: if not damaged(DSRSENS): boom(w) proutn(_("%d unit hit on ") % int(hit)) else: proutn(_("Very small hit on ")) ienm = game.quad[w.i][w.j] 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) 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: prout(_("***Mr. Spock- \"Captain, the vessel at Sector %s")%w) prout(_(" has just lost its firepower.\"")) game.enemies[kk].power = -kpow kk += 1 return 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 automode = "NOTSET" key = 0 skip(1) # SR sensors and Computer are needed for automode if damaged(DSRSENS) or damaged(DCOMPTR): itarg = False if game.condition == "docked": prout(_("Phasers can't be fired through base shields.")) scanner.chew() return if damaged(DPHASER): prout(_("Phaser control damaged.")) scanner.chew() return if game.shldup: if damaged(DSHCTRL): prout(_("High speed shield control damaged.")) scanner.chew() return if game.energy <= 200.0: prout(_("Insufficient energy to activate high-speed shield control.")) scanner.chew() return prout(_("Weapons Officer Sulu- \"High-speed shield control enabled, sir.\"")) 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.nexttok() if key == "IHALPHA": if scanner.sees("manual"): if len(game.enemies)==0: prout(_("There is no enemy present to select.")) scanner.chew() key = "IHEOL" automode = "AUTOMATIC" else: automode = "MANUAL" key = scanner.nexttok() elif scanner.sees("automatic"): if (not itarg) and len(game.enemies) != 0: automode = "FORCEMAN" else: if len(game.enemies)==0: prout(_("Energy will be expended into space.")) automode = "AUTOMATIC" key = scanner.nexttok() elif scanner.sees("no"): no = True else: huh() return elif key == "IHREAL": if len(game.enemies)==0: prout(_("Energy will be expended into space.")) automode = "AUTOMATIC" elif not itarg: automode = "FORCEMAN" else: automode = "AUTOMATIC" else: # "IHEOL" if len(game.enemies)==0: prout(_("Energy will be expended into space.")) automode = "AUTOMATIC" elif not itarg: automode = "FORCEMAN" else: proutn(_("Manual or automatic? ")) scanner.chew() avail = game.energy if ifast: avail -= 200.0 if automode == "AUTOMATIC": if key == "IHALPHA" and scanner.sees("no"): no = True key = scanner.nexttok() if key != "IHREAL" and len(game.enemies) != 0: prout(_("Phasers locked on target. Energy available: %.2f")%avail) 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 proutn(_("%d units required. ") % irec) scanner.chew() proutn(_("Units to fire= ")) key = scanner.nexttok() if key != "IHREAL": return rpow = scanner.real if rpow > avail: proutn(_("Energy available= %.2f") % avail) skip(1) key = "IHEOL" if not rpow > avail: break if rpow <= 0: # chicken out scanner.chew() return key = scanner.nexttok() if key == "IHALPHA" and scanner.sees("no"): no = True if ifast: game.energy -= 200 # Go and do it! if checkshctrl(rpow): return scanner.chew() game.energy -= rpow extra = rpow if len(game.enemies): extra = 0.0 powrem = rpow for i in range(len(game.enemies)): 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)) over = randreal(1.01, 1.06) * hits[i] temp = powrem powrem -= hits[i] + over if powrem <= 0 and temp < hits[i]: hits[i] = temp if powrem <= 0: over = 0.0 extra += over if powrem > 0.0: extra += powrem hittem(hits) game.ididit = True if extra > 0 and not game.alldone: if game.tholian: proutn(_("*** Tholian web absorbs ")) if len(game.enemies)>0: proutn(_("excess ")) prout(_("phaser energy.")) else: prout(_("%d expended on empty space.") % int(extra)) elif automode == "FORCEMAN": scanner.chew() key = "IHEOL" if damaged(DCOMPTR): prout(_("Battle computer damaged, manual fire only.")) else: skip(1) prouts(_("---WORKING---")) skip(1) prout(_("Short-range-sensors-damaged")) prout(_("Insufficient-data-for-automatic-phaser-fire")) prout(_("Manual-fire-must-be-used")) skip(1) elif automode == "MANUAL": rpow = 0.0 for k in range(len(game.enemies)): aim = game.enemies[k].location ienm = game.quad[aim.i][aim.j] if msgflag: proutn(_("Energy available= %.2f") % (avail-0.006)) skip(1) msgflag = False rpow = 0.0 if damaged(DSRSENS) and \ not game.sector.distance(aim)<2**0.5 and ienm in ('C', 'S'): prout(cramen(ienm) + _(" can't be located without short range scan.")) scanner.chew() key = "IHEOL" 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 kz = k proutn("(") if not damaged(DCOMPTR): proutn("%d" % irec) else: proutn("??") proutn(") ") proutn(_("units to fire at %s- ") % crmena(False, ienm, "sector", aim)) key = scanner.nexttok() if key == "IHALPHA" and scanner.sees("no"): no = True key = scanner.nexttok() continue if key == "IHALPHA": huh() return if key == "IHEOL": if k == 1: # Let me say I'm baffled by this msgflag = True continue if scanner.real < 0: # abort out scanner.chew() return hits[k] = scanner.real rpow += scanner.real # If total requested is too much, inform and start over if rpow > avail: prout(_("Available energy exceeded -- try again.")) scanner.chew() return key = scanner.nexttok() # scan for next value k += 1 if rpow == 0.0: # zero energy -- abort scanner.chew() return if key == "IHALPHA" and scanner.sees("no"): no = True game.energy -= rpow scanner.chew() if ifast: game.energy -= 200.0 if checkshctrl(rpow): return hittem(hits) game.ididit = True # Say shield raised or malfunction, if necessary if game.alldone: return if ifast: skip(1) if no == 0: if withprob(0.01): prout(_("Sulu- \"Sir, the high-speed shield control has malfunctioned . . .")) prouts(_(" CLICK CLICK POP . . .")) prout(_(" No response, sir!")) game.shldup = False else: prout(_("Shields raised.")) else: game.shldup = False overheat(rpow) # Code from events,c begins here. # This isn't a real event queue a la BSD Trek yet -- you can only have one # event of each type active at any given time. Mostly these means we can # only have one FDISTR/FENSLV/FREPRO sequence going at any given time # BSD Trek, from which we swiped the idea, can have up to 5. def unschedule(evtype): "Remove an event from the schedule." game.future[evtype].date = FOREVER return game.future[evtype] def is_scheduled(evtype): "Is an event of specified type scheduled." return game.future[evtype].date != FOREVER def scheduled(evtype): "When will this event happen?" return game.future[evtype].date def schedule(evtype, offset): "Schedule an event of specified type." game.future[evtype].date = game.state.date + offset return game.future[evtype] def postpone(evtype, offset): "Postpone a scheduled event." game.future[evtype].date += offset def cancelrest(): "Rest period is interrupted by event." if game.resting: skip(1) proutn(_("Mr. Spock- \"Captain, shall we cancel the rest period?\"")) if ja(): game.resting = False game.optime = 0.0 return True return False 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() def tractorbeam(yank): "Tractor-beaming cases merge here." announce() game.optime = (10.0/(7.5*7.5))*yank # 7.5 is yank rate (warp 7.5) skip(1) prout("***" + crmshp() + _(" caught in long range tractor beam--")) # If Kirk & Co. screwing around on planet, handle atover(True) # atover(true) is Grab if game.alldone: return if game.icraft: # Caught in Galileo? finish(FSTRACTOR) return # Check to see if shuttle is aboard if game.iscraft == "offship": skip(1) if withprob(0.5): prout(_("Galileo, left on the planet surface, is captured")) prout(_("by aliens and made into a flying McDonald's.")) game.damage[DSHUTTL] = -10 game.iscraft = "removed" else: prout(_("Galileo, left on the planet surface, is well hidden.")) if evcode == FSPY: game.quadrant = game.state.kscmdr else: game.quadrant = game.state.kcmdr[i] game.sector = randplace(QUADSIZE) prout(crmshp() + _(" is pulled to Quadrant %s, Sector %s") \ % (game.quadrant, game.sector)) if game.resting: prout(_("(Remainder of rest/repair period cancelled.)")) game.resting = False if not game.shldup: if not damaged(DSHIELD) and game.shield > 0: doshield(shraise=True) # raise shields game.shldchg = False else: prout(_("(Shields not currently useable.)")) newqad() # 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) else: schedule(FTBEAM, game.optime+expran(1.5*game.intime/len(game.state.kcmdr))) def destroybase(): "Code merges here for any commander destroying a starbase." # Not perfect, but will have to do # Handle case where base is in same quadrant as starship if game.battle == game.quadrant: game.state.chart[game.battle.i][game.battle.j].starbase = False game.quad[game.base.i][game.base.j] = '.' game.base.invalidate() newcnd() skip(1) prout(_("Spock- \"Captain, I believe the starbase has been destroyed.\"")) elif game.state.baseq and communicating(): # Get word via subspace radio announce() skip(1) prout(_("Lt. Uhura- \"Captain, Starfleet Command reports that")) proutn(_(" the starbase in Quadrant %s has been destroyed by") % game.battle) if game.isatb == 2: prout(_("the Klingon Super-Commander")) else: prout(_("a Klingon Commander")) game.state.chart[game.battle.i][game.battle.j].starbase = False # Remove Starbase from galaxy game.state.galaxy[game.battle.i][game.battle.j].starbase = False game.state.baseq = [x for x in game.state.baseq if x != game.battle] if game.isatb == 2: # reinstate a commander's base attack game.battle = hold game.isatb = 0 else: game.battle.invalidate() if game.idebug: prout("=== EVENTS from %.2f to %.2f:" % (game.state.date, fintim)) for i in range(1, NEVENTS): if i == FSNOVA: proutn("=== Supernova ") elif i == FTBEAM: proutn("=== T Beam ") elif i == FSNAP: proutn("=== Snapshot ") elif i == FBATTAK: proutn("=== Base Attack ") elif i == FCDBAS: proutn("=== Base Destroy ") elif i == FSCMOVE: proutn("=== SC Move ") elif i == FSCDBAS: proutn("=== SC Base Destroy ") elif i == FDSPROB: proutn("=== Probe Move ") elif i == FDISTR: proutn("=== Distress Call ") elif i == FENSLV: proutn("=== Enslavement ") elif i == FREPRO: proutn("=== Klingon Build ") if is_scheduled(i): prout("%.2f" % (scheduled(i))) else: prout("never") radio_was_broken = damaged(DRADIO) hold.i = hold.j = 0 while True: # Select earliest extraneous event, evcode==0 if no events evcode = FSPY if game.alldone: return datemin = fintim for l in range(1, NEVENTS): if game.future[l].date < datemin: evcode = l if game.idebug: prout("== Event %d fires" % evcode) datemin = game.future[l].date xtime = datemin-game.state.date game.state.date = datemin # 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: finish(FDEPLETE) return # Any crew left alive? if game.state.crew <= 0: finish(FCREW) return # Is life support adequate? if damaged(DLIFSUP) and game.condition != "docked": if game.lsupres < xtime and game.damage[DLIFSUP] > game.lsupres: finish(FLIFESUP) return game.lsupres -= xtime if game.damage[DLIFSUP] <= xtime: game.lsupres = game.inlsr # Fix devices repair = xtime if game.condition == "docked": repair /= DOCKFAC # Don't fix Deathray here for l in range(NDEVICES): if game.damage[l] > 0.0 and l != DDRAY: if game.damage[l]-repair > 0.0: game.damage[l] -= repair else: game.damage[l] = 0.0 # If radio repaired, update star chart and attack reports if radio_was_broken and not damaged(DRADIO): prout(_("Lt. Uhura- \"Captain, the sub-space radio is working and")) prout(_(" surveillance reports are coming in.")) skip(1) if not game.iseenit: attackreport(False) game.iseenit = True rechart() prout(_(" The star chart is now up to date.\"")) skip(1) # Cause extraneous event EVCODE to occur game.optime -= xtime if evcode == FSNOVA: # Supernova announce() supernova(None) schedule(FSNOVA, expran(0.5*game.intime)) if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova: return 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: return if game.ientesc or \ (game.energy<2000 and game.torps<4 and game.shield < 1250) or \ (damaged(DPHASER) and (damaged(DPHOTON) or game.torps<4)) or \ (damaged(DSHIELD) and \ (game.energy < 2500 or damaged(DPHASER)) and \ (game.torps < 5 or damaged(DPHOTON))): # Tractor-beam her! istract = ictbeam = True tractorbeam((game.state.kscmdr-game.quadrant).distance()) else: return elif evcode == FTBEAM: # Tractor beam if not game.state.kcmdr: unschedule(FTBEAM) continue i = randrange(len(game.state.kcmdr)) yank = (game.state.kcmdr[i]-game.quadrant).distance() if istract or game.condition == "docked" or yank == 0: # Drats! Have to reschedule schedule(FTBEAM, game.optime + expran(1.5*game.intime/len(game.state.kcmdr))) continue ictbeam = True tractorbeam(yank) elif evcode == FSNAP: # Snapshot of the universe (for time warp) game.snapsht = copy.deepcopy(game.state) game.state.snap = True schedule(FSNAP, expran(0.5 * game.intime)) elif evcode == FBATTAK: # Commander attacks starbase if not game.state.kcmdr or not game.state.baseq: # no can do unschedule(FBATTAK) unschedule(FCDBAS) continue try: for ibq in game.state.baseq: for cmdr in game.state.kcmdr: if ibq == cmdr and ibq != game.quadrant and ibq != game.state.kscmdr: raise JumpOut else: # no match found -- try later schedule(FBATTAK, expran(0.3*game.intime)) unschedule(FCDBAS) continue except JumpOut: pass # commander + starbase combination found -- launch attack game.battle = ibq schedule(FCDBAS, randreal(1.0, 4.0)) if game.isatb: # extra time if SC already attacking postpone(FCDBAS, scheduled(FSCDBAS)-game.state.date) game.future[FBATTAK].date = game.future[FCDBAS].date + expran(0.3*game.intime) game.iseenit = False if not communicating(): continue # No warning :-( game.iseenit = True announce() skip(1) prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") % game.battle) prout(_(" reports that it is under attack and that it can")) prout(_(" hold out only until stardate %d.\"") % (int(scheduled(FCDBAS)))) if cancelrest(): return elif evcode == FSCDBAS: # Supercommander destroys base unschedule(FSCDBAS) game.isatb = 2 if not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].starbase: continue # WAS RETURN! hold = game.battle game.battle = game.state.kscmdr destroybase() elif evcode == FCDBAS: # Commander succeeds in destroying base if evcode == FCDBAS: unschedule(FCDBAS) if not game.state.baseq() \ or not game.state.galaxy[game.battle.i][game.battle.j].starbase: game.battle.invalidate() continue # find the lucky pair for cmdr in game.state.kcmdr: if cmdr == game.battle: break else: # No action to take after all continue destroybase() elif evcode == FSCMOVE: # Supercommander moves schedule(FSCMOVE, 0.2777) if not game.ientesc and not istract and game.isatb != 1 and \ (not game.iscate or not game.justin): supercommander() elif evcode == FDSPROB: # Move deep space probe schedule(FDSPROB, 0.01) if not game.probe.nexttok(): if not game.probe.quadrant().valid_quadrant() or \ game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j].supernova: # Left galaxy or ran into supernova if communicating(): announce() skip(1) proutn(_("Lt. Uhura- \"The deep space probe ")) if not game.probe.quadrant().valid_quadrant(): prout(_("has left the galaxy.\"")) else: prout(_("is no longer transmitting.\"")) unschedule(FDSPROB) continue if communicating(): #announce() skip(1) prout(_("Lt. Uhura- \"The deep space probe is now in Quadrant %s.\"") % game.probe.quadrant()) pquad = game.probe.quadrant() pdest = game.state.galaxy[pquad.i][pquad.j] if communicating(): game.state.chart[pquad.i][pquad.j].klingons = pdest.klingons game.state.chart[pquad.i][pquad.j].starbase = pdest.starbase game.state.chart[pquad.i][pquad.j].stars = pdest.stars pdest.charted = True game.probe.moves -= 1 # One less to travel if game.probe.arrived() and game.isarmed and pdest.stars: supernova(game.probe.quadrant()) # fire in the hole! unschedule(FDSPROB) if game.state.galaxy[pquad.i][pquad.j].supernova: return elif evcode == FDISTR: # inhabited system issues distress call unschedule(FDISTR) # try a whole bunch of times to find something suitable for i in range(100): # need a quadrant which is not the current one, # which has some stars which are inhabited and # not already under attack, which is not # supernova'ed, and which has some Klingons in it w = randplace(GALSIZE) q = game.state.galaxy[w.i][w.j] if not (game.quadrant == w or q.planet == None or \ not q.planet.inhabited or \ q.supernova or q.status!="secure" or q.klingons<=0): break else: # can't seem to find one; ignore this call if game.idebug: prout("=== Couldn't find location for distress event.") continue # got one!! Schedule its enslavement ev = schedule(FENSLV, expran(game.intime)) ev.quadrant = w q.status = "distressed" # tell the captain about it if we can if communicating(): prout(_("Uhura- Captain, %s in Quadrant %s reports it is under attack") \ % (q.planet, repr(w))) prout(_("by a Klingon invasion fleet.")) if cancelrest(): return elif evcode == FENSLV: # starsystem is enslaved ev = unschedule(FENSLV) # see if current distress call still active q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j] if q.klingons <= 0: q.status = "secure" continue q.status = "enslaved" # play stork and schedule the first baby ev2 = schedule(FREPRO, expran(2.0 * game.intime)) ev2.quadrant = ev.quadrant # report the disaster if we can if communicating(): prout(_("Uhura- We've lost contact with starsystem %s") % \ q.planet) prout(_("in Quadrant %s.\n") % ev.quadrant) elif evcode == FREPRO: # Klingon reproduces # If we ever switch to a real event queue, we'll need to # explicitly retrieve and restore the x and y. ev = schedule(FREPRO, expran(1.0 * game.intime)) # see if current distress call still active q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j] if q.klingons <= 0: q.status = "secure" continue if game.state.remkl >= MAXKLGAME: continue # full right now # reproduce one Klingon w = ev.quadrant m = Coord() if game.klhere >= MAXKLQUAD: try: # this quadrant not ok, pick an adjacent one for m.i in range(w.i - 1, w.i + 2): for m.j in range(w.j - 1, w.j + 2): if not m.valid_quadrant(): continue q = game.state.galaxy[m.i][m.j] # check for this quad ok (not full & no snova) if q.klingons >= MAXKLQUAD or q.supernova: continue raise JumpOut else: continue # search for eligible quadrant failed except JumpOut: w = m # deliver the child game.state.remkl += 1 q.klingons += 1 if game.quadrant == w: game.klhere += 1 game.enemies.append(newkling()) # recompute time left game.recompute() if communicating(): if game.quadrant == w: prout(_("Spock- sensors indicate the Klingons have")) prout(_("launched a warship from %s.") % q.planet) else: prout(_("Uhura- Starfleet reports increased Klingon activity")) if q.planet != None: proutn(_("near %s ") % q.planet) prout(_("in Quadrant %s.") % w) def wait(): "Wait on events." game.ididit = False while True: key = scanner.nexttok() if key != "IHEOL": break proutn(_("How long? ")) scanner.chew() if key != "IHREAL": huh() return origTime = delay = scanner.real if delay <= 0.0: return if delay >= game.state.remtime or len(game.enemies) != 0: proutn(_("Are you sure? ")) if not ja(): return # Alternate resting periods (events) with attacks game.resting = True while True: if delay <= 0: game.resting = False if not game.resting: prout(_("%d stardates left.") % int(game.state.remtime)) return temp = game.optime = delay if len(game.enemies): rtime = randreal(1.0, 2.0) if rtime < temp: temp = rtime game.optime = temp if game.optime < delay: attack(torps_ok=False) if game.alldone: return events() game.ididit = True if game.alldone: return delay -= temp # Repair Deathray if long rest at starbase if origTime-delay >= 9.99 and game.condition == "docked": game.damage[DDRAY] = 0.0 # leave if quadrant supernovas if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova: break game.resting = False game.optime = 0 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) if withprob(0.05): # Wow! We've supernova'ed supernova(game.quadrant) return # handle initial nova game.quad[nov.i][nov.j] = '.' prout(crmena(False, '*', "sector", nov) + _(" novas.")) game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1 game.state.starkl += 1 # Set up queue to recursively trigger adjacent stars hits = [nov] kount = 0 while hits: 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: continue neighbor = start + offset if not neighbor.valid_sector(): continue iquad = game.quad[neighbor.i][neighbor.j] # Empty space ends reaction if iquad in ('.', '?', ' ', 'T', '#'): pass elif iquad == '*': # Affect another star if withprob(0.05): # This star supernovas supernova(game.quadrant) return else: hits.append(neighbor) game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1 game.state.starkl += 1 proutn(crmena(True, '*', "sector", neighbor)) prout(_(" novas.")) game.quad[neighbor.i][neighbor.j] = '.' kount += 1 elif iquad in ('P', '@'): # Destroy planet game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None if iquad == 'P': game.state.nplankl += 1 else: game.state.nworldkl += 1 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed.")) game.iplnet.pclass = "destroyed" game.iplnet = None game.plnet.invalidate() if game.landed: finish(FPNOVA) return game.quad[neighbor.i][neighbor.j] = '.' elif iquad == 'B': # Destroy base game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False game.state.baseq = [x for x in game.state.baseq if x!= game.quadrant] game.base.invalidate() game.state.basekl += 1 newcnd() prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed.")) game.quad[neighbor.i][neighbor.j] = '.' elif iquad in ('E', 'F'): # Buffet ship prout(_("***Starship buffeted by nova.")) if game.shldup: if game.shield >= 2000.0: game.shield -= 2000.0 else: diff = 2000.0 - game.shield game.energy -= diff game.shield = 0.0 game.shldup = False prout(_("***Shields knocked out.")) game.damage[DSHIELD] += 0.005*game.damfac*randreal()*diff else: game.energy -= 2000.0 if game.energy <= 0: finish(FNOVA) return # add in course nova contributes to kicking starship 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 for ll in range(len(game.enemies)): if game.enemies[ll].location == neighbor: break game.enemies[ll].power -= 800.0 # If firepower is lost, die if game.enemies[ll].power <= 0.0: deadkl(neighbor, iquad, neighbor) break newc = neighbor + neighbor - hits[-1] proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged")) if not newc.valid_sector(): # can't leave quadrant skip(1) break iquad1 = game.quad[newc.i][newc.j] if iquad1 == ' ': proutn(_(", blasted into ") + crmena(False, ' ', "sector", newc)) skip(1) deadkl(neighbor, iquad, newc) break if iquad1 != '.': # can't move into something else skip(1) break proutn(_(", buffeted to Sector %s") % newc) game.quad[neighbor.i][neighbor.j] = '.' game.quad[newc.i][newc.j] = iquad game.enemies[ll].move(newc) # Starship affected by nova -- kick it away. dist = kount*0.1 direc = ncourse[3*(bump.i+1)+bump.j+2] if direc == 0.0: dist = 0.0 if dist == 0.0: return scourse = course(bearing=direc, distance=dist) game.optime = scourse.time(warp=4) skip(1) prout(_("Force of nova displaces starship.")) imove(scourse, noattack=True) game.optime = scourse.time(warp=4) return def supernova(w): "Star goes supernova." num = 0; npdead = 0 if w != None: nq = copy.copy(w) else: # Scheduled supernova -- select star at random. stars = 0 nq = Coord() for nq.i in range(GALSIZE): for nq.j in range(GALSIZE): stars += game.state.galaxy[nq.i][nq.j].stars if stars == 0: return # nothing to supernova exists num = randrange(stars) + 1 for nq.i in range(GALSIZE): for nq.j in range(GALSIZE): num -= game.state.galaxy[nq.i][nq.j].stars if num <= 0: break if num <=0: break if game.idebug: proutn("=== Super nova here?") if ja(): nq = game.quadrant if not nq == game.quadrant or game.justin: # it isn't here, or we just entered (treat as enroute) if communicating(): skip(1) prout(_("Message from Starfleet Command Stardate %.2f") % game.state.date) prout(_(" Supernova in Quadrant %s; caution advised.") % nq) else: ns = Coord() # we are in the quadrant! num = randrange(game.state.galaxy[nq.i][nq.j].stars) + 1 for ns.i in range(QUADSIZE): for ns.j in range(QUADSIZE): if game.quad[ns.i][ns.j]=='*': num -= 1 if num==0: break if num==0: break skip(1) prouts(_("***RED ALERT! RED ALERT!")) skip(1) prout(_("***Incipient supernova detected at Sector %s") % ns) if (ns.i-game.sector.i)**2 + (ns.j-game.sector.j)**2 <= 2.1: proutn(_("Emergency override attempts t")) prouts("***************") skip(1) stars() game.alldone = True # destroy any Klingons in supernovaed quadrant kldead = game.state.galaxy[nq.i][nq.j].klingons game.state.galaxy[nq.i][nq.j].klingons = 0 if nq == game.state.kscmdr: # did in the Supercommander! game.state.nscrem = game.state.kscmdr.i = game.state.kscmdr.j = game.isatb = 0 game.iscate = False unschedule(FSCMOVE) unschedule(FSCDBAS) survivors = filter(lambda w: w != nq, game.state.kcmdr) comkills = len(game.state.kcmdr) - len(survivors) game.state.kcmdr = survivors kldead -= comkills if not game.state.kcmdr: unschedule(FTBEAM) game.state.remkl -= kldead # destroy Romulans and planets in supernovaed quadrant nrmdead = game.state.galaxy[nq.i][nq.j].romulans game.state.galaxy[nq.i][nq.j].romulans = 0 game.state.nromrem -= nrmdead # Destroy planets for loop in range(game.inplan): if game.state.planets[loop].quadrant == nq: game.state.planets[loop].pclass = "destroyed" npdead += 1 # Destroy any base in supernovaed quadrant game.state.baseq = [x for x in game.state.baseq if x != nq] # If starship caused supernova, tally up destruction if w != None: game.state.starkl += game.state.galaxy[nq.i][nq.j].stars game.state.basekl += game.state.galaxy[nq.i][nq.j].starbase game.state.nplankl += npdead # mark supernova in galaxy and in star chart if game.quadrant == nq or communicating(): game.state.galaxy[nq.i][nq.j].supernova = True # If supernova destroys last Klingons give special message if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0 and not nq == game.quadrant: skip(2) if w == None: prout(_("Lucky you!")) proutn(_("A supernova in %s has just destroyed the last Klingons.") % nq) finish(FWON) return # if some Klingons remain, continue or die in supernova if game.alldone: finish(FSNOVAED) return # Code from finish.c ends here. def selfdestruct(): "Self-destruct maneuver. Finish with a BANG!" scanner.chew() if damaged(DCOMPTR): prout(_("Computer damaged; cannot execute destruct sequence.")) return prouts(_("---WORKING---")); skip(1) prouts(_("SELF-DESTRUCT-SEQUENCE-ACTIVATED")); skip(1) prouts(" 10"); skip(1) prouts(" 9"); skip(1) prouts(" 8"); skip(1) prouts(" 7"); skip(1) prouts(" 6"); skip(1) skip(1) prout(_("ENTER-CORRECT-PASSWORD-TO-CONTINUE-")) skip(1) prout(_("SELF-DESTRUCT-SEQUENCE-OTHERWISE-")) skip(1) prout(_("SELF-DESTRUCT-SEQUENCE-WILL-BE-ABORTED")) skip(1) scanner.nexttok() if game.passwd != scanner.token: prouts(_("PASSWORD-REJECTED;")) skip(1) prouts(_("CONTINUITY-EFFECTED")) skip(2) return prouts(_("PASSWORD-ACCEPTED")); skip(1) prouts(" 5"); skip(1) prouts(" 4"); skip(1) prouts(" 3"); skip(1) prouts(" 2"); skip(1) prouts(" 1"); skip(1) if withprob(0.15): prouts(_("GOODBYE-CRUEL-WORLD")) skip(1) kaboom() def kaboom(): stars() if game.ship=='E': prouts("***") prouts(_("********* Entropy of %s maximized *********") % crmshp()) skip(1) stars() skip(1) if len(game.enemies) != 0: whammo = 25.0 * game.energy 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) finish(FDILITHIUM) def killrate(): "Compute our rate of kils over time." elapsed = game.state.date - game.indate if elapsed == 0: # Avoid divide-by-zero error if calculated on turn 0 return 0 else: starting = (game.inkling + game.incom + game.inscom) remaining = (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) return (starting - remaining)/elapsed def badpoints(): "Compute demerits." badpt = 5.0*game.state.starkl + \ game.casual + \ 10.0*game.state.nplankl + \ 300*game.state.nworldkl + \ 45.0*game.nhelp +\ 100.0*game.state.basekl +\ 3.0*game.abandoned if game.ship == 'F': badpt += 100.0 elif game.ship == None: badpt += 200.0 return badpt def finish(ifin): # end the game, with appropriate notfications igotit = False game.alldone = True skip(3) prout(_("It is stardate %.1f.") % game.state.date) skip(1) if ifin == FWON: # Game has been won if game.state.nromrem != 0: prout(_("The remaining %d Romulans surrender to Starfleet Command.") % game.state.nromrem) prout(_("You have smashed the Klingon invasion fleet and saved")) prout(_("the Federation.")) game.gamewon = True if game.alive: badpt = badpoints() if badpt < 100.0: badpt = 0.0 # Close enough! # killsPerDate >= RateMax if game.state.date-game.indate < 5.0 or \ killrate() >= 0.1*game.skill*(game.skill+1.0) + 0.1 + 0.008*badpt: skip(1) prout(_("In fact, you have done so well that Starfleet Command")) if game.skill == SKILL_NOVICE: prout(_("promotes you one step in rank from \"Novice\" to \"Fair\".")) elif game.skill == SKILL_FAIR: prout(_("promotes you one step in rank from \"Fair\" to \"Good\".")) elif game.skill == SKILL_GOOD: prout(_("promotes you one step in rank from \"Good\" to \"Expert\".")) elif game.skill == SKILL_EXPERT: prout(_("promotes you to Commodore Emeritus.")) skip(1) prout(_("Now that you think you're really good, try playing")) prout(_("the \"Emeritus\" game. It will splatter your ego.")) elif game.skill == SKILL_EMERITUS: skip(1) proutn(_("Computer- ")) prouts(_("ERROR-ERROR-ERROR-ERROR")) skip(2) prouts(_(" YOUR-SKILL-HAS-EXCEEDED-THE-CAPACITY-OF-THIS-PROGRAM")) skip(1) prouts(_(" THIS-PROGRAM-MUST-SURVIVE")) skip(1) prouts(_(" THIS-PROGRAM-MUST-SURVIVE")) skip(1) prouts(_(" THIS-PROGRAM-MUST-SURVIVE")) skip(1) prouts(_(" THIS-PROGRAM-MUST?- MUST ? - SUR? ? -? VI")) skip(2) prout(_("Now you can retire and write your own Star Trek game!")) skip(1) elif game.skill >= SKILL_EXPERT: 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(): igotit = True # Only grant long life if alive (original didn't!) skip(1) prout(_("LIVE LONG AND PROSPER.")) score() if igotit: plaque() return elif ifin == FDEPLETE: # Federation Resources Depleted prout(_("Your time has run out and the Federation has been")) prout(_("conquered. Your starship is now Klingon property,")) prout(_("and you are put on trial as a war criminal. On the")) proutn(_("basis of your record, you are ")) if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)*3.0 > (game.inkling + game.incom + game.inscom): prout(_("acquitted.")) skip(1) prout(_("LIVE LONG AND PROSPER.")) else: prout(_("found guilty and")) prout(_("sentenced to death by slow torture.")) game.alive = False score() return elif ifin == FLIFESUP: prout(_("Your life support reserves have run out, and")) prout(_("you die of thirst, starvation, and asphyxiation.")) prout(_("Your starship is a derelict in space.")) elif ifin == FNRG: prout(_("Your energy supply is exhausted.")) skip(1) prout(_("Your starship is a derelict in space.")) elif ifin == FBATTLE: prout(_("The %s has been destroyed in battle.") % crmshp()) skip(1) prout(_("Dulce et decorum est pro patria mori.")) elif ifin == FNEG3: prout(_("You have made three attempts to cross the negative energy")) prout(_("barrier which surrounds the galaxy.")) skip(1) prout(_("Your navigation is abominable.")) score() elif ifin == FNOVA: prout(_("Your starship has been destroyed by a nova.")) prout(_("That was a great shot.")) skip(1) elif ifin == FSNOVAED: prout(_("The %s has been fried by a supernova.") % crmshp()) prout(_("...Not even cinders remain...")) elif ifin == FABANDN: prout(_("You have been captured by the Klingons. If you still")) prout(_("had a starbase to be returned to, you would have been")) prout(_("repatriated and given another chance. Since you have")) prout(_("no starbases, you will be mercilessly tortured to death.")) elif ifin == FDILITHIUM: prout(_("Your starship is now an expanding cloud of subatomic particles")) elif ifin == FMATERIALIZE: prout(_("Starbase was unable to re-materialize your starship.")) prout(_("Sic transit gloria mundi")) elif ifin == FPHASER: prout(_("The %s has been cremated by its own phasers.") % crmshp()) elif ifin == FLOST: prout(_("You and your landing party have been")) prout(_("converted to energy, disipating through space.")) elif ifin == FMINING: prout(_("You are left with your landing party on")) prout(_("a wild jungle planet inhabited by primitive cannibals.")) skip(1) prout(_("They are very fond of \"Captain Kirk\" soup.")) skip(1) prout(_("Without your leadership, the %s is destroyed.") % crmshp()) elif ifin == FDPLANET: prout(_("You and your mining party perish.")) skip(1) prout(_("That was a great shot.")) skip(1) elif ifin == FSSC: prout(_("The Galileo is instantly annihilated by the supernova.")) prout(_("You and your mining party are atomized.")) skip(1) prout(_("Mr. Spock takes command of the %s and") % crmshp()) prout(_("joins the Romulans, wreaking terror on the Federation.")) elif ifin == FPNOVA: prout(_("You and your mining party are atomized.")) skip(1) prout(_("Mr. Spock takes command of the %s and") % crmshp()) prout(_("joins the Romulans, wreaking terror on the Federation.")) elif ifin == FSTRACTOR: prout(_("The shuttle craft Galileo is also caught,")) prout(_("and breaks up under the strain.")) skip(1) prout(_("Your debris is scattered for millions of miles.")) prout(_("Without your leadership, the %s is destroyed.") % crmshp()) elif ifin == FDRAY: prout(_("The mutants attack and kill Spock.")) prout(_("Your ship is captured by Klingons, and")) prout(_("your crew is put on display in a Klingon zoo.")) elif ifin == FTRIBBLE: prout(_("Tribbles consume all remaining water,")) prout(_("food, and oxygen on your ship.")) skip(1) prout(_("You die of thirst, starvation, and asphyxiation.")) prout(_("Your starship is a derelict in space.")) elif ifin == FHOLE: prout(_("Your ship is drawn to the center of the black hole.")) prout(_("You are crushed into extremely dense matter.")) elif ifin == FCREW: prout(_("Your last crew member has died.")) if game.ship == 'F': game.ship = None elif game.ship == 'E': game.ship = 'F' game.alive = False if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0: goodies = game.state.remres/game.inresor baddies = (game.state.remkl + 2.0*len(game.state.kcmdr))/(game.inkling+2.0*game.incom) if goodies/baddies >= randreal(1.0, 1.5): prout(_("As a result of your actions, a treaty with the Klingon")) prout(_("Empire has been signed. The terms of the treaty are")) if goodies/baddies >= randreal(3.0): prout(_("favorable to the Federation.")) skip(1) prout(_("Congratulations!")) else: prout(_("highly unfavorable to the Federation.")) else: prout(_("The Federation will be destroyed.")) else: prout(_("Since you took the last Klingon with you, you are a")) prout(_("martyr and a hero. Someday maybe they'll erect a")) prout(_("statue in your memory. Rest in peace, and try not")) prout(_("to think about pigeons.")) game.gamewon = True score() def score(): "Compute player's score." timused = game.state.date - game.indate if (timused == 0 or (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0) and timused < 5.0: timused = 5.0 game.perdate = killrate() ithperd = 500*game.perdate + 0.5 iwon = 0 if game.gamewon: iwon = 100*game.skill if game.ship == 'E': klship = 0 elif game.ship == 'F': klship = 1 else: klship = 2 game.score = 10*(game.inkling - game.state.remkl) \ + 50*(game.incom - len(game.state.kcmdr)) \ + ithperd + iwon \ + 20*(game.inrom - game.state.nromrem) \ + 200*(game.inscom - game.state.nscrem) \ - game.state.nromrem \ - badpoints() if not game.alive: game.score -= 200 skip(2) prout(_("Your score --")) if game.inrom - game.state.nromrem: prout(_("%6d Romulans destroyed %5d") % (game.inrom - game.state.nromrem, 20*(game.inrom - game.state.nromrem))) if game.state.nromrem and game.gamewon: prout(_("%6d Romulans captured %5d") % (game.state.nromrem, game.state.nromrem)) if game.inkling - game.state.remkl: prout(_("%6d ordinary Klingons destroyed %5d") % (game.inkling - game.state.remkl, 10*(game.inkling - game.state.remkl))) if game.incom - len(game.state.kcmdr): prout(_("%6d Klingon commanders destroyed %5d") % (game.incom - len(game.state.kcmdr), 50*(game.incom - len(game.state.kcmdr)))) if game.inscom - game.state.nscrem: prout(_("%6d Super-Commander destroyed %5d") % (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem))) if ithperd: prout(_("%6.2f Klingons per stardate %5d") % (game.perdate, ithperd)) if game.state.starkl: prout(_("%6d stars destroyed by your action %5d") % (game.state.starkl, -5*game.state.starkl)) if game.state.nplankl: prout(_("%6d planets destroyed by your action %5d") % (game.state.nplankl, -10*game.state.nplankl)) if (game.options & OPTION_WORLDS) and game.state.nworldkl: prout(_("%6d inhabited planets destroyed by your action %5d") % (game.state.nworldkl, -300*game.state.nworldkl)) if game.state.basekl: prout(_("%6d bases destroyed by your action %5d") % (game.state.basekl, -100*game.state.basekl)) if game.nhelp: prout(_("%6d calls for help from starbase %5d") % (game.nhelp, -45*game.nhelp)) if game.casual: prout(_("%6d casualties incurred %5d") % (game.casual, -game.casual)) if game.abandoned: prout(_("%6d crew abandoned in space %5d") % (game.abandoned, -3*game.abandoned)) if klship: prout(_("%6d ship(s) lost or destroyed %5d") % (klship, -100*klship)) if not game.alive: prout(_("Penalty for getting yourself killed -200")) if game.gamewon: proutn(_("Bonus for winning ")) if game.skill == SKILL_NOVICE: proutn(_("Novice game ")) elif game.skill == SKILL_FAIR: proutn(_("Fair game ")) elif game.skill == SKILL_GOOD: proutn(_("Good game ")) elif game.skill == SKILL_EXPERT: proutn(_("Expert game ")) elif game.skill == SKILL_EMERITUS: proutn(_("Emeritus game")) prout(" %5d" % iwon) skip(1) prout(_("TOTAL SCORE %5d") % game.score) def plaque(): "Emit winner's commemmorative plaque." skip(2) while True: proutn(_("File or device name for your plaque: ")) winner = cgetline() try: fp = open(winner, "w") break except IOError: prout(_("Invalid name.")) proutn(_("Enter name to go on plaque (up to 30 characters): ")) winner = cgetline() # The 38 below must be 64 for 132-column paper nskip = 38 - len(winner)/2 fp.write("\n\n\n\n") # --------DRAW ENTERPRISE PICTURE. fp.write(" EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n" ) fp.write(" EEE E : : : E\n" ) fp.write(" EE EEE E : : NCC-1701 : E\n") fp.write("EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEE : : : E\n") fp.write(" E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n") fp.write(" EEEEEEEEE EEEEEEEEEEEEE E E\n") fp.write(" EEEEEEE EEEEE E E E E\n") fp.write(" EEE E E E E\n") fp.write(" E E E E\n") fp.write(" EEEEEEEEEEEEE E E\n") fp.write(" EEE : EEEEEEE EEEEEEEE\n") fp.write(" :E : EEEE E\n") fp.write(" .-E -:----- E\n") fp.write(" :E : E\n") fp.write(" EE : EEEEEEEE\n") fp.write(" EEEEEEEEEEEEEEEEEEEEEEE\n") fp.write("\n\n\n") fp.write(_(" U. S. S. ENTERPRISE\n")) fp.write("\n\n\n\n") fp.write(_(" For demonstrating outstanding ability as a starship captain\n")) fp.write("\n") fp.write(_(" Starfleet Command bestows to you\n")) fp.write("\n") fp.write("%*s%s\n\n" % (nskip, "", winner)) fp.write(_(" the rank of\n\n")) fp.write(_(" \"Commodore Emeritus\"\n\n")) fp.write(" ") if game.skill == SKILL_EXPERT: fp.write(_(" Expert level\n\n")) elif game.skill == SKILL_EMERITUS: fp.write(_("Emeritus level\n\n")) else: fp.write(_(" Cheat level\n\n")) 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") % game.score) fp.write(_(" Klingons per stardate: %.2f\n") % game.perdate) fp.close() # Code from io.c begins here rows = linecount = 0 # for paging stdscr = None replayfp = None fullscreen_window = None srscan_window = None report_window = None status_window = None lrscan_window = None message_window = None prompt_window = None curwnd = None def iostart(): global stdscr, rows "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[0] < 3: import locale locale.setlocale(locale.LC_ALL, "") gettext.bindtextdomain("sst", "/usr/local/share/locale") gettext.textdomain("sst") if not (game.options & OPTION_CURSES): ln_env = os.getenv("LINES") if ln_env: rows = ln_env else: rows = 25 else: stdscr = curses.initscr() stdscr.keypad(True) curses.nonl() curses.cbreak() if game.options & OPTION_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) global fullscreen_window, srscan_window, report_window, status_window global lrscan_window, message_window, prompt_window (rows, columns) = stdscr.getmaxyx() fullscreen_window = stdscr srscan_window = curses.newwin(12, 25, 0, 0) report_window = curses.newwin(11, 0, 1, 25) status_window = curses.newwin(10, 0, 1, 39) lrscan_window = curses.newwin(5, 0, 0, 64) message_window = curses.newwin(0, 0, 12, 0) prompt_window = curses.newwin(1, 0, rows-2, 0) message_window.scrollok(True) setwnd(fullscreen_window) def ioend(): "Wrap up I/O." if game.options & OPTION_CURSES: stdscr.keypad(False) curses.echo() curses.nocbreak() curses.endwin() def waitfor(): "Wait for user action -- OK to do nothing if on a TTY" if game.options & OPTION_CURSES: stdscr.getch() def announce(): skip(1) prouts(_("[ANNOUNCEMENT ARRIVING...]")) skip(1) def pause_game(): if game.skill > SKILL_FAIR: prompt = _("[CONTINUE?]") else: prompt = _("[PRESS ENTER TO CONTINUE]") if game.options & OPTION_CURSES: drawmaps(0) setwnd(prompt_window) prompt_window.clear() prompt_window.addstr(prompt) prompt_window.getstr() prompt_window.clear() prompt_window.refresh() setwnd(message_window) else: global linecount sys.stdout.write('\n') proutn(prompt) if not replayfp: input() 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() try: curwnd.move(y+1, 0) except curses.error: pass else: global linecount linecount += 1 if rows and linecount >= rows: pause_game() else: sys.stdout.write('\n') 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: sys.stdout.write(line) sys.stdout.flush() def prout(line): proutn(line) skip(1) def prouts(line): "Emit slowly!" for c in line: if not replayfp or replayfp.closed: # Don't slow down replays time.sleep(0.03) proutn(c) if game.options & OPTION_CURSES: curwnd.refresh() else: sys.stdout.flush() if not replayfp or replayfp.closed: time.sleep(0.03) def cgetline(): "Get a line of input." if game.options & OPTION_CURSES: line = curwnd.getstr().decode('utf-8') + "\n" curwnd.refresh() else: if replayfp and not replayfp.closed: while True: line = replayfp.readline() proutn(line) if line == '': prout("*** Replay finished") replayfp.close() break elif line[0] != "#": break else: line = eval(input()) + "\n" if logfp: logfp.write(line) return line 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 # 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" if game.options & OPTION_CURSES: curwnd.clrtoeol() curwnd.refresh() 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() linecount = 0 def textcolor(color=DEFAULT): if game.options & OPTION_COLOR: if color == DEFAULT: curwnd.attrset(0) elif color == BLACK: curwnd.attron(curses.color_pair(curses.COLOR_BLACK)) elif color == BLUE: curwnd.attron(curses.color_pair(curses.COLOR_BLUE)) elif color == GREEN: curwnd.attron(curses.color_pair(curses.COLOR_GREEN)) elif color == CYAN: curwnd.attron(curses.color_pair(curses.COLOR_CYAN)) elif color == RED: curwnd.attron(curses.color_pair(curses.COLOR_RED)) elif color == MAGENTA: curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA)) elif color == BROWN: curwnd.attron(curses.color_pair(curses.COLOR_YELLOW)) elif color == LIGHTGRAY: curwnd.attron(curses.color_pair(curses.COLOR_WHITE)) elif color == DARKGRAY: 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) elif color == LIGHTGREEN: 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) elif color == LIGHTRED: 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) elif color == YELLOW: 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) def highvideo(): if game.options & OPTION_COLOR: curwnd.attron(curses.A_REVERSE) # # Things past this point have policy implications. # def drawmaps(mode): "Hook to be called after moving to redraw maps." if game.options & OPTION_CURSES: if mode == 1: sensor() setwnd(srscan_window) curwnd.move(0, 0) srscan() if mode != 2: setwnd(status_window) status_window.clear() status_window.move(0, 0) setwnd(report_window) report_window.clear() report_window.move(0, 0) status() setwnd(lrscan_window) lrscan_window.clear() lrscan_window.move(0, 0) lrscan(silent=False) def put_srscan_sym(w, sym): "Emit symbol for short-range scan." srscan_window.move(w.i+1, w.j*2+2) srscan_window.addch(sym) srscan_window.refresh() def boom(w): "Enemy fall down, go boom." if game.options & OPTION_CURSES: drawmaps(2) setwnd(srscan_window) srscan_window.attron(curses.A_REVERSE) put_srscan_sym(w, game.quad[w.i][w.j]) #sound(500) #time.sleep(1.0) #nosound() srscan_window.attroff(curses.A_REVERSE) put_srscan_sym(w, game.quad[w.i][w.j]) curses.delay_output(500) setwnd(message_window) def warble(): "Sound and visual effects for teleportation." if game.options & OPTION_CURSES: drawmaps(2) setwnd(message_window) #sound(50) prouts(" . . . . . ") if game.options & OPTION_CURSES: #curses.delay_output(1000) #nosound() pass def tracktorpedo(w, step, i, n, iquad): "Torpedo-track animation." if not game.options & OPTION_CURSES: if step == 1: if n != 1: skip(1) proutn(_("Track for torpedo number %d- ") % (i+1)) else: skip(1) proutn(_("Torpedo track- ")) elif step==4 or step==9: skip(1) proutn("%s " % w) else: if not damaged(DSRSENS) or game.condition=="docked": if i != 0 and step == 1: drawmaps(2) time.sleep(0.4) if (iquad=='.') or (iquad==' '): put_srscan_sym(w, '+') #sound(step*10) #time.sleep(0.1) #nosound() put_srscan_sym(w, iquad) else: curwnd.attron(curses.A_REVERSE) put_srscan_sym(w, iquad) #sound(500) #time.sleep(1.0) #nosound() curwnd.attroff(curses.A_REVERSE) put_srscan_sym(w, iquad) else: proutn("%s " % w) def makechart(): "Display the current galaxy chart." if game.options & OPTION_CURSES: setwnd(message_window) message_window.clear() chart() if game.options & OPTION_TTY: skip(1) NSYM = 14 def prstat(txt, data): proutn(txt) if game.options & OPTION_CURSES: skip(1) setwnd(status_window) else: proutn(" " * (NSYM - len(txt))) proutn(data) skip(1) if game.options & OPTION_CURSES: setwnd(report_window) # Code from moving.c begins here def imove(icourse=None, noattack=False): "Movement execution for warp, impulse, supernova, and tractor-beam events." w = Coord() def newquadrant(noattack): # Leaving quadrant -- allow final enemy attack # Don't do it if being pushed by Nova if len(game.enemies) != 0 and not noattack: newcnd() for enemy in game.enemies: finald = (w - enemy.location).distance() enemy.kavgd = 0.5 * (finald + enemy.kdist) # Stas Sergeev added the condition # that attacks only happen if Klingons # are present and your skill is good. if game.skill > SKILL_GOOD and game.klhere > 0 and not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova: attack(torps_ok=False) if game.alldone: return # check for edge of galaxy kinks = 0 while True: kink = False if icourse.final.i < 0: icourse.final.i = -icourse.final.i kink = True if icourse.final.j < 0: icourse.final.j = -icourse.final.j kink = True if icourse.final.i >= GALSIZE*QUADSIZE: icourse.final.i = (GALSIZE*QUADSIZE*2) - icourse.final.i kink = True if icourse.final.j >= GALSIZE*QUADSIZE: icourse.final.j = (GALSIZE*QUADSIZE*2) - icourse.final.j kink = True if kink: kinks += 1 else: break if kinks: game.nkinks += 1 if game.nkinks == 3: # Three strikes -- you're out! finish(FNEG3) return skip(1) prout(_("YOU HAVE ATTEMPTED TO CROSS THE NEGATIVE ENERGY BARRIER")) prout(_("AT THE EDGE OF THE GALAXY. THE THIRD TIME YOU TRY THIS,")) prout(_("YOU WILL BE DESTROYED.")) # Compute final position in new quadrant if trbeam: # Don't bother if we are to be beamed return 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 newqad() if game.skill>SKILL_NOVICE: attack(torps_ok=False) def check_collision(h): iquad = game.quad[h.i][h.j] if iquad != '.': # object encountered in flight path 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: break collision(rammed=False, enemy=enemy) return True elif iquad == ' ': skip(1) prouts(_("***RED ALERT! RED ALERT!")) skip(1) proutn("***" + crmshp()) proutn(_(" pulled into black hole at Sector %s") % h) # Getting pulled into a black hole was certain # death in Almy's original. Stas Sergeev added a # possibility that you'll get timewarped instead. n=0 for m in range(NDEVICES): if game.damage[m]>0: n += 1 probf=math.pow(1.4,(game.energy+game.shield)/5000.0-1.0)*math.pow(1.3,1.0/(n+1)-1.0) if (game.options & OPTION_BLKHOLE) and withprob(1-probf): timwrp() else: finish(FHOLE) return True else: # something else skip(1) proutn(crmshp()) if iquad == '#': prout(_(" encounters Tholian web at %s;") % h) else: prout(_(" blocked by object at %s;") % h) proutn(_("Emergency stop required ")) prout(_("%2d units of energy.") % int(stopegy)) game.energy -= stopegy if game.energy <= 0: finish(FNRG) return True return False trbeam = False if game.inorbit: prout(_("Helmsman Sulu- \"Leaving standard orbit.\"")) game.inorbit = False # If tractor beam is to occur, don't move full distance if game.state.date+game.optime >= scheduled(FTBEAM): trbeam = True game.condition = "red" 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(icourse.moves): icourse.nexttok() w = icourse.sector() if icourse.origin.quadrant() != icourse.location.quadrant(): newquadrant(noattack) break elif check_collision(w): print("Collision detected") break else: game.sector = w # We're in destination quadrant -- compute new average enemy distances game.quad[game.sector.i][game.sector.j] = game.ship if game.enemies: for enemy in game.enemies: finald = (w-enemy.location).distance() enemy.kavgd = 0.5 * (finald + enemy.kdist) enemy.kdist = finald sortenemies() if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova: attack(torps_ok=False) for enemy in game.enemies: enemy.kavgd = enemy.kdist newcnd() drawmaps(0) setwnd(message_window) return def dock(verbose): "Dock our ship at a starbase." scanner.chew() if game.condition == "docked" and verbose: prout(_("Already docked.")) return if game.inorbit: prout(_("You must first leave standard orbit.")) return if not game.base.is_valid() or abs(game.sector.i-game.base.i) > 1 or abs(game.sector.j-game.base.j) > 1: prout(crmshp() + _(" not adjacent to base.")) return game.condition = "docked" if "verbose": prout(_("Docked.")) game.ididit = True if game.energy < game.inenrg: game.energy = game.inenrg game.shield = game.inshld game.torps = game.intorps game.lsupres = game.inlsr game.state.crew = FULLCREW if not damaged(DRADIO) and \ ((is_scheduled(FCDBAS) or game.isatb == 1) and not game.iseenit): # get attack report from base prout(_("Lt. Uhura- \"Captain, an important message from the starbase:\"")) attackreport(False) game.iseenit = True def cartesian(loc1=None, loc2=None): if loc1 is None: return game.quadrant * QUADSIZE + game.sector elif loc2 is None: return game.quadrant * QUADSIZE + loc1 else: return loc1 * QUADSIZE + loc2 def getcourse(isprobe): "Get a course and distance from the user." key = 0 dquad = copy.copy(game.quadrant) navmode = "unspecified" itemp = "curt" dsect = Coord() iprompt = False if game.landed and not isprobe: prout(_("Dummy! You can't leave standard orbit until you")) proutn(_("are back aboard the ship.")) scanner.chew() raise TrekError while navmode == "unspecified": if damaged(DNAVSYS): if isprobe: prout(_("Computer damaged; manual navigation only")) else: prout(_("Computer damaged; manual movement only")) scanner.chew() navmode = "manual" key = "IHEOL" break key = scanner.nexttok() if key == "IHEOL": proutn(_("Manual or automatic- ")) iprompt = True scanner.chew() elif key == "IHALPHA": if scanner.sees("manual"): navmode = "manual" key = scanner.nexttok() break elif scanner.sees("automatic"): navmode = "automatic" key = scanner.nexttok() break else: huh() scanner.chew() raise TrekError else: # numeric if isprobe: prout(_("(Manual navigation assumed.)")) else: prout(_("(Manual movement assumed.)")) navmode = "manual" break delta = Coord() if navmode == "automatic": while key == "IHEOL": if isprobe: proutn(_("Target quadrant or quadrant§or- ")) else: proutn(_("Destination sector or quadrant§or- ")) scanner.chew() iprompt = True key = scanner.nexttok() if key != "IHREAL": huh() raise TrekError xi = int(round(scanner.real))-1 key = scanner.nexttok() if key != "IHREAL": huh() raise TrekError xj = int(round(scanner.real))-1 key = scanner.nexttok() if key == "IHREAL": # both quadrant and sector specified xk = int(round(scanner.real))-1 key = scanner.nexttok() if key != "IHREAL": huh() raise TrekError xl = int(round(scanner.real))-1 dquad.i = xi dquad.j = xj dsect.i = xk dsect.j = xl else: # only one pair of numbers was specified if isprobe: # only quadrant specified -- go to center of dest quad dquad.i = xi dquad.j = xj dsect.j = dsect.i = 4 # preserves 1-origin behavior else: # only sector specified dsect.i = xi dsect.j = xj itemp = "normal" if not dquad.valid_quadrant() or not dsect.valid_sector(): huh() raise TrekError skip(1) if not isprobe: if itemp > "curt": if iprompt: prout(_("Helmsman Sulu- \"Course locked in for Sector %s.\"") % dsect) else: prout(_("Ensign Chekov- \"Course laid in, Captain.\"")) # the actual deltas get computed here delta.j = dquad.j-game.quadrant.j + (dsect.j-game.sector.j)/(QUADSIZE*1.0) delta.i = game.quadrant.i-dquad.i + (game.sector.i-dsect.i)/(QUADSIZE*1.0) else: # manual while key == "IHEOL": proutn(_("X and Y displacements- ")) scanner.chew() iprompt = True key = scanner.nexttok() itemp = "verbose" if key != "IHREAL": huh() raise TrekError delta.j = scanner.real key = scanner.nexttok() if key != "IHREAL": huh() raise TrekError delta.i = scanner.real # Check for zero movement if delta.i == 0 and delta.j == 0: scanner.chew() raise TrekError if itemp == "verbose" and not isprobe: skip(1) prout(_("Helmsman Sulu- \"Aye, Sir.\"")) scanner.chew() return course(bearing=delta.bearing(), distance=delta.distance()) class course: def __init__(self, bearing, distance, origin=None): self.distance = distance self.bearing = bearing if origin is None: self.origin = cartesian(game.quadrant, game.sector) else: self.origin = origin # The bearing() code we inherited from FORTRAN is actually computing # clockface directions! if self.bearing < 0.0: self.bearing += 12.0 self.angle = ((15.0 - self.bearing) * 0.5235988) if origin is None: 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)) bigger = max(abs(self.increment.i), abs(self.increment.j)) self.increment /= bigger self.moves = int(round(10*self.distance*bigger)) self.reset() self.final = (self.location + self.moves*self.increment).roundtogrid() def reset(self): self.location = self.origin self.step = 0 def arrived(self): return self.location.roundtogrid() == self.final def nexttok(self): "Next step on course." self.step += 1 self.nextlocation = self.location + self.increment samequad = (self.location.quadrant() == self.nextlocation.quadrant()) self.location = self.nextlocation return samequad def quadrant(self): return self.location.quadrant() def sector(self): return self.location.sector() def power(self, warp): return self.distance*(warp**3)*(game.shldup+1) def time(self, warp): return 10.0*self.distance/warp**2 def impulse(): "Move under impulse power." game.ididit = False if damaged(DIMPULS): scanner.chew() skip(1) prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\"")) return if game.energy > 30.0: try: course = getcourse(isprobe=False) except TrekError: return power = 20.0 + 100.0*course.distance else: power = 30.0 if power >= game.energy: # Insufficient power for trip skip(1) prout(_("First Officer Spock- \"Captain, the impulse engines")) prout(_("require 20.0 units to engage, plus 100.0 units per")) if game.energy > 30: proutn(_("quadrant. We can go, therefore, a maximum of %d") % int(0.01 * (game.energy-20.0)-0.05)) prout(_(" quadrants.\"")) else: prout(_("quadrant. They are, therefore, useless.\"")) scanner.chew() return # Make sure enough time is left for the trip 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")) proutn(_("we dare spend the time?\" ")) if not ja(): return # Activate impulse engines and pay the cost imove(course, noattack=False) game.ididit = True if game.alldone: return power = 20.0 + 100.0*course.distance game.energy -= power game.optime = course.distance/0.095 if game.energy <= 0: finish(FNRG) return def warp(wcourse, involuntary): "ove under warp drive." blooey = False; twarp = False if not involuntary: # Not WARPX entry game.ididit = False if game.damage[DWARPEN] > 10.0: scanner.chew() skip(1) prout(_("Engineer Scott- \"The warp engines are damaged, Sir.\"")) return if damaged(DWARPEN) and game.warpfac > 4.0: scanner.chew() skip(1) prout(_("Engineer Scott- \"Sorry, Captain. Until this damage")) prout(_(" is repaired, I can only give you warp 4.\"")) return # Read in course and distance if wcourse==None: try: 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 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*wcourse.power(game.warpfac) > game.energy: 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: proutn(_("We don't have enough energy, but we could do it at warp %d") % iwarp) if game.shldup: prout(",") prout(_("if you'll lower the shields.")) else: prout(".") else: 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 = wcourse.time(game.warpfac) if game.optime >= 0.8*game.state.remtime: skip(1) prout(_("First Officer Spock- \"Captain, I compute that such")) proutn(_(" a trip would require approximately %2.0f") % (100.0*game.optime/game.state.remtime)) prout(_(" percent of our")) proutn(_(" remaining time. Are you sure this is wise?\" ")) if not ja(): game.ididit = False game.optime=0 return # Entry WARPX if game.warpfac > 6.0: # Decide if engine damage will occur # ESR: Seems wrong. Probability of damage goes *down* with distance? prob = wcourse.distance*(6.0-game.warpfac)**2/66.666666666 if prob > randreal(): blooey = True wcourse.distance = randreal(wcourse.distance) # Decide if time warp will occur if 0.5*wcourse.distance*math.pow(7.0,game.warpfac-10.0) > randreal(): twarp = True if game.idebug and game.warpfac==10 and not twarp: blooey = False proutn("=== Force time warp? ") 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 look = wcourse.moves while look > 0: look -= 1 wcourse.nexttok() w = wcourse.sector() if not w.valid_sector(): break if game.quad[w.i][w.j] != '.': blooey = False twarp = False wcourse.reset() # Activate Warp Engines and pay the cost imove(wcourse, noattack=False) if game.alldone: return game.energy -= wcourse.power(game.warpfac) if game.energy <= 0: finish(FNRG) game.optime = wcourse.time(game.warpfac) if twarp: timwrp() if blooey: game.damage[DWARPEN] = game.damfac * randreal(1.0, 4.0) skip(1) prout(_("Engineering to bridge--")) prout(_(" Scott here. The warp engines are damaged.")) prout(_(" We'll have to reduce speed to warp 4.")) game.ididit = True return def setwarp(): "Change the warp factor." while True: key=scanner.nexttok() if key != "IHEOL": break scanner.chew() proutn(_("Warp factor- ")) if key != "IHREAL": huh() return if game.damage[DWARPEN] > 10.0: prout(_("Warp engines inoperative.")) return if damaged(DWARPEN) and scanner.real > 4.0: prout(_("Engineer Scott- \"I'm doing my best, Captain,")) prout(_(" but right now we can only go warp 4.\"")) return if scanner.real > 10.0: prout(_("Helmsman Sulu- \"Our top speed is warp 10, Captain.\"")) return if scanner.real < 1.0: prout(_("Helmsman Sulu- \"We can't go below warp 1, Captain.\"")) return oldfac = game.warpfac game.warpfac = scanner.real if game.warpfac <= oldfac or game.warpfac <= 6.0: prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\"") % int(game.warpfac)) return if game.warpfac < 8.00: prout(_("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\"")) return if game.warpfac == 10.0: prout(_("Engineer Scott- \"Aye, Captain, we'll try it.\"")) return prout(_("Engineer Scott- \"Aye, Captain, but our engines may not take it.\"")) return def atover(igrab): "Cope with being tossed out of quadrant by supernova or yanked by beam." scanner.chew() # is captain on planet? if game.landed: if damaged(DTRANSP): finish(FPNOVA) return prout(_("Scotty rushes to the transporter controls.")) if game.shldup: prout(_("But with the shields up it's hopeless.")) finish(FPNOVA) prouts(_("His desperate attempt to rescue you . . .")) if withprob(0.5): prout(_("fails.")) finish(FPNOVA) return prout(_("SUCCEEDS!")) if game.imine: game.imine = False proutn(_("The crystals mined were ")) if withprob(0.25): prout(_("lost.")) else: prout(_("saved.")) game.icrystl = True if igrab: return # Check to see if captain in shuttle craft if game.icraft: finish(FSTRACTOR) if game.alldone: return # Inform captain of attempt to reach safety skip(1) while True: if game.justin: prouts(_("***RED ALERT! RED ALERT!")) skip(1) proutn(_("The %s has stopped in a quadrant containing") % crmshp()) prouts(_(" a supernova.")) skip(2) prout(_("***Emergency automatic override attempts to hurl ")+crmshp()) prout(_("safely out of quadrant.")) if not damaged(DRADIO): game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True # Try to use warp engines if damaged(DWARPEN): skip(1) prout(_("Warp engines damaged.")) finish(FSNOVAED) return game.warpfac = randreal(6.0, 8.0) prout(_("Warp factor set to %d") % int(game.warpfac)) power = 0.75*game.energy dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1)) dist = max(dist, randreal(math.sqrt(2))) bugout = course(bearing=randreal(12), distance=dist) # How dumb! game.optime = bugout.time(game.warpfac) game.justin = False game.inorbit = False warp(bugout, involuntary=True) if not game.justin: # This is bad news, we didn't leave quadrant. if game.alldone: return skip(1) prout(_("Insufficient energy to leave quadrant.")) finish(FSNOVAED) return # Repeat if another snova if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova: break if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0: finish(FWON) # Snova killed remaining enemy. def timwrp(): "Let's do the time warp again." prout(_("***TIME WARP ENTERED.")) if game.state.snap and withprob(0.5): # Go back in time prout(_("You are traveling backwards in time %d stardates.") % int(game.state.date-game.snapsht.date)) game.state = game.snapsht game.state.snap = False if len(game.state.kcmdr): schedule(FTBEAM, expran(game.intime/len(game.state.kcmdr))) schedule(FBATTAK, expran(0.3*game.intime)) schedule(FSNOVA, expran(0.5*game.intime)) # next snapshot will be sooner schedule(FSNAP, expran(0.25*game.state.remtime)) if game.state.nscrem: schedule(FSCMOVE, 0.2777) game.isatb = 0 unschedule(FCDBAS) unschedule(FSCDBAS) game.battle.invalidate() # Make sure Galileo is consistant -- Snapshot may have been taken # when on planet, which would give us two Galileos! gotit = False for l in range(game.inplan): if game.state.planets[l].known == "shuttle_down": gotit = True if game.iscraft == "onship" and game.ship=='E': prout(_("Chekov- \"Security reports the Galileo has disappeared, Sir!")) game.iscraft = "offship" # Likewise, if in the original time the Galileo was abandoned, but # was on ship earlier, it would have vanished -- let's restore it. if game.iscraft == "offship" and not gotit and game.damage[DSHUTTL] >= 0.0: prout(_("Chekov- \"Security reports the Galileo has reappeared in the dock!\"")) game.iscraft = "onship" # There used to be code to do the actual reconstrction here, # but the starchart is now part of the snapshotted galaxy state. prout(_("Spock has reconstructed a correct star chart from memory")) else: # Go forward in time game.optime = expran(0.5*game.intime) prout(_("You are traveling forward in time %d stardates.") % int(game.optime)) # cheat to make sure no tractor beams occur during time warp postpone(FTBEAM, game.optime) game.damage[DRADIO] += game.optime newqad() events() # Stas Sergeev added this -- do pending events def probe(): "Launch deep-space probe." # New code to launch a deep space probe if game.nprobes == 0: scanner.chew() skip(1) if game.ship == 'E': prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\"")) else: prout(_("Ye Faerie Queene has no deep space probes.")) return if damaged(DDSP): scanner.chew() skip(1) prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\"")) return if is_scheduled(FDSPROB): scanner.chew() skip(1) if damaged(DRADIO) and game.condition != "docked": prout(_("Spock- \"Records show the previous probe has not yet")) prout(_(" reached its destination.\"")) else: prout(_("Uhura- \"The previous probe is still reporting data, Sir.\"")) return key = scanner.nexttok() if key == "IHEOL": if game.nprobes == 1: prout(_("1 probe left.")) else: prout(_("%d probes left") % game.nprobes) proutn(_("Are you sure you want to fire a probe? ")) if not ja(): return game.isarmed = False if key == "IHALPHA" and scanner.token == "armed": game.isarmed = True key = scanner.nexttok() elif key == "IHEOL": proutn(_("Arm NOVAMAX warhead? ")) game.isarmed = ja() elif key == "IHREAL": # first element of course scanner.push(scanner.token) try: game.probe = getcourse(isprobe=True) except TrekError: return game.nprobes -= 1 schedule(FDSPROB, 0.01) # Time to move one sector prout(_("Ensign Chekov- \"The deep space probe is launched, Captain.\"")) game.ididit = True return def mayday(): "Yell for help from nearest starbase." # There's more than one way to move in this game! scanner.chew() # Test for conditions which prevent calling for help if game.condition == "docked": prout(_("Lt. Uhura- \"But Captain, we're already docked.\"")) return if damaged(DRADIO): prout(_("Subspace radio damaged.")) return if not game.state.baseq: prout(_("Lt. Uhura- \"Captain, I'm not getting any response from Starbase.\"")) return if game.landed: prout(_("You must be aboard the %s.") % crmshp()) return # OK -- call for help from nearest starbase game.nhelp += 1 if game.base.i!=0: # There's one in this quadrant ddist = (game.base - game.sector).distance() else: ddist = FOREVER for ibq in game.state.baseq: xdist = QUADSIZE * (ibq - game.quadrant).distance() if xdist < ddist: ddist = xdist # Since starbase not in quadrant, set up new quadrant game.quadrant = ibq newqad() # dematerialize starship game.quad[game.sector.i][game.sector.j]='.' proutn(_("Starbase in Quadrant %s responds--%s dematerializes") \ % (game.quadrant, crmshp())) game.sector.invalidate() for m in range(1, 5+1): w = game.base.scatter() if w.valid_sector() and game.quad[w.i][w.j]=='.': # found one -- finish up game.sector = w break if not game.sector.is_valid(): prout(_("You have been lost in space...")) finish(FMATERIALIZE) return # Give starbase three chances to rematerialize starship probf = math.pow((1.0 - math.pow(0.98,ddist)), 0.33333333) for m in range(1, 3+1): if m == 1: proutn(_("1st")) elif m == 2: proutn(_("2nd")) elif m == 3: proutn(_("3rd")) proutn(_(" attempt to re-materialize ") + crmshp()) game.quad[game.sector.i][game.sector.j]=('-','o','O')[m-1] textcolor(RED) warble() if randreal() > probf: break prout(_("fails.")) textcolor(DEFAULT) curses.delay_output(500) if m > 3: game.quad[game.sector.i][game.sector.j]='?' game.alive = False drawmaps(1) setwnd(message_window) finish(FMATERIALIZE) return game.quad[game.sector.i][game.sector.j]=game.ship textcolor(GREEN) prout(_("succeeds.")) textcolor(DEFAULT) dock(False) skip(1) prout(_("Lt. Uhura- \"Captain, we made it!\"")) def abandon(): "Abandon ship." scanner.chew() if game.condition=="docked": if game.ship!='E': prout(_("You cannot abandon Ye Faerie Queene.")) return else: # Must take shuttle craft to exit if game.damage[DSHUTTL]==-1: prout(_("Ye Faerie Queene has no shuttle craft.")) return if game.damage[DSHUTTL]<0: prout(_("Shuttle craft now serving Big Macs.")) return if game.damage[DSHUTTL]>0: prout(_("Shuttle craft damaged.")) return if game.landed: prout(_("You must be aboard the ship.")) return if game.iscraft != "onship": prout(_("Shuttle craft not currently available.")) return # Emit abandon ship messages skip(1) prouts(_("***ABANDON SHIP! ABANDON SHIP!")) skip(1) prouts(_("***ALL HANDS ABANDON SHIP!")) skip(2) prout(_("Captain and crew escape in shuttle craft.")) if not game.state.baseq: # Oops! no place to go... finish(FABANDN) return q = game.state.galaxy[game.quadrant.i][game.quadrant.j] # Dispose of crew if not (game.options & OPTION_WORLDS) and not damaged(DTRANSP): prout(_("Remainder of ship's complement beam down")) prout(_("to nearest habitable planet.")) elif q.planet != None and not damaged(DTRANSP): prout(_("Remainder of ship's complement beam down to %s.") % q.planet) else: prout(_("Entire crew of %d left to die in outer space.") % game.state.crew) game.casual += game.state.crew game.abandoned += game.state.crew # If at least one base left, give 'em the Faerie Queene skip(1) game.icrystl = False # crystals are lost game.nprobes = 0 # No probes prout(_("You are captured by Klingons and released to")) prout(_("the Federation in a prisoner-of-war exchange.")) nb = randrange(len(game.state.baseq)) # Set up quadrant and position FQ adjacient to base if not game.quadrant == game.state.baseq[nb]: game.quadrant = game.state.baseq[nb] game.sector.i = game.sector.j = 5 newqad() while True: # position next to base by trial and error game.quad[game.sector.i][game.sector.j] = '.' for l in range(QUADSIZE): game.sector = game.base.scatter() if game.sector.valid_sector() and \ game.quad[game.sector.i][game.sector.j] == '.': break if l < QUADSIZE+1: break # found a spot game.sector.i=QUADSIZE/2 game.sector.j=QUADSIZE/2 newqad() # Get new commission game.quad[game.sector.i][game.sector.j] = game.ship = 'F' game.state.crew = FULLCREW prout(_("Starfleet puts you in command of another ship,")) prout(_("the Faerie Queene, which is antiquated but,")) prout(_("still useable.")) if game.icrystl: prout(_("The dilithium crystals have been moved.")) game.imine = False game.iscraft = "offship" # Galileo disappears # Resupply ship game.condition="docked" for l in range(NDEVICES): game.damage[l] = 0.0 game.damage[DSHUTTL] = -1 game.energy = game.inenrg = 3000.0 game.shield = game.inshld = 1250.0 game.torps = game.intorps = 6 game.lsupres=game.inlsr=3.0 game.shldup=False game.warpfac=5.0 return # Code from planets.c begins here. def consumeTime(): "Abort a lengthy operation if an event interrupts it." game.ididit = True events() if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.justin: return True return False def survey(): "Report on (uninhabited) planets in the galaxy." iknow = False skip(1) scanner.chew() prout(_("Spock- \"Planet report follows, Captain.\"")) skip(1) for i in range(game.inplan): if game.state.planets[i].pclass == "destroyed": continue if (game.state.planets[i].known != "unknown" \ and not game.state.planets[i].inhabited) \ or game.idebug: iknow = True 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": proutn(_("no ")) prout(_("dilithium crystals present.")) if game.state.planets[i].known=="shuttle_down": prout(_(" Shuttle Craft Galileo on surface.")) if not iknow: prout(_("No information available.")) def orbit(): "Enter standard orbit." skip(1) scanner.chew() if game.inorbit: prout(_("Already in standard orbit.")) return if damaged(DWARPEN) and damaged(DIMPULS): prout(_("Both warp and impulse engines damaged.")) return if not game.plnet.is_valid(): prout("There is no planet in this sector.") return if abs(game.sector.i-game.plnet.i)>1 or abs(game.sector.j-game.plnet.j)>1: prout(crmshp() + _(" not adjacent to planet.")) skip(1) return game.optime = randreal(0.02, 0.05) prout(_("Helmsman Sulu- \"Entering standard orbit, Sir.\"")) newcnd() if consumeTime(): return game.height = randreal(1400, 8600) prout(_("Sulu- \"Entered orbit at altitude %.2f kilometers.\"") % game.height) game.inorbit = True game.ididit = True def sensor(): "Examine planets in this quadrant." if damaged(DSRSENS): if game.options & OPTION_TTY: prout(_("Short range sensors damaged.")) return if game.iplnet == None: if game.options & OPTION_TTY: prout(_("Spock- \"No planet in this quadrant, Captain.\"")) return if game.iplnet.known == "unknown": prout(_("Spock- \"Sensor scan for Quadrant %s-") % game.quadrant) skip(1) prout(_(" Planet at Sector %s is of class %s.") % (game.plnet, game.iplnet.pclass)) if game.iplnet.known=="shuttle_down": prout(_(" Sensors show Galileo still on surface.")) proutn(_(" Readings indicate")) if game.iplnet.crystals != "present": proutn(_(" no")) prout(_(" dilithium crystals present.\"")) if game.iplnet.known == "unknown": game.iplnet.known = "known" elif game.iplnet.inhabited: prout(_("Spock- \"The inhabited planet %s ") % game.iplnet.name) prout(_(" is located at Sector %s, Captain.\"") % game.plnet) def beam(): "Use the transporter." nrgneed = 0 scanner.chew() skip(1) if damaged(DTRANSP): prout(_("Transporter damaged.")) 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(): shuttle() return if not game.inorbit: prout(crmshp() + _(" not in standard orbit.")) return if game.shldup: prout(_("Impossible to transport through shields.")) return if game.iplnet.known=="unknown": prout(_("Spock- \"Captain, we have no information on this planet")) prout(_(" and Starfleet Regulations clearly state that in this situation")) prout(_(" you may not go down.\"")) return if not game.landed and game.iplnet.crystals=="absent": 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 not ja(): scanner.chew() return if not (game.options & OPTION_PLAIN): nrgneed = 50 * game.skill + game.height / 100.0 if nrgneed > game.energy: prout(_("Engineering to bridge--")) prout(_(" Captain, we don't have enough energy for transportation.")) return if not game.landed and nrgneed * 2 > game.energy: prout(_("Engineering to bridge--")) prout(_(" Captain, we have enough energy only to transport you down to")) prout(_(" the planet, but there wouldn't be an energy for the trip back.")) 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 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(): scanner.chew() return prout(_("Your crew hides the Galileo to prevent capture by aliens.")) prout(_("Landing party assembled, ready to beam up.")) skip(1) prout(_("Kirk whips out communicator...")) prouts(_("BEEP BEEP BEEP")) skip(2) prout(_("\"Kirk to enterprise- Lock on coordinates...energize.\"")) else: # Going to planet prout(_("Scotty- \"Transporter room ready, Sir.\"")) skip(1) prout(_("Kirk and landing party prepare to beam down to planet surface.")) skip(1) prout(_("Kirk- \"Energize.\"")) game.ididit = True skip(1) prouts("WWHOOOIIIIIRRRRREEEE.E.E. . . . . . .") skip(2) if not withprob(0.98): prouts("BOOOIIIOOOIIOOOOIIIOIING . . .") skip(2) prout(_("Scotty- \"Oh my God! I've lost them.\"")) finish(FLOST) return prouts(". . . . . . .E.E.EEEERRRRRIIIIIOOOHWW") game.landed = not game.landed game.energy -= nrgneed skip(2) prout(_("Transport complete.")) if game.landed and game.iplnet.known=="shuttle_down": prout(_("The shuttle craft Galileo is here!")) if not game.landed and game.imine: game.icrystl = True game.cryprob = 0.05 game.imine = False return def mine(): "Strip-mine a world for dilithium." skip(1) scanner.chew() if not game.landed: prout(_("Mining party not on planet.")) return if game.iplnet.crystals == "mined": prout(_("This planet has already been strip-mined for dilithium.")) return elif game.iplnet.crystals == "absent": prout(_("No dilithium crystals on this planet.")) return if game.imine: prout(_("You've already mined enough crystals for this trip.")) return if game.icrystl and game.cryprob == 0.05: prout(_("With all those fresh crystals aboard the ") + crmshp()) prout(_("there's no reason to mine more at this time.")) return game.optime = randreal(0.1, 0.3)*(ord(game.iplnet.pclass)-ord("L")) if consumeTime(): return prout(_("Mining operation complete.")) game.iplnet.crystals = "mined" game.imine = game.ididit = True def usecrystals(): "Use dilithium crystals." game.ididit = False skip(1) scanner.chew() if not game.icrystl: prout(_("No dilithium crystals available.")) return if game.energy >= 1000: prout(_("Spock- \"Captain, Starfleet Regulations prohibit such an operation")) prout(_(" except when Condition Yellow exists.")) return prout(_("Spock- \"Captain, I must warn you that loading")) prout(_(" raw dilithium crystals into the ship's power")) prout(_(" system may risk a severe explosion.")) proutn(_(" Are you sure this is wise?\" ")) if not ja(): scanner.chew() return skip(1) prout(_("Engineering Officer Scott- \"(GULP) Aye Sir.")) prout(_(" Mr. Spock and I will try it.\"")) skip(1) prout(_("Spock- \"Crystals in place, Sir.")) prout(_(" Ready to activate circuit.\"")) skip(1) prouts(_("Scotty- \"Keep your fingers crossed, Sir!\"")) skip(1) if withprob(game.cryprob): prouts(_(" \"Activating now! - - No good! It's***")) skip(2) prouts(_("***RED ALERT! RED A*L********************************")) skip(1) stars() prouts(_("****************** KA-BOOM!!!! *******************")) skip(1) kaboom() return game.energy += randreal(5000.0, 5500.0) prouts(_(" \"Activating now! - - ")) prout(_("The instruments")) prout(_(" are going crazy, but I think it's")) prout(_(" going to work!! Congratulations, Sir!\"")) game.cryprob *= 2.0 game.ididit = True def shuttle(): "Use shuttlecraft for planetary jaunt." scanner.chew() skip(1) if damaged(DSHUTTL): if game.damage[DSHUTTL] == -1.0: if game.inorbit and game.iplnet.known == "shuttle_down": prout(_("Ye Faerie Queene has no shuttle craft bay to dock it at.")) else: prout(_("Ye Faerie Queene had no shuttle craft.")) elif game.damage[DSHUTTL] > 0: prout(_("The Galileo is damaged.")) else: # game.damage[DSHUTTL] < 0 prout(_("Shuttle craft is now serving Big Macs.")) return if not game.inorbit: prout(crmshp() + _(" not in standard orbit.")) return if (game.iplnet.known != "shuttle_down") and game.iscraft != "onship": prout(_("Shuttle craft not currently available.")) return if not game.landed and game.iplnet.known=="shuttle_down": prout(_("You will have to beam down to retrieve the shuttle craft.")) return if game.shldup or game.condition == "docked": prout(_("Shuttle craft cannot pass through shields.")) return if game.iplnet.known=="unknown": prout(_("Spock- \"Captain, we have no information on this planet")) prout(_(" and Starfleet Regulations clearly state that in this situation")) prout(_(" you may not fly down.\"")) return game.optime = 3.0e-5*game.height if game.optime >= 0.8*game.state.remtime: prout(_("First Officer Spock- \"Captain, I compute that such")) proutn(_(" a maneuver would require approximately %2d%% of our") % \ int(100*game.optime/game.state.remtime)) prout(_("remaining time.")) proutn(_("Are you sure this is wise?\" ")) if not ja(): game.optime = 0.0 return if game.landed: # Kirk on planet if game.iscraft == "onship": # Galileo on ship! if not damaged(DTRANSP): proutn(_("Spock- \"Would you rather use the transporter?\" ")) if ja(): beam() return proutn(_("Shuttle crew")) else: proutn(_("Rescue party")) prout(_(" boards Galileo and swoops toward planet surface.")) game.iscraft = "offship" skip(1) if consumeTime(): return game.iplnet.known="shuttle_down" prout(_("Trip complete.")) return else: # Ready to go back to ship prout(_("You and your mining party board the")) prout(_("shuttle craft for the trip back to the Enterprise.")) skip(1) prouts(_("The short hop begins . . .")) skip(1) game.iplnet.known="known" game.icraft = True skip(1) game.landed = False if consumeTime(): return game.iscraft = "onship" game.icraft = False if game.imine: game.icrystl = True game.cryprob = 0.05 game.imine = False prout(_("Trip complete.")) return else: # Kirk on ship and so is Galileo prout(_("Mining party assembles in the hangar deck,")) prout(_("ready to board the shuttle craft \"Galileo\".")) skip(1) prouts(_("The hangar doors open; the trip begins.")) skip(1) game.icraft = True game.iscraft = "offship" if consumeTime(): return game.iplnet.known = "shuttle_down" game.landed = True game.icraft = False prout(_("Trip complete.")) return def deathray(): "Use the big zapper." game.ididit = False skip(1) scanner.chew() if game.ship != 'E': prout(_("Ye Faerie Queene has no death ray.")) return if len(game.enemies)==0: prout(_("Sulu- \"But Sir, there are no enemies in this quadrant.\"")) return if damaged(DDRAY): prout(_("Death Ray is damaged.")) return prout(_("Spock- \"Captain, the 'Experimental Death Ray'")) prout(_(" is highly unpredictible. Considering the alternatives,")) proutn(_(" are you sure this is wise?\" ")) if not ja(): return prout(_("Spock- \"Acknowledged.\"")) skip(1) game.ididit = True prouts(_("WHOOEE ... WHOOEE ... WHOOEE ... WHOOEE")) skip(1) prout(_("Crew scrambles in emergency preparation.")) prout(_("Spock and Scotty ready the death ray and")) prout(_("prepare to channel all ship's power to the device.")) skip(1) prout(_("Spock- \"Preparations complete, sir.\"")) prout(_("Kirk- \"Engage!\"")) skip(1) prouts(_("WHIRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR")) skip(1) dprob = 0.30 if game.options & OPTION_PLAIN: dprob = 0.5 r = randreal() if r > dprob: prouts(_("Sulu- \"Captain! It's working!\"")) skip(2) while len(game.enemies) > 0: deadkl(game.enemies[1].location, game.quad[game.enemies[1].location.i][game.enemies[1].location.j],game.enemies[1].location) prout(_("Ensign Chekov- \"Congratulations, Captain!\"")) if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0: finish(FWON) if (game.options & OPTION_PLAIN) == 0: prout(_("Spock- \"Captain, I believe the `Experimental Death Ray'")) if withprob(0.05): prout(_(" is still operational.\"")) else: prout(_(" has been rendered nonfunctional.\"")) game.damage[DDRAY] = 39.95 return r = randreal() # Pick failure method if r <= 0.30: prouts(_("Sulu- \"Captain! It's working!\"")) skip(1) prouts(_("***RED ALERT! RED ALERT!")) skip(1) prout(_("***MATTER-ANTIMATTER IMPLOSION IMMINENT!")) skip(1) prouts(_("***RED ALERT! RED A*L********************************")) skip(1) stars() prouts(_("****************** KA-BOOM!!!! *******************")) skip(1) kaboom() return if r <= 0.55: prouts(_("Sulu- \"Captain! Yagabandaghangrapl, brachriigringlanbla!\"")) skip(1) prout(_("Lt. Uhura- \"Graaeek! Graaeek!\"")) skip(1) prout(_("Spock- \"Fascinating! . . . All humans aboard")) prout(_(" have apparently been transformed into strange mutations.")) prout(_(" Vulcans do not seem to be affected.")) skip(1) prout(_("Kirk- \"Raauch! Raauch!\"")) finish(FDRAY) return if r <= 0.75: prouts(_("Sulu- \"Captain! It's --WHAT?!?!\"")) skip(2) proutn(_("Spock- \"I believe the word is")) prouts(_(" *ASTONISHING*")) prout(_(" Mr. Sulu.")) for i in range(QUADSIZE): for j in range(QUADSIZE): if game.quad[i][j] == '.': game.quad[i][j] = '?' prout(_(" Captain, our quadrant is now infested with")) prouts(_(" - - - - - - *THINGS*.")) skip(1) prout(_(" I have no logical explanation.\"")) return prouts(_("Sulu- \"Captain! The Death Ray is creating tribbles!\"")) skip(1) prout(_("Scotty- \"There are so many tribbles down here")) prout(_(" in Engineering, we can't move for 'em, Captain.\"")) finish(FTRIBBLE) return # Code from reports.c begins here def attackreport(curt): "eport status of bases under attack." if not curt: if is_scheduled(FCDBAS): prout(_("Starbase in Quadrant %s is currently under Commander attack.") % game.battle) prout(_("It can hold out until Stardate %d.") % int(scheduled(FCDBAS))) elif game.isatb == 1: prout(_("Starbase in Quadrant %s is under Super-commander attack.") % game.state.kscmdr) prout(_("It can hold out until Stardate %d.") % int(scheduled(FSCDBAS))) else: prout(_("No Starbase is currently under attack.")) else: if is_scheduled(FCDBAS): proutn(_("Base in %s attacked by C. Alive until %.1f") % (game.battle, scheduled(FCDBAS))) if game.isatb: proutn(_("Base in %s attacked by S. Alive until %.1f") % (game.state.kscmdr, scheduled(FSCDBAS))) clreol() def report(): # report on general game status scanner.chew() s1 = (game.thawed and _("thawed ")) or "" s2 = {1:"short", 2:"medium", 4:"long"}[game.length] s3 = (None, _("novice"), _("fair"), _("good"), _("expert"), _("emeritus"))[game.skill] prout(_("You %s a %s%s %s game.") % ((_("were playing"), _("are playing"))[game.alldone], s1, s2, s3)) if game.skill>SKILL_GOOD and game.thawed and not game.alldone: prout(_("No plaque is allowed.")) if game.tourn: prout(_("This is tournament game %d.") % game.tourn) prout(_("Your secret password is \"%s\"") % game.passwd) proutn(_("%d of %d Klingons have been killed") % (((game.inkling + game.incom + game.inscom) - (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)), (game.inkling + game.incom + game.inscom))) if game.incom - len(game.state.kcmdr): prout(_(", including %d Commander%s.") % (game.incom - len(game.state.kcmdr), (_("s"), "")[(game.incom - len(game.state.kcmdr))==1])) elif game.inkling - game.state.remkl + (game.inscom - game.state.nscrem) > 0: prout(_(", but no Commanders.")) else: prout(".") if game.skill > SKILL_FAIR: prout(_("The Super Commander has %sbeen destroyed.") % ("", _("not "))[game.state.nscrem]) if len(game.state.baseq) != game.inbase: proutn(_("There ")) if game.inbase-len(game.state.baseq)==1: proutn(_("has been 1 base")) else: proutn(_("have been %d bases") % (game.inbase-len(game.state.baseq))) prout(_(" destroyed, %d remaining.") % len(game.state.baseq)) else: prout(_("There are %d bases.") % game.inbase) if communicating() or game.iseenit: # Don't report this if not seen and # either the radio is dead or not at base! attackreport(False) game.iseenit = True if game.casual: prout(_("%d casualt%s suffered so far.") % (game.casual, ("y", "ies")[game.casual!=1])) if game.nhelp: prout(_("There were %d call%s for help.") % (game.nhelp, ("" , _("s"))[game.nhelp!=1])) if game.ship == 'E': proutn(_("You have ")) if game.nprobes: proutn("%d" % (game.nprobes)) else: proutn(_("no")) proutn(_(" deep space probe")) if game.nprobes!=1: proutn(_("s")) prout(".") if communicating() and is_scheduled(FDSPROB): if game.isarmed: proutn(_("An armed deep space probe is in ")) else: proutn(_("A deep space probe is in ")) prout("Quadrant %s." % game.probec) if game.icrystl: if game.cryprob <= .05: prout(_("Dilithium crystals aboard ship... not yet used.")) else: i=0 ai = 0.05 while game.cryprob > ai: ai *= 2.0 i += 1 prout(_("Dilithium crystals have been used %d time%s.") % \ (i, (_("s"), "")[i==1])) skip(1) def lrscan(silent): "Long-range sensor scan." if damaged(DLRSENS): # Now allow base's sensors if docked if game.condition != "docked": if not silent: prout(_("LONG-RANGE SENSORS DAMAGED.")) return if not silent: prout(_("Starbase's long-range scan")) elif not silent: prout(_("Long-range scan")) for x in range(game.quadrant.i-1, game.quadrant.i+2): 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 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 not silent and game.state.galaxy[x][y].supernova: proutn(" ***") 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)) if not silent: prout(" ") def damagereport(): "Damage report." jdam = False scanner.chew() for i in range(NDEVICES): if damaged(i): if not jdam: prout(_("\tDEVICE\t\t\t-REPAIR TIMES-")) prout(_("\t\t\tIN FLIGHT\t\tDOCKED")) jdam = True prout(" %-26s\t%8.2f\t\t%8.2f" % (device[i], game.damage[i]+0.05, DOCKFAC*game.damage[i]+0.005)) if not jdam: prout(_("All devices functional.")) def rechart(): "Update the chart in the Enterprise's computer from galaxy data." game.lastchart = game.state.date for i in range(GALSIZE): for j in range(GALSIZE): if game.state.galaxy[i][j].charted: game.state.chart[i][j].klingons = game.state.galaxy[i][j].klingons game.state.chart[i][j].starbase = game.state.galaxy[i][j].starbase game.state.chart[i][j].stars = game.state.galaxy[i][j].stars def chart(): "Display the star chart." scanner.chew() if (game.options & OPTION_AUTOSCAN): lrscan(silent=True) if not damaged(DRADIO): rechart() if game.lastchart < game.state.date and game.condition == "docked": prout(_("Spock- \"I revised the Star Chart from the starbase's records.\"")) rechart() prout(_(" STAR CHART FOR THE KNOWN GALAXY")) if game.state.date > game.lastchart: prout(_("(Last surveillance update %d stardates ago).") % ((int)(game.state.date-game.lastchart))) prout(" 1 2 3 4 5 6 7 8") for i in range(GALSIZE): proutn("%d |" % (i+1)) for j in range(GALSIZE): if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j: proutn("<") else: proutn(" ") if game.state.galaxy[i][j].supernova: show = "***" elif not game.state.galaxy[i][j].charted and game.state.galaxy[i][j].starbase: show = ".1." elif game.state.galaxy[i][j].charted: show = "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars) else: show = "..." proutn(show) if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j: proutn(">") else: proutn(" ") proutn(" |") if i 0 for x in game.damage]))) if not req or req == 3: prstat(_("Position"), "%s , %s" % (game.quadrant, game.sector)) if not req or req == 4: if damaged(DLIFSUP): if game.condition == "docked": s = _("DAMAGED, Base provides") else: s = _("DAMAGED, reserves=%4.2f") % game.lsupres else: s = _("ACTIVE") prstat(_("Life Support"), s) if not req or req == 5: prstat(_("Warp Factor"), "%.1f" % game.warpfac) if not req or req == 6: extra = "" if game.icrystl and (game.options & OPTION_SHOWME): extra = _(" (have crystals)") prstat(_("Energy"), "%.2f%s" % (game.energy, extra)) if not req or req == 7: prstat(_("Torpedoes"), "%d" % (game.torps)) if not req or req == 8: if damaged(DSHIELD): s = _("DAMAGED,") elif game.shldup: s = _("UP,") else: s = _("DOWN,") data = _(" %d%% %.1f units") \ % (int((100.0*game.shield)/game.inshld + 0.5), game.shield) prstat(_("Shields"), s+data) if not req or req == 9: prstat(_("Klingons Left"), "%d" \ % (game.state.remkl+len(game.state.kcmdr)+game.state.nscrem)) if not req or req == 10: if game.options & OPTION_WORLDS: plnet = game.state.galaxy[game.quadrant.i][game.quadrant.j].planet if plnet and plnet.inhabited: prstat(_("Major system"), plnet.name) else: prout(_("Sector is uninhabited")) elif not req or req == 11: attackreport(not req) def request(): "Request specified status data, a historical relic from slow TTYs." requests = ("da","co","po","ls","wa","en","to","sh","kl","sy", "ti") while scanner.nexttok() == "IHEOL": proutn(_("Information desired? ")) scanner.chew() if scanner.token in requests: status(requests.index(scanner.token)) else: prout(_("UNRECOGNIZED REQUEST. Legal requests are:")) prout((" date, condition, position, lsupport, warpfactor,")) prout((" energy, torpedoes, shields, klingons, system, time.")) def srscan(): "Short-range scan." goodScan=True if damaged(DSRSENS): # Allow base's sensors if docked if game.condition != "docked": prout(_(" S.R. SENSORS DAMAGED!")) goodScan=False else: prout(_(" [Using Base's sensors]")) else: prout(_(" Short-range scan")) if goodScan and not damaged(DRADIO): game.state.chart[game.quadrant.i][game.quadrant.j].klingons = game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons game.state.chart[game.quadrant.i][game.quadrant.j].starbase = game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase game.state.chart[game.quadrant.i][game.quadrant.j].stars = game.state.galaxy[game.quadrant.i][game.quadrant.j].stars game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True prout(" 1 2 3 4 5 6 7 8 9 10") if game.condition != "docked": newcnd() for i in range(QUADSIZE): proutn("%2d " % (i+1)) for j in range(QUADSIZE): sectscan(goodScan, i, j) skip(1) def eta(): "Use computer to get estimated time of arrival for a warp jump." w1 = Coord(); w2 = Coord() prompt = False if damaged(DCOMPTR): prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR.")) skip(1) return if scanner.nexttok() != "IHREAL": prompt = True scanner.chew() proutn(_("Destination quadrant and/or sector? ")) if scanner.nexttok()!="IHREAL": huh() return w1.j = int(scanner.real-0.5) if scanner.nexttok() != "IHREAL": huh() return w1.i = int(scanner.real-0.5) if scanner.nexttok() == "IHREAL": w2.j = int(scanner.real-0.5) if scanner.nexttok() != "IHREAL": huh() return w2.i = int(scanner.real-0.5) else: if game.quadrant.j>w1.i: w2.i = 0 else: w2.i=QUADSIZE-1 if game.quadrant.i>w1.j: w2.j = 0 else: w2.j=QUADSIZE-1 if not w1.valid_quadrant() or not w2.valid_sector(): huh() return dist = math.sqrt((w1.j-game.quadrant.j+(w2.j-game.sector.j)/(QUADSIZE*1.0))**2+ (w1.i-game.quadrant.i+(w2.i-game.sector.i)/(QUADSIZE*1.0))**2) wfl = False if prompt: prout(_("Answer \"no\" if you don't know the value:")) while True: scanner.chew() proutn(_("Time or arrival date? ")) if scanner.nexttok()=="IHREAL": ttime = scanner.real if ttime > game.state.date: ttime -= game.state.date # Actually a star date twarp=(math.floor(math.sqrt((10.0*dist)/ttime)*10.0)+1.0)/10.0 if ttime <= 1e-10 or twarp > 10: prout(_("We'll never make it, sir.")) scanner.chew() return if twarp < 1.0: twarp = 1.0 break scanner.chew() proutn(_("Warp factor? ")) if scanner.nexttok()== "IHREAL": wfl = True twarp = scanner.real if twarp<1.0 or twarp > 10.0: huh() return break prout(_("Captain, certainly you can give me one of these.")) while True: scanner.chew() ttime = (10.0*dist)/twarp**2 tpower = dist*twarp*twarp*twarp*(game.shldup+1) if tpower >= game.energy: prout(_("Insufficient energy, sir.")) if not game.shldup or tpower > game.energy*2.0: if not wfl: return proutn(_("New warp factor to try? ")) if scanner.nexttok() == "IHREAL": wfl = True twarp = scanner.real if twarp<1.0 or twarp > 10.0: huh() return continue else: scanner.chew() skip(1) return prout(_("But if you lower your shields,")) proutn(_("remaining")) tpower /= 2 else: proutn(_("Remaining")) prout(_(" energy will be %.2f.") % (game.energy-tpower)) if wfl: prout(_("And we will arrive at stardate %.2f.") % (game.state.date+ttime)) elif twarp==1.0: prout(_("Any warp speed is adequate.")) else: prout(_("Minimum warp needed is %.2f,") % (twarp)) prout(_("and we will arrive at stardate %.2f.") % (game.state.date+ttime)) if game.state.remtime < ttime: prout(_("Unfortunately, the Federation will be destroyed by then.")) if twarp > 6.0: prout(_("You'll be taking risks at that speed, Captain")) if (game.isatb==1 and game.state.kscmdr == w1 and \ scheduled(FSCDBAS)< ttime+game.state.date) or \ (scheduled(FCDBAS) 10.0: huh() return else: scanner.chew() skip(1) return # Code from setup.c begins here def prelim(): "Issue a historically correct banner." skip(2) prout(_("-SUPER- STAR TREK")) skip(1) # From the FORTRAN original # prout(_("Latest update-21 Sept 78")) # skip(1) def freeze(boss): "Save game." if boss: scanner.push("emsave.trk") key = scanner.nexttok() if key == "IHEOL": proutn(_("File name: ")) key = scanner.nexttok() if key != "IHALPHA": huh() return if '.' not in scanner.token: scanner.token += ".trk" try: fp = open(scanner.token, "wb") except IOError: prout(_("Can't freeze game as file %s") % scanner.token) return pickle.dump(game, fp) fp.close() scanner.chew() def thaw(): "Retrieve saved game." global game game.passwd = None key = scanner.nexttok() if key == "IHEOL": proutn(_("File name: ")) key = scanner.nexttok() if key != "IHALPHA": huh() return True if '.' not in scanner.token: scanner.token += ".trk" try: fp = open(scanner.token, "rb") except IOError: prout(_("Can't thaw game in %s") % scanner.token) return game = pickle.load(fp) fp.close() scanner.chew() return False # I used to find planets # with references in ST:TOS. Earth and the Alpha Centauri # Colony have been omitted. # # Some planets marked Class G and P here will be displayed as class M # because of the way planets are generated. This is a known bug. systnames = ( # Federation Worlds _("Andoria (Fesoan)"), # several episodes _("Tellar Prime (Miracht)"), # TOS: "Journey to Babel" _("Vulcan (T'Khasi)"), # many episodes _("Medusa"), # TOS: "Is There in Truth No Beauty?" _("Argelius II (Nelphia)"), # TOS: "Wolf in the Fold" ("IV" in BSD) _("Ardana"), # TOS: "The Cloud Minders" _("Catulla (Cendo-Prae)"), # TOS: "The Way to Eden" _("Gideon"), # TOS: "The Mark of Gideon" _("Aldebaran III"), # TOS: "The Deadly Years" _("Alpha Majoris I"), # TOS: "Wolf in the Fold" _("Altair IV"), # TOS: "Amok Time _("Ariannus"), # TOS: "Let That Be Your Last Battlefield" _("Benecia"), # TOS: "The Conscience of the King" _("Beta Niobe I (Sarpeidon)"), # TOS: "All Our Yesterdays" _("Alpha Carinae II"), # TOS: "The Ultimate Computer" _("Capella IV (Kohath)"), # TOS: "Friday's Child" (Class G) _("Daran V"), # TOS: "For the World is Hollow and I Have Touched the Sky" _("Deneb II"), # TOS: "Wolf in the Fold" ("IV" in BSD) _("Eminiar VII"), # TOS: "A Taste of Armageddon" _("Gamma Canaris IV"), # TOS: "Metamorphosis" _("Gamma Tranguli VI (Vaalel)"), # TOS: "The Apple" _("Ingraham B"), # TOS: "Operation: Annihilate" _("Janus IV"), # TOS: "The Devil in the Dark" _("Makus III"), # TOS: "The Galileo Seven" _("Marcos XII"), # TOS: "And the Children Shall Lead", _("Omega IV"), # TOS: "The Omega Glory" _("Regulus V"), # TOS: "Amok Time _("Deneva"), # TOS: "Operation -- Annihilate!" # Worlds from BSD Trek _("Rigel II"), # TOS: "Shore Leave" ("III" in BSD) _("Beta III"), # TOS: "The Return of the Archons" _("Triacus"), # TOS: "And the Children Shall Lead", _("Exo III"), # TOS: "What Are Little Girls Made Of?" (Class P) # # Others # _("Hansen's Planet"), # TOS: "The Galileo Seven" # _("Taurus IV"), # TOS: "The Galileo Seven" (class G) # _("Antos IV (Doraphane)"), # TOS: "Whom Gods Destroy", "Who Mourns for Adonais?" # _("Izar"), # TOS: "Whom Gods Destroy" # _("Tiburon"), # TOS: "The Way to Eden" # _("Merak II"), # TOS: "The Cloud Minders" # _("Coridan (Desotriana)"), # TOS: "Journey to Babel" # _("Iotia"), # TOS: "A Piece of the Action" ) device = ( _("S. R. Sensors"), \ _("L. R. Sensors"), \ _("Phasers"), \ _("Photon Tubes"), \ _("Life Support"), \ _("Warp Engines"), \ _("Impulse Engines"), \ _("Shields"), \ _("Subspace Radio"), \ _("Shuttle Craft"), \ _("Computer"), \ _("Navigation System"), \ _("Transporter"), \ _("Shield Control"), \ _("Death Ray"), \ _("D. S. Probe"), \ ) def setup(): "Prepare to play, set up cosmos." w = Coord() # Decide how many of everything if choose(): return # frozen game # Prepare the Enterprise game.alldone = game.gamewon = game.shldchg = game.shldup = False game.ship = 'E' game.state.crew = FULLCREW game.energy = game.inenrg = 5000.0 game.shield = game.inshld = 2500.0 game.inlsr = 4.0 game.lsupres = 4.0 game.quadrant = randplace(GALSIZE) game.sector = randplace(QUADSIZE) game.torps = game.intorps = 10 game.nprobes = randrange(2, 5) game.warpfac = 5.0 for i in range(NDEVICES): game.damage[i] = 0.0 # Set up assorted game parameters 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 = 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 game.instar = 0 for i in range(GALSIZE): for j in range(GALSIZE): # Can't have more stars per quadrant than fit in one decimal digit, # if we do the chart representation will break. k = randrange(1, min(10, QUADSIZE**2/10)) game.instar += k game.state.galaxy[i][j].stars = k # Locate star bases in galaxy if game.idebug: prout("=== Allocating %d bases" % game.inbase) for i in range(game.inbase): while True: while True: w = randplace(GALSIZE) if not game.state.galaxy[w.i][w.j].starbase: break contflag = False # C version: for (j = i-1; j > 0; j--) # so it did them in the opposite order. for j in range(1, i): # Improved placement algorithm to spread out bases distq = (w - game.state.baseq[j]).distance() if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75): contflag = True if game.idebug: prout("=== Abandoning base #%d at %s" % (i, w)) break elif distq < 6.0 * (BASEMAX+1-game.inbase): if game.idebug: prout("=== Saving base #%d, close to #%d" % (i, j)) if not contflag: break if game.idebug: prout("=== Placing base #%d in quadrant %s" % (i, w)) game.state.baseq.append(w) game.state.galaxy[w.i][w.j].starbase = game.state.chart[w.i][w.j].starbase = True # Position ordinary Klingon Battle Cruisers krem = game.inkling klumper = 0.25*game.skill*(9.0-game.length)+1.0 if klumper > MAXKLQUAD: klumper = MAXKLQUAD while True: r = randreal() klump = (1.0 - r*r)*klumper if klump > krem: klump = krem krem -= klump while True: w = randplace(GALSIZE) if not game.state.galaxy[w.i][w.j].supernova and \ game.state.galaxy[w.i][w.j].klingons + klump <= MAXKLQUAD: break game.state.galaxy[w.i][w.j].klingons += int(klump) if krem <= 0: break # Position Klingon Commander Ships for i in range(game.incom): while True: w = randplace(GALSIZE) if not welcoming(w) or w in game.state.kcmdr: continue if (game.state.galaxy[w.i][w.j].klingons or withprob(0.25)): break game.state.galaxy[w.i][w.j].klingons += 1 game.state.kcmdr.append(w) # Locate planets in galaxy for i in range(game.inplan): while True: w = randplace(GALSIZE) if game.state.galaxy[w.i][w.j].planet == None: break new = Planet() new.quadrant = w new.crystals = "absent" if (game.options & OPTION_WORLDS) and i < NINHAB: new.pclass = "M" # All inhabited planets are class M new.crystals = "absent" new.known = "known" new.name = systnames[i] new.inhabited = True else: new.pclass = ("M", "N", "O")[randrange(0, 3)] if withprob(0.33): new.crystals = "present" new.known = "unknown" new.inhabited = False game.state.galaxy[w.i][w.j].planet = new game.state.planets.append(new) # Locate Romulans for i in range(game.state.nromrem): w = randplace(GALSIZE) game.state.galaxy[w.i][w.j].romulans += 1 # Place the Super-Commander if needed if game.state.nscrem > 0: while True: w = randplace(GALSIZE) if welcoming(w): break game.state.kscmdr = w game.state.galaxy[w.i][w.j].klingons += 1 # Initialize times for extraneous events schedule(FSNOVA, expran(0.5 * game.intime)) schedule(FTBEAM, expran(1.5 * (game.intime / len(game.state.kcmdr)))) schedule(FSNAP, randreal(1.0, 2.0)) # Force an early snapshot schedule(FBATTAK, expran(0.3*game.intime)) unschedule(FCDBAS) if game.state.nscrem: schedule(FSCMOVE, 0.2777) else: unschedule(FSCMOVE) unschedule(FSCDBAS) unschedule(FDSPROB) if (game.options & OPTION_WORLDS) and game.skill >= SKILL_GOOD: schedule(FDISTR, expran(1.0 + game.intime)) else: unschedule(FDISTR) unschedule(FENSLV) unschedule(FREPRO) # Place thing (in tournament game, we don't want one!) # New in SST2K: never place the Thing near a starbase. # This makes sense and avoids a special case in the old code. global thing if game.tourn is None: while True: thing = randplace(GALSIZE) if thing not in game.state.baseq: break skip(2) game.state.snap = False if game.skill == SKILL_NOVICE: prout(_("It is stardate %d. The Federation is being attacked by") % int(game.state.date)) prout(_("a deadly Klingon invasion force. As captain of the United")) prout(_("Starship U.S.S. Enterprise, it is your mission to seek out")) prout(_("and destroy this invasion force of %d battle cruisers.") % ((game.inkling + game.incom + game.inscom))) prout(_("You have an initial allotment of %d stardates to complete") % int(game.intime)) prout(_("your mission. As you proceed you may be given more time.")) skip(1) prout(_("You will have %d supporting starbases.") % (game.inbase)) proutn(_("Starbase locations- ")) else: prout(_("Stardate %d.") % int(game.state.date)) skip(1) prout(_("%d Klingons.") % (game.inkling + game.incom + game.inscom)) prout(_("An unknown number of Romulans.")) if game.state.nscrem: prout(_("And one (GULP) Super-Commander.")) prout(_("%d stardates.") % int(game.intime)) proutn(_("%d starbases in ") % game.inbase) for i in range(game.inbase): proutn(repr(game.state.baseq[i])) proutn(" ") skip(2) proutn(_("The Enterprise is currently in Quadrant %s") % game.quadrant) proutn(_(" Sector %s") % game.sector) skip(2) prout(_("Good Luck!")) 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 if game.neutz: # bad luck to start in a Romulan Neutral Zone attack(torps_ok=False) def choose(): "Choose your game type." while True: game.tourn = game.length = 0 game.thawed = False game.skill = SKILL_NONE scanner.chew() # if not scanner.inqueue: # Can start with command line options proutn(_("Would you like a regular, tournament, or saved game? ")) scanner.nexttok() if scanner.sees("tournament"): while scanner.nexttok() == "IHEOL": proutn(_("Type in tournament number-")) if scanner.real == 0: scanner.chew() continue # We don't want a blank entry game.tourn = int(round(scanner.real)) random.seed(scanner.real) if logfp: logfp.write("# random.seed(%d)\n" % scanner.real) break if scanner.sees("saved") or scanner.sees("frozen"): if thaw(): continue scanner.chew() if game.passwd == None: continue if not game.alldone: game.thawed = True # No plaque if not finished report() waitfor() return True if scanner.sees("regular"): break proutn(_("What is \"%s\"? ") % scanner.token) scanner.chew() while game.length==0 or game.skill==SKILL_NONE: if scanner.nexttok() == "IHALPHA": if scanner.sees("short"): game.length = 1 elif scanner.sees("medium"): game.length = 2 elif scanner.sees("long"): game.length = 4 elif scanner.sees("novice"): game.skill = SKILL_NOVICE elif scanner.sees("fair"): game.skill = SKILL_FAIR elif scanner.sees("good"): game.skill = SKILL_GOOD elif scanner.sees("expert"): game.skill = SKILL_EXPERT elif scanner.sees("emeritus"): game.skill = SKILL_EMERITUS else: proutn(_("What is \"")) proutn(scanner.token) prout("\"?") else: scanner.chew() if game.length==0: proutn(_("Would you like a Short, Medium, or Long game? ")) elif game.skill == SKILL_NONE: proutn(_("Are you a Novice, Fair, Good, Expert, or Emeritus player? ")) # Choose game options -- added by ESR for SST2K if scanner.nexttok() != "IHALPHA": scanner.chew() proutn(_("Choose your game style (plain, almy, fancy or just press enter): ")) scanner.nexttok() if scanner.sees("plain"): # Approximates the UT FORTRAN version. game.options &=~ (OPTION_THOLIAN | OPTION_PLANETS | OPTION_THINGY | OPTION_PROBE | OPTION_RAMMING | OPTION_MVBADDY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS) game.options |= OPTION_PLAIN elif scanner.sees("almy"): # Approximates Tom Almy's version. game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS) game.options |= OPTION_ALMY elif scanner.sees("fancy") or scanner.sees("\n"): pass elif len(scanner.token): proutn(_("What is \"%s\"?") % scanner.token) game.options &=~ OPTION_COLOR setpassword() if game.passwd == "debug": game.idebug = True prout("=== Debug mode enabled.") # Use parameters to generate initial values of things game.damfac = 0.5 * game.skill game.inbase = randrange(BASEMIN, BASEMAX+1) game.inplan = 0 if game.options & OPTION_PLANETS: game.inplan += randrange(int(MAXUNINHAB/2), int(MAXUNINHAB+1)) if game.options & OPTION_WORLDS: game.inplan += int(NINHAB) game.state.nromrem = game.inrom = randrange(2 *game.skill) game.state.nscrem = game.inscom = (game.skill > SKILL_FAIR) game.state.remtime = 7.0 * game.length game.intime = game.state.remtime game.state.remkl = game.inkling = 2.0*game.intime*((game.skill+1 - 2*randreal())*game.skill*0.1+.15) game.incom = min(MINCMDR, int(game.skill + 0.0625*game.inkling*randreal())) game.state.remres = (game.inkling+4*game.incom)*game.intime game.inresor = game.state.remres if game.inkling > 50: game.state.inbase += 1 return False def dropin(iquad=None): "Drop a feature on a random dot in the current quadrant." while True: w = randplace(QUADSIZE) if game.quad[w.i][w.j] == '.': break if iquad is not None: game.quad[w.i][w.j] = iquad return w def newcnd(): "Update our alert status." game.condition = "green" if game.energy < 1000.0: game.condition = "yellow" if game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons or game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans: game.condition = "red" if not game.alive: game.condition="dead" def newkling(): "Drop new Klingon into current quadrant." 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(key=lambda x: x.kdist) def newqad(): "Set up a new state of quadrant, for when we enter or re-enter it." game.justin = True game.iplnet = None game.neutz = game.inorbit = game.landed = False game.ientesc = game.iseenit = False # Create a blank quadrant game.quad = fill2d(QUADSIZE, lambda i, j: '.') if game.iscate: # Attempt to escape Super-commander, so tbeam back! game.iscate = False game.ientesc = True q = game.state.galaxy[game.quadrant.i][game.quadrant.j] # cope with supernova if q.supernova: return game.klhere = q.klingons game.irhere = q.romulans # Position Starship game.quad[game.sector.i][game.sector.j] = game.ship game.enemies = [] if q.klingons: # Position ordinary Klingons for i in range(game.klhere): newkling() # If we need a commander, promote a Klingon for cmdr in game.state.kcmdr: if cmdr == game.quadrant: e = game.enemies[game.klhere-1] game.quad[e.location.i][e.location.j] = 'C' e.power = randreal(950,1350) + 50.0*game.skill break # If we need a super-commander, promote a Klingon if game.quadrant == game.state.kscmdr: e = game.enemies[0] game.quad[e.location.i][e.location.j] = 'S' e.power = randreal(1175.0, 1575.0) + 125.0*game.skill 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) # If quadrant needs a starbase, put it in if q.starbase: game.base = dropin('B') # If quadrant needs a planet, put it in if q.planet: game.iplnet = q.planet if not q.planet.inhabited: game.plnet = dropin('P') else: game.plnet = dropin('@') # Check for condition newcnd() # Check for RNZ if game.irhere > 0 and game.klhere == 0: game.neutz = True if not damaged(DRADIO): skip(1) prout(_("LT. Uhura- \"Captain, an urgent message.")) prout(_(" I'll put it on audio.\" CLICK")) skip(1) prout(_("INTRUDER! YOU HAVE VIOLATED THE ROMULAN NEUTRAL ZONE.")) prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!")) # Put in THING if needed if thing == game.quadrant: Enemy(etype='?', loc=dropin(), power=randreal(6000,6500.0)+250.0*game.skill) if not damaged(DSRSENS): skip(1) prout(_("Mr. Spock- \"Captain, this is most unusual.")) prout(_(" Please examine your short-range scan.\"")) # Decide if quadrant needs a Tholian; lighten up if skill is low if game.options & OPTION_THOLIAN: 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() 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(etype='T', loc=w, power=randrange(100, 500) + 25.0*game.skill) # Reserve unoccupied corners if game.quad[0][0]=='.': game.quad[0][0] = 'X' if game.quad[0][QUADSIZE-1]=='.': game.quad[0][QUADSIZE-1] = 'X' if game.quad[QUADSIZE-1][0]=='.': game.quad[QUADSIZE-1][0] = 'X' if game.quad[QUADSIZE-1][QUADSIZE-1]=='.': game.quad[QUADSIZE-1][QUADSIZE-1] = 'X' sortenemies() # And finally the stars for i in range(q.stars): dropin('*') # Put in a few black holes for i in range(1, 3+1): if withprob(0.5): dropin(' ') # Take out X's in corners if Tholian present if game.tholian: if game.quad[0][0]=='X': game.quad[0][0] = '.' if game.quad[0][QUADSIZE-1]=='X': game.quad[0][QUADSIZE-1] = '.' if game.quad[QUADSIZE-1][0]=='X': game.quad[QUADSIZE-1][0] = '.' if game.quad[QUADSIZE-1][QUADSIZE-1]=='X': game.quad[QUADSIZE-1][QUADSIZE-1] = '.' def setpassword(): "Set the self-destruct password." if game.options & OPTION_PLAIN: while True: scanner.chew() proutn(_("Please type in a secret password- ")) scanner.nexttok() game.passwd = scanner.token if game.passwd != None: break else: game.passwd = "" 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), ("", 0), ] def listCommands(): "Generate a list of legal commands." prout(_("LEGAL COMMANDS ARE:")) emitted = 0 for (key, opt) in commands: if not opt or (opt & game.options): proutn("%-12s " % key) emitted += 1 if emitted % 5 == 4: skip(1) skip(1) def helpme(): "Browse on-line help." key = scanner.nexttok() while True: if key == "IHEOL": setwnd(prompt_window) proutn(_("Help on what command? ")) key = scanner.nexttok() setwnd(message_window) if key == "IHEOL": return cmds = [x[0] for x in commands] if scanner.token.upper() in cmds or scanner.token.upper() == "ABBREV": break skip(1) listCommands() key = "IHEOL" scanner.chew() skip(1) cmd = scanner.token.upper() for directory in docpath: try: fp = open(os.path.join(directory, "sst.doc"), "r") break except IOError: pass else: prout(_("Spock- \"Captain, that information is missing from the")) prout(_(" computer. You need to find sst.doc and put it somewhere")) proutn(_(" in these directories: %s") % ":".join(docpath)) prout(".\"") # This used to continue: "You need to find SST.DOC and put # it in the current directory." return while True: linebuf = fp.readline() if linebuf == '': prout(_("Spock- \"Captain, there is no information on that command.\"")) fp.close() return if linebuf[0] == '%' and linebuf[1] == '%' and linebuf[2] == ' ': linebuf = linebuf[3:].strip() if cmd.upper() == linebuf: break skip(1) prout(_("Spock- \"Captain, I've found the following information:\"")) skip(1) while True: linebuf = fp.readline() if "******" in linebuf: break proutn(linebuf) fp.close() def makemoves(): "Command-interpretation loop." while True: # command loop drawmaps(1) while True: # get a command hitme = False game.optime = game.justin = False scanner.chew() setwnd(prompt_window) clrscr() proutn("COMMAND> ") if scanner.nexttok() == "IHEOL": if game.options & OPTION_CURSES: makechart() continue elif scanner.token == "": continue game.ididit = False clrscr() setwnd(message_window) clrscr() 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 status() elif cmd == "REQUEST": # status request request() elif cmd == "LRSCAN": # long range scan lrscan(silent=False) elif cmd == "PHASERS": # phasers phasers() if game.ididit: hitme = True elif cmd in ("TORPEDO", "PHOTONS"): # photon torpedos torps() if game.ididit: hitme = True elif cmd == "MOVE": # move under warp warp(wcourse=None, involuntary=False) elif cmd == "SHIELDS": # shields doshield(shraise=False) if game.ididit: hitme = True game.shldchg = False elif cmd == "DOCK": # dock at starbase dock(True) if game.ididit: attack(torps_ok=False) elif cmd == "DAMAGES": # damage reports damagereport() elif cmd == "CHART": # chart makechart() elif cmd == "IMPULSE": # impulse impulse() elif cmd == "REST": # rest wait() if game.ididit: hitme = True elif cmd == "WARP": # warp setwarp() elif cmd == "SCORE": # score score() elif cmd == "SENSORS": # sensors sensor() elif cmd == "ORBIT": # orbit orbit() if game.ididit: hitme = True elif cmd == "TRANSPORT": # transport "beam" beam() elif cmd == "MINE": # mine mine() if game.ididit: hitme = True elif cmd == "CRYSTALS": # crystals usecrystals() if game.ididit: hitme = True elif cmd == "SHUTTLE": # shuttle shuttle() if game.ididit: hitme = True elif cmd == "PLANETS": # Planet list survey() elif cmd == "REPORT": # Game Report report() elif cmd == "COMPUTER": # use COMPUTER! eta() elif cmd == "COMMANDS": listCommands() elif cmd == "EMEXIT": # Emergency exit clrscr() # Hide screen freeze(True) # forced save raise SystemExit(1) # And quick exit elif cmd == "PROBE": probe() # Launch probe if game.ididit: hitme = True elif cmd == "ABANDON": # Abandon Ship abandon() elif cmd == "DESTRUCT": # Self Destruct selfdestruct() elif cmd == "SAVE": # Save Game freeze(False) clrscr() if game.skill > SKILL_GOOD: prout(_("WARNING--Saved games produce no plaques!")) elif cmd == "DEATHRAY": # Try a desparation measure deathray() if game.ididit: hitme = True elif cmd == "DEBUGCMD": # What do we want for debug??? debugme() elif cmd == "MAYDAY": # Call for help mayday() if game.ididit: hitme = True elif cmd == "QUIT": game.alldone = True # quit the game elif cmd == "HELP": helpme() # get help while True: if game.alldone: break # Game has ended if game.optime != 0.0: events() if game.alldone: break # Events did us in if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova: atover(False) continue if hitme and not game.justin: attack(torps_ok=True) if game.alldone: break if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova: atover(False) hitme = True continue break if game.alldone: break if game.idebug: prout("=== Ending") def cramen(type): "Emit the name of an enemy or feature." if type == 'R': s = _("Romulan") elif type == 'K': s = _("Klingon") elif type == 'C': s = _("Commander") elif type == 'S': s = _("Super-commander") elif type == '*': s = _("Star") elif type == 'P': s = _("Planet") elif type == 'B': s = _("Starbase") elif type == ' ': s = _("Black hole") elif type == 'T': s = _("Tholian") elif type == '#': s = _("Tholian web") elif type == '?': s = _("Stranger") elif type == '@': s = _("Inhabited World") else: s = "Unknown??" return s def crmena(stars, enemy, loctype, w): "Emit the name of an enemy and his location." buf = "" if stars: buf += "***" buf += cramen(enemy) + _(" at ") if loctype == "quadrant": buf += _("Quadrant ") elif loctype == "sector": buf += _("Sector ") return buf + repr(w) def crmshp(): "Emit our ship name." return{'E':_("Enterprise"),'F':_("Faerie Queene")}.get(game.ship,"Ship???") def stars(): "Emit a line of stars" prouts("******************************************************") skip(1) def expran(avrage): return -avrage*math.log(1e-7 + randreal()) def randplace(size): "Choose a random location." w = Coord() w.i = randrange(size) w.j = randrange(size) return w class sstscanner: def __init__(self): self.type = None self.token = None self.real = 0.0 self.inqueue = [] def nexttok(self): # Get a token from the user self.real = 0.0 self.token = '' # Fill the token quue if nothing here while not self.inqueue: line = cgetline() if curwnd==prompt_window: clrscr() setwnd(message_window) clrscr() if line == '': return None if not line: continue else: self.inqueue = line.lstrip().split() + ["\n"] # From here on in it's all looking at the queue self.token = self.inqueue.pop(0) if self.token == "\n": self.type = "IHEOL" return "IHEOL" try: self.real = float(self.token) self.type = "IHREAL" return "IHREAL" except ValueError: pass # Treat as alpha self.token = self.token.lower() self.type = "IHALPHA" self.real = None return "IHALPHA" def append(self, tok): self.inqueue.append(tok) def push(self, tok): self.inqueue.insert(0, tok) def waiting(self): return self.inqueue def chew(self): # Demand input for next scan self.inqueue = [] self.real = self.token = None def sees(self, s): # compares s to item and returns true if it matches to the length of s return s.startswith(self.token) def int(self): # Round token value to nearest integer return int(round(scanner.real)) def getcoord(self): s = Coord() scanner.nexttok() if scanner.type != "IHREAL": huh() return None s.i = scanner.int()-1 scanner.nexttok() if scanner.type != "IHREAL": huh() return None s.j = scanner.int()-1 return s def __repr__(self): return "" % (scanner.token, scanner.type, scanner.inqueue) def ja(): "Yes-or-no confirmation." scanner.chew() while True: scanner.nexttok() if scanner.token == 'y': return True if scanner.token == 'n': return False scanner.chew() proutn(_("Please answer with \"y\" or \"n\": ")) def huh(): "Complain about unparseable input." scanner.chew() skip(1) prout(_("Beg your pardon, Captain?")) def debugme(): "Access to the internals for debugging." proutn("Reset levels? ") 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(): for i in range(NDEVICES): if game.damage[i] > 0.0: game.damage[i] = 0.0 proutn("Toggle debug flag? ") 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(): for i in range(NDEVICES): proutn("Kill %s?" % device[i]) scanner.chew() key = scanner.nexttok() if key == "IHALPHA" and scanner.sees("y"): game.damage[i] = 10.0 proutn("Examine/change events? ") if ja(): ev = Event() w = Coord() legends = { FSNOVA: "Supernova ", FTBEAM: "T Beam ", FSNAP: "Snapshot ", FBATTAK: "Base Attack ", FCDBAS: "Base Destroy ", FSCMOVE: "SC Move ", FSCDBAS: "SC Base Destroy ", FDSPROB: "Probe Move ", FDISTR: "Distress Call ", FENSLV: "Enslavement ", FREPRO: "Klingon Build ", } for i in range(1, NEVENTS): proutn(legends[i]) if is_scheduled(i): proutn("%.2f" % (scheduled(i)-game.state.date)) if i == FENSLV or i == FREPRO: ev = findevent(i) proutn(" in %s" % ev.quadrant) else: proutn("never") proutn("? ") scanner.chew() key = scanner.nexttok() if key == 'n': unschedule(i) scanner.chew() elif key == "IHREAL": ev = schedule(i, scanner.real) if i == FENSLV or i == FREPRO: scanner.chew() proutn("In quadrant- ") key = scanner.nexttok() # "IHEOL" says to leave coordinates as they are if key != "IHEOL": if key != "IHREAL": prout("Event %d canceled, no x coordinate." % (i)) unschedule(i) continue w.i = int(round(scanner.real)) key = scanner.nexttok() if key != "IHREAL": prout("Event %d canceled, no y coordinate." % (i)) unschedule(i) continue w.j = int(round(scanner.real)) ev.quadrant = w scanner.chew() proutn("Induce supernova here? ") 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 game = None 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:txV") replay = False for (switch, val) in options: if switch == '-r': try: replayfp = open(val, "r") except IOError: sys.stderr.write("sst: can't open replay file %s\n" % val) raise SystemExit(1) try: line = replayfp.readline().strip() (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) game.options |= OPTION_TTY game.options &=~ OPTION_CURSES elif switch == '-s': seed = int(val) elif switch == '-t': game.options |= OPTION_TTY game.options &=~ OPTION_CURSES elif switch == '-x': 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) # where to save the input in case of bugs if "TMPDIR" in os.environ: tmpdir = os.environ['TMPDIR'] else: tmpdir = "/tmp" try: logfp = open(os.path.join(tmpdir, "sst-input.log"), "w") except IOError: sys.stderr.write("sst: warning, can't open logfile\n") sys.exit(1) 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) scanner = sstscanner() for arg in arguments: scanner.append(arg) try: iostart() while True: # Play a game setwnd(fullscreen_window) clrscr() prelim() setup() if game.alldone: score() 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(): scanner.chew() scanner.push("\n") freeze(False) scanner.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.")) finally: ioend() raise SystemExit(0) except KeyboardInterrupt: if logfp: logfp.close() print("") # End.