3 sst.py -- Super Star Trek 2K
5 SST2K is a Python translation of a C translation of a FORTRAN
6 original dating back to 1973. Beautiful Python it is not, but it
7 works. Translation by Eric S. Raymond; original game by David Matuszek
8 and Paul Reynolds, with modifications by Don Smith, Tom Almy,
9 Stas Sergeev, and Eric S. Raymond.
11 See the doc/HACKING file in the distribution for designers notes and advice
12 on how to modify (and how not to modify!) this code.
14 import os, sys, math, curses, time, pickle, random, copy, gettext, getpass
16 # This import only works on Unixes. The intention is to enable
17 # Ctrl-P, Ctrl-N, and friends in Cmd.
25 docpath = (".", "../doc", "/usr/share/doc/sst")
28 return gettext.gettext(st)
30 GALSIZE = 8 # Galaxy size in quadrants
31 NINHAB = (GALSIZE * GALSIZE // 2) # Number of inhabited worlds
32 MAXUNINHAB = 10 # Maximum uninhabited worlds
33 QUADSIZE = 10 # Quadrant size in sectors
34 BASEMIN = 2 # Minimum starbases
35 BASEMAX = (GALSIZE * GALSIZE // 12) # Maximum starbases
36 MAXKLGAME = 127 # Maximum Klingons per game
37 MAXKLQUAD = 9 # Maximum Klingons per quadrant
38 FULLCREW = 428 # Crew size. BSD Trek was 387, that's wrong
39 FOREVER = 1e30 # Time for the indefinite future
40 MAXBURST = 3 # Max # of torps you can launch in one turn
41 MINCMDR = 10 # Minimum number of Klingon commanders
42 DOCKFAC = 0.25 # Repair faster when docked
43 PHASEFAC = 2.0 # Unclear what this is, it was in the C version
63 class TrekError(Exception):
66 class JumpOut(Exception):
70 def __init__(self, x=None, y=None):
73 def valid_quadrant(self):
74 return self.i >= 0 and self.i < GALSIZE and self.j >= 0 and self.j < GALSIZE
75 def valid_sector(self):
76 return self.i >= 0 and self.i < QUADSIZE and self.j >= 0 and self.j < QUADSIZE
78 self.i = self.j = None
80 return self.i != None and self.j != None
81 def __eq__(self, other):
82 return other != None and self.i == other.i and self.j == other.j
83 def __ne__(self, other):
84 return other is None or self.i != other.i or self.j != other.j
85 def __add__(self, other):
86 return Coord(self.i+other.i, self.j+other.j)
87 def __sub__(self, other):
88 return Coord(self.i-other.i, self.j-other.j)
89 def __mul__(self, other):
90 return Coord(self.i*other, self.j*other)
91 def __rmul__(self, other):
92 return Coord(self.i*other, self.j*other)
93 def __div__(self, other):
94 return Coord(self.i/other, self.j/other)
95 def __mod__(self, other):
96 return Coord(self.i % other, self.j % other)
97 def __rdiv__(self, other):
98 return Coord(self.i/other, self.j/other)
99 def roundtogrid(self):
100 return Coord(int(round(self.i)), int(round(self.j)))
101 def distance(self, other=None):
104 return math.sqrt((self.i - other.i)**2 + (self.j - other.j)**2)
106 return 1.90985*math.atan2(self.j, self.i)
112 s.i = self.i / abs(self.i)
116 s.j = self.j / abs(self.j)
119 #print "Location %s -> %s" % (self, (self / QUADSIZE).roundtogrid())
120 return self.roundtogrid() / QUADSIZE
122 return self.roundtogrid() % QUADSIZE
125 s.i = self.i + randrange(-1, 2)
126 s.j = self.j + randrange(-1, 2)
129 if self.i is None or self.j is None:
131 return "%s - %s" % (self.i+1, self.j+1)
135 "Do not anger the Space Thingy!"
142 return (q.i, q.j) == (self.i, self.j)
146 self.name = None # string-valued if inhabited
147 self.quadrant = Coord() # quadrant located
148 self.pclass = None # could be ""M", "N", "O", or "destroyed"
149 self.crystals = "absent"# could be "mined", "present", "absent"
150 self.known = "unknown" # could be "unknown", "known", "shuttle_down"
151 self.inhabited = False # is it inhabited?
159 self.starbase = False
162 self.supernova = False
164 self.status = "secure" # Could be "secure", "distressed", "enslaved"
169 self.starbase = False
172 return "<%s,%s,%s>" % (self.klingons, self.starbase, self.stars)
174 def fill2d(size, fillfun):
175 "Fill an empty list in 2D."
177 for i in range(size):
179 for j in range(size):
180 lst[i].append(fillfun(i, j))
185 self.snap = False # snapshot taken
186 self.crew = 0 # crew complement
187 self.remkl = 0 # remaining klingons
188 self.nscrem = 0 # remaining super commanders
189 self.starkl = 0 # destroyed stars
190 self.basekl = 0 # destroyed bases
191 self.nromrem = 0 # Romulans remaining
192 self.nplankl = 0 # destroyed uninhabited planets
193 self.nworldkl = 0 # destroyed inhabited planets
194 self.planets = [] # Planet information
195 self.date = 0.0 # stardate
196 self.remres = 0 # remaining resources
197 self.remtime = 0 # remaining time
198 self.baseq = [] # Base quadrant coordinates
199 self.kcmdr = [] # Commander quadrant coordinates
200 self.kscmdr = Coord() # Supercommander quadrant coordinates
202 self.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
204 self.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
208 self.date = None # A real number
209 self.quadrant = None # A coord structure
212 OPTION_ALL = 0xffffffff
213 OPTION_TTY = 0x00000001 # old interface
214 OPTION_CURSES = 0x00000002 # new interface
215 OPTION_IOMODES = 0x00000003 # cover both interfaces
216 OPTION_PLANETS = 0x00000004 # planets and mining
217 OPTION_THOLIAN = 0x00000008 # Tholians and their webs (UT 1979 version)
218 OPTION_THINGY = 0x00000010 # Space Thingy can shoot back (Stas, 2005)
219 OPTION_PROBE = 0x00000020 # deep-space probes (DECUS version, 1980)
220 OPTION_SHOWME = 0x00000040 # bracket Enterprise in chart
221 OPTION_RAMMING = 0x00000080 # enemies may ram Enterprise (Almy)
222 OPTION_MVBADDY = 0x00000100 # more enemies can move (Almy)
223 OPTION_BLKHOLE = 0x00000200 # black hole may timewarp you (Stas, 2005)
224 OPTION_BASE = 0x00000400 # bases have good shields (Stas, 2005)
225 OPTION_WORLDS = 0x00000800 # logic for inhabited worlds (ESR, 2006)
226 OPTION_AUTOSCAN = 0x00001000 # automatic LRSCAN before CHART (ESR, 2006)
227 OPTION_PLAIN = 0x01000000 # user chose plain game
228 OPTION_ALMY = 0x02000000 # user chose Almy variant
229 OPTION_COLOR = 0x04000000 # enable color display (experimental, ESR, 2010)
248 NDEVICES = 16 # Number of devices
258 return (game.damage[dev] != 0.0)
260 return not damaged(DRADIO) or game.condition=="docked"
262 # Define future events
263 FSPY = 0 # Spy event happens always (no future[] entry)
264 # can cause SC to tractor beam Enterprise
265 FSNOVA = 1 # Supernova
266 FTBEAM = 2 # Commander tractor beams Enterprise
267 FSNAP = 3 # Snapshot for time warp
268 FBATTAK = 4 # Commander attacks base
269 FCDBAS = 5 # Commander destroys base
270 FSCMOVE = 6 # Supercommander moves (might attack base)
271 FSCDBAS = 7 # Supercommander destroys base
272 FDSPROB = 8 # Move deep space probe
273 FDISTR = 9 # Emit distress call from an inhabited world
274 FENSLV = 10 # Inhabited word is enslaved */
275 FREPRO = 11 # Klingons build a ship in an enslaved system
278 # Abstract out the event handling -- underlying data structures will change
279 # when we implement stateful events
280 def findevent(evtype):
281 return game.future[evtype]
284 def __init__(self, etype=None, loc=None, power=None):
286 self.location = Coord()
291 self.power = power # enemy energy level
292 game.enemies.append(self)
294 motion = (loc != self.location)
295 if self.location.i is not None and self.location.j is not None:
298 game.quad[self.location.i][self.location.j] = '#'
300 game.quad[self.location.i][self.location.j] = '.'
302 self.location = copy.copy(loc)
303 game.quad[self.location.i][self.location.j] = self.type
304 self.kdist = self.kavgd = (game.sector - loc).distance()
306 self.location = Coord()
307 self.kdist = self.kavgd = None
308 game.enemies.remove(self)
311 return "<%s,%s.%f>" % (self.type, self.location, self.power) # For debugging
315 self.options = None # Game options
316 self.state = Snapshot() # A snapshot structure
317 self.snapsht = Snapshot() # Last snapshot taken for time-travel purposes
318 self.quad = None # contents of our quadrant
319 self.damage = [0.0] * NDEVICES # damage encountered
320 self.future = [] # future events
324 self.future.append(Event())
325 self.passwd = None # Self Destruct password
327 self.quadrant = None # where we are in the large
328 self.sector = None # where we are in the small
329 self.tholian = None # Tholian enemy object
330 self.base = None # position of base in current quadrant
331 self.battle = None # base coordinates being attacked
332 self.plnet = None # location of planet in quadrant
333 self.gamewon = False # Finished!
334 self.ididit = False # action taken -- allows enemy to attack
335 self.alive = False # we are alive (not killed)
336 self.justin = False # just entered quadrant
337 self.shldup = False # shields are up
338 self.shldchg = False # shield is changing (affects efficiency)
339 self.iscate = False # super commander is here
340 self.ientesc = False # attempted escape from supercommander
341 self.resting = False # rest time
342 self.icraft = False # Kirk in Galileo
343 self.landed = False # party on planet (true), on ship (false)
344 self.alldone = False # game is now finished
345 self.neutz = False # Romulan Neutral Zone
346 self.isarmed = False # probe is armed
347 self.inorbit = False # orbiting a planet
348 self.imine = False # mining
349 self.icrystl = False # dilithium crystals aboard
350 self.iseenit = False # seen base attack report
351 self.thawed = False # thawed game
352 self.condition = None # "green", "yellow", "red", "docked", "dead"
353 self.iscraft = None # "onship", "offship", "removed"
354 self.skill = None # Player skill level
355 self.inkling = 0 # initial number of klingons
356 self.inbase = 0 # initial number of bases
357 self.incom = 0 # initial number of commanders
358 self.inscom = 0 # initial number of commanders
359 self.inrom = 0 # initial number of commanders
360 self.instar = 0 # initial stars
361 self.intorps = 0 # initial/max torpedoes
362 self.torps = 0 # number of torpedoes
363 self.ship = 0 # ship type -- 'E' is Enterprise
364 self.abandoned = 0 # count of crew abandoned in space
365 self.length = 0 # length of game
366 self.klhere = 0 # klingons here
367 self.casual = 0 # causalties
368 self.nhelp = 0 # calls for help
369 self.nkinks = 0 # count of energy-barrier crossings
370 self.iplnet = None # planet # in quadrant
371 self.inplan = 0 # initial planets
372 self.irhere = 0 # Romulans in quadrant
373 self.isatb = 0 # =2 if super commander is attacking base
374 self.tourn = None # tournament number
375 self.nprobes = 0 # number of probes available
376 self.inresor = 0.0 # initial resources
377 self.intime = 0.0 # initial time
378 self.inenrg = 0.0 # initial/max energy
379 self.inshld = 0.0 # initial/max shield
380 self.inlsr = 0.0 # initial life support resources
381 self.indate = 0.0 # initial date
382 self.energy = 0.0 # energy level
383 self.shield = 0.0 # shield level
384 self.warpfac = 0.0 # warp speed
385 self.lsupres = 0.0 # life support reserves
386 self.optime = 0.0 # time taken by current operation
387 self.damfac = 0.0 # damage factor
388 self.lastchart = 0.0 # time star chart was last updated
389 self.cryprob = 0.0 # probability that crystal will work
390 self.probe = None # object holding probe course info
391 self.height = 0.0 # height of orbit around planet
392 self.score = 0.0 # overall score
393 self.perdate = 0.0 # rate of kills
394 self.idebug = False # Debugging instrumentation enabled?
395 self.statekscmdr = None # No SuperCommander coordinates yet.
397 # Stas thinks this should be (C expression):
398 # game.state.remkl + len(game.state.kcmdr) > 0 ?
399 # game.state.remres/(game.state.remkl + 4*len(game.state.kcmdr)) : 99
400 # He says the existing expression is prone to divide-by-zero errors
401 # after killing the last klingon when score is shown -- perhaps also
402 # if the only remaining klingon is SCOM.
403 self.state.remtime = self.state.remres/(self.state.remkl + 4*len(self.state.kcmdr))
429 return random.random() < p
431 def randrange(*args):
432 return random.randrange(*args)
437 v *= args[0] # from [0, args[0])
439 v = args[0] + v*(args[1]-args[0]) # from [args[0], args[1])
442 # Code from ai.c begins here
445 "Would this quadrant welcome another Klingon?"
446 return iq.valid_quadrant() and \
447 not game.state.galaxy[iq.i][iq.j].supernova and \
448 game.state.galaxy[iq.i][iq.j].klingons < MAXKLQUAD
450 def tryexit(enemy, look, irun):
451 "A bad guy attempts to bug out."
453 iq.i = game.quadrant.i+(look.i+(QUADSIZE-1))/QUADSIZE - 1
454 iq.j = game.quadrant.j+(look.j+(QUADSIZE-1))/QUADSIZE - 1
455 if not welcoming(iq):
457 if enemy.type == 'R':
458 return False # Romulans cannot escape!
460 # avoid intruding on another commander's territory
461 if enemy.type == 'C':
462 if iq in game.state.kcmdr:
464 # refuse to leave if currently attacking starbase
465 if game.battle == game.quadrant:
467 # don't leave if over 1000 units of energy
468 if enemy.power > 1000.0:
470 oldloc = copy.copy(enemy.location)
471 # handle local matters related to escape
474 if game.condition != "docked":
476 # Handle global matters related to escape
477 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
478 game.state.galaxy[iq.i][iq.j].klingons += 1
479 if enemy.type == 'S':
483 schedule(FSCMOVE, 0.2777)
485 game.state.kscmdr = iq
487 for cmdr in game.state.kcmdr:
488 if cmdr == game.quadrant:
489 game.state.kcmdr.append(iq)
491 # report move out of quadrant.
492 return [(True, enemy, oldloc, iq)]
494 # The bad-guy movement algorithm:
496 # 1. Enterprise has "force" based on condition of phaser and photon torpedoes.
497 # If both are operating full strength, force is 1000. If both are damaged,
498 # force is -1000. Having shields down subtracts an additional 1000.
500 # 2. Enemy has forces equal to the energy of the attacker plus
501 # 100*(K+R) + 500*(C+S) - 400 for novice through good levels OR
502 # 346*K + 400*R + 500*(C+S) - 400 for expert and emeritus.
504 # Attacker Initial energy levels (nominal):
505 # Klingon Romulan Commander Super-Commander
506 # Novice 400 700 1200
508 # Good 450 800 1300 1750
509 # Expert 475 850 1350 1875
510 # Emeritus 500 900 1400 2000
511 # VARIANCE 75 200 200 200
513 # Enemy vessels only move prior to their attack. In Novice - Good games
514 # only commanders move. In Expert games, all enemy vessels move if there
515 # is a commander present. In Emeritus games all enemy vessels move.
517 # 3. If Enterprise is not docked, an aggressive action is taken if enemy
518 # forces are 1000 greater than Enterprise.
520 # Agressive action on average cuts the distance between the ship and
521 # the enemy to 1/4 the original.
523 # 4. At lower energy advantage, movement units are proportional to the
524 # advantage with a 650 advantage being to hold ground, 800 to move forward
525 # 1, 950 for two, 150 for back 4, etc. Variance of 100.
527 # If docked, is reduced by roughly 1.75*game.skill, generally forcing a
528 # retreat, especially at high skill levels.
530 # 5. Motion is limited to skill level, except for SC hi-tailing it out.
532 def movebaddy(enemy):
533 "Tactical movement for the bad guys."
537 # This should probably be just (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
538 if game.skill >= SKILL_EXPERT:
539 nbaddys = (((game.quadrant in game.state.kcmdr)*2 + (game.state.kscmdr==game.quadrant)*2+game.klhere*1.23+game.irhere*1.5)/2.0)
541 nbaddys = (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
542 old_dist = enemy.kdist
543 mdist = int(old_dist + 0.5) # Nearest integer distance
544 # If SC, check with spy to see if should hi-tail it
545 if enemy.type == 'S' and \
546 (enemy.power <= 500.0 or (game.condition=="docked" and not damaged(DPHOTON))):
550 # decide whether to advance, retreat, or hold position
551 forces = enemy.power+100.0*len(game.enemies)+400*(nbaddys-1)
553 forces += 1000 # Good for enemy if shield is down!
554 if not damaged(DPHASER) or not damaged(DPHOTON):
555 if damaged(DPHASER): # phasers damaged
558 forces -= 0.2*(game.energy - 2500.0)
559 if damaged(DPHOTON): # photon torpedoes damaged
562 forces -= 50.0*game.torps
564 # phasers and photon tubes both out!
567 if forces <= 1000.0 and game.condition != "docked": # Typical situation
568 motion = ((forces + randreal(200))/150.0) - 5.0
570 if forces > 1000.0: # Very strong -- move in for kill
571 motion = (1.0 - randreal())**2 * old_dist + 1.0
572 if game.condition == "docked" and (game.options & OPTION_BASE): # protected by base -- back off !
573 motion -= game.skill*(2.0-randreal()**2)
575 proutn("=== MOTION = %d, FORCES = %1.2f, " % (motion, forces))
576 # don't move if no motion
579 # Limit motion according to skill
580 if abs(motion) > game.skill:
585 # calculate preferred number of steps
586 nsteps = abs(int(motion))
587 if motion > 0 and nsteps > mdist:
588 nsteps = mdist # don't overshoot
589 if nsteps > QUADSIZE:
590 nsteps = QUADSIZE # This shouldn't be necessary
592 nsteps = 1 # This shouldn't be necessary
594 proutn("NSTEPS = %d:" % nsteps)
595 # Compute preferred values of delta X and Y
596 m = game.sector - enemy.location
597 if 2.0 * abs(m.i) < abs(m.j):
599 if 2.0 * abs(m.j) < abs(game.sector.i-enemy.location.i):
601 m = (motion * m).sgn()
602 goto = enemy.location
604 for ll in range(nsteps):
606 proutn(" %d" % (ll+1))
607 # Check if preferred position available
618 attempts = 0 # Settle mysterious hang problem
619 while attempts < 20 and not success:
621 if look.i < 0 or look.i >= QUADSIZE:
623 return tryexit(enemy, look, irun)
624 if krawli == m.i or m.j == 0:
626 look.i = goto.i + krawli
628 elif look.j < 0 or look.j >= QUADSIZE:
630 return tryexit(enemy, look, irun)
631 if krawlj == m.j or m.i == 0:
633 look.j = goto.j + krawlj
635 elif (game.options & OPTION_RAMMING) and game.quad[look.i][look.j] != '.':
636 # See if enemy should ram ship
637 if game.quad[look.i][look.j] == game.ship and \
638 (enemy.type == 'C' or enemy.type == 'S'):
639 collision(rammed=True, enemy=enemy)
641 if krawli != m.i and m.j != 0:
642 look.i = goto.i + krawli
644 elif krawlj != m.j and m.i != 0:
645 look.j = goto.j + krawlj
648 break # we have failed
659 # Enemy moved, but is still in sector
660 return [(False, enemy, old_dist, goto)]
663 "Sequence Klingon tactical movement."
666 # Figure out which Klingon is the commander (or Supercommander)
669 if game.quadrant in game.state.kcmdr:
670 for enemy in game.enemies:
671 if enemy.type == 'C':
672 tacmoves += movebaddy(enemy)
673 if game.state.kscmdr == game.quadrant:
674 for enemy in game.enemies:
675 if enemy.type == 'S':
676 tacmoves += movebaddy(enemy)
678 # If skill level is high, move other Klingons and Romulans too!
679 # Move these last so they can base their actions on what the
681 if game.skill >= SKILL_EXPERT and (game.options & OPTION_MVBADDY):
682 for enemy in game.enemies:
683 if enemy.type in ('K', 'R'):
684 tacmoves += movebaddy(enemy)
687 def movescom(iq, avoid):
688 "Commander movement helper."
689 # Avoid quadrants with bases if we want to avoid Enterprise
690 if not welcoming(iq) or (avoid and iq in game.state.baseq):
692 if game.justin and not game.iscate:
695 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons -= 1
696 game.state.kscmdr = iq
697 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons += 1
698 if game.state.kscmdr == game.quadrant:
699 # SC has scooted, remove him from current quadrant
704 for enemy in game.enemies:
705 if enemy.type == 'S':
708 if game.condition != "docked":
711 # check for a helpful planet
712 for i in range(game.inplan):
713 if game.state.planets[i].quadrant == game.state.kscmdr and \
714 game.state.planets[i].crystals == "present":
716 game.state.planets[i].pclass = "destroyed"
717 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].planet = None
720 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
721 proutn(_(" a planet in Quadrant %s has been destroyed") % game.state.kscmdr)
722 prout(_(" by the Super-commander.\""))
724 return True # looks good!
726 def supercommander():
727 "Move the Super Commander."
734 prout("== SUPERCOMMANDER")
735 # Decide on being active or passive
736 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 \
737 (game.state.date-game.indate) < 3.0)
738 if not game.iscate and avoid:
739 # compute move away from Enterprise
740 idelta = game.state.kscmdr-game.quadrant
741 if idelta.distance() > 2.0:
743 idelta.i = game.state.kscmdr.j-game.quadrant.j
744 idelta.j = game.quadrant.i-game.state.kscmdr.i
746 # compute distances to starbases
747 if not game.state.baseq:
751 sc = game.state.kscmdr
752 for (i, base) in enumerate(game.state.baseq):
753 basetbl.append((i, (base - sc).distance()))
754 if game.state.baseq > 1:
755 basetbl.sort(key=lambda x: x[1])
756 # look for nearest base without a commander, no Enterprise, and
757 # without too many Klingons, and not already under attack.
758 ifindit = iwhichb = 0
759 for (i2, base) in enumerate(game.state.baseq):
760 i = basetbl[i2][0] # bug in original had it not finding nearest
761 if base == game.quadrant or base == game.battle or not welcoming(base):
763 # if there is a commander, and no other base is appropriate,
764 # we will take the one with the commander
765 for cmdr in game.state.kcmdr:
766 if base == cmdr and ifindit != 2:
770 else: # no commander -- use this one
775 return # Nothing suitable -- wait until next time
776 ibq = game.state.baseq[iwhichb]
777 # decide how to move toward base
778 idelta = ibq - game.state.kscmdr
779 # Maximum movement is 1 quadrant in either or both axes
780 idelta = idelta.sgn()
781 # try moving in both x and y directions
782 # there was what looked like a bug in the Almy C code here,
783 # but it might be this translation is just wrong.
784 iq = game.state.kscmdr + idelta
785 if not movescom(iq, avoid):
786 # failed -- try some other maneuvers
787 if idelta.i == 0 or idelta.j == 0:
790 iq.j = game.state.kscmdr.j + 1
791 if not movescom(iq, avoid):
792 iq.j = game.state.kscmdr.j - 1
795 iq.i = game.state.kscmdr.i + 1
796 if not movescom(iq, avoid):
797 iq.i = game.state.kscmdr.i - 1
800 # try moving just in x or y
801 iq.j = game.state.kscmdr.j
802 if not movescom(iq, avoid):
803 iq.j = game.state.kscmdr.j + idelta.j
804 iq.i = game.state.kscmdr.i
807 if len(game.state.baseq) == 0:
810 for ibq in game.state.baseq:
811 if ibq == game.state.kscmdr and game.state.kscmdr == game.battle:
814 return # no, don't attack base!
817 schedule(FSCDBAS, randreal(1.0, 3.0))
818 if is_scheduled(FCDBAS):
819 postpone(FSCDBAS, scheduled(FCDBAS)-game.state.date)
820 if not communicating():
824 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") \
826 prout(_(" reports that it is under attack from the Klingon Super-commander."))
827 proutn(_(" It can survive until stardate %d.\"") \
828 % int(scheduled(FSCDBAS)))
831 prout(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
835 game.optime = 0.0 # actually finished
837 # Check for intelligence report
838 if not game.idebug and \
840 (not communicating()) or \
841 not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].charted):
844 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
845 proutn(_(" the Super-commander is in Quadrant %s,") % game.state.kscmdr)
850 if not game.tholian or game.justin:
853 if game.tholian.location.i == 0 and game.tholian.location.j == 0:
856 elif game.tholian.location.i == 0 and game.tholian.location.j == QUADSIZE-1:
859 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == QUADSIZE-1:
862 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == 0:
866 # something is wrong!
867 game.tholian.move(None)
868 prout("***Internal error: Tholian in a bad spot.")
870 # do nothing if we are blocked
871 if game.quad[tid.i][tid.j] not in ('.', '#'):
873 here = copy.copy(game.tholian.location)
874 delta = (tid - game.tholian.location).sgn()
876 while here.i != tid.i:
878 if game.quad[here.i][here.j] == '.':
879 game.tholian.move(here)
881 while here.j != tid.j:
883 if game.quad[here.i][here.j] == '.':
884 game.tholian.move(here)
885 # check to see if all holes plugged
886 for i in range(QUADSIZE):
887 if game.quad[0][i] != '#' and game.quad[0][i] != 'T':
889 if game.quad[QUADSIZE-1][i] != '#' and game.quad[QUADSIZE-1][i] != 'T':
891 if game.quad[i][0] != '#' and game.quad[i][0] != 'T':
893 if game.quad[i][QUADSIZE-1] != '#' and game.quad[i][QUADSIZE-1] != 'T':
895 # All plugged up -- Tholian splits
896 game.quad[game.tholian.location.i][game.tholian.location.j] = '#'
898 prout(crmena(True, 'T', "sector", game.tholian) + _(" completes web."))
899 game.tholian.move(None)
902 # Code from battle.c begins here
904 def doshield(shraise):
905 "Change shield status."
911 key = scanner.nexttok()
913 if scanner.sees("transfer"):
917 prout(_("Shields damaged and down."))
919 if scanner.sees("up"):
921 elif scanner.sees("down"):
924 proutn(_("Do you wish to change shield energy? "))
927 elif damaged(DSHIELD):
928 prout(_("Shields damaged and down."))
931 proutn(_("Shields are up. Do you want them down? "))
938 proutn(_("Shields are down. Do you want them up? "))
944 if action == "SHUP": # raise shields
946 prout(_("Shields already up."))
950 if game.condition != "docked":
952 prout(_("Shields raised."))
955 prout(_("Shields raising uses up last of energy."))
960 elif action == "SHDN":
962 prout(_("Shields already down."))
966 prout(_("Shields lowered."))
969 elif action == "NRG":
970 while scanner.nexttok() != "IHREAL":
972 proutn(_("Energy to transfer to shields- "))
977 if nrg > game.energy:
978 prout(_("Insufficient ship energy."))
981 if game.shield+nrg >= game.inshld:
982 prout(_("Shield energy maximized."))
983 if game.shield+nrg > game.inshld:
984 prout(_("Excess energy requested returned to ship energy"))
985 game.energy -= game.inshld-game.shield
986 game.shield = game.inshld
988 if nrg < 0.0 and game.energy-nrg > game.inenrg:
989 # Prevent shield drain loophole
991 prout(_("Engineering to bridge--"))
992 prout(_(" Scott here. Power circuit problem, Captain."))
993 prout(_(" I can't drain the shields."))
996 if game.shield+nrg < 0:
997 prout(_("All shield energy transferred to ship."))
998 game.energy += game.shield
1001 proutn(_("Scotty- \""))
1003 prout(_("Transferring energy to shields.\""))
1005 prout(_("Draining energy from shields.\""))
1011 "Choose a device to damage, at random."
1013 105, # DSRSENS: short range scanners 10.5%
1014 105, # DLRSENS: long range scanners 10.5%
1015 120, # DPHASER: phasers 12.0%
1016 120, # DPHOTON: photon torpedoes 12.0%
1017 25, # DLIFSUP: life support 2.5%
1018 65, # DWARPEN: warp drive 6.5%
1019 70, # DIMPULS: impulse engines 6.5%
1020 145, # DSHIELD: deflector shields 14.5%
1021 30, # DRADIO: subspace radio 3.0%
1022 45, # DSHUTTL: shuttle 4.5%
1023 15, # DCOMPTR: computer 1.5%
1024 20, # NAVCOMP: navigation system 2.0%
1025 75, # DTRANSP: transporter 7.5%
1026 20, # DSHCTRL: high-speed shield controller 2.0%
1027 10, # DDRAY: death ray 1.0%
1028 30, # DDSP: deep-space probes 3.0%
1030 assert(sum(weights) == 1000)
1031 idx = randrange(1000)
1033 for (i, w) in enumerate(weights):
1037 return None # we should never get here
1039 def collision(rammed, enemy):
1040 "Collision handling for rammong events."
1041 prouts(_("***RED ALERT! RED ALERT!"))
1043 prout(_("***COLLISION IMMINENT."))
1047 hardness = {'R':1.5, 'C':2.0, 'S':2.5, 'T':0.5, '?':4.0}.get(enemy.type, 1.0)
1049 proutn(_(" rammed by "))
1052 proutn(crmena(False, enemy.type, "sector", enemy.location))
1054 proutn(_(" (original position)"))
1056 deadkl(enemy.location, enemy.type, game.sector)
1057 proutn("***" + crmshp() + " heavily damaged.")
1058 icas = randrange(10, 30)
1059 prout(_("***Sickbay reports %d casualties") % icas)
1061 game.state.crew -= icas
1062 # In the pre-SST2K version, all devices got equiprobably damaged,
1063 # which was silly. Instead, pick up to half the devices at
1064 # random according to our weighting table,
1065 ncrits = randrange(NDEVICES/2)
1069 if game.damage[dev] < 0:
1071 extradm = (10.0*hardness*randreal()+1.0)*game.damfac
1072 # Damage for at least time of travel!
1073 game.damage[dev] += game.optime + extradm
1075 prout(_("***Shields are down."))
1076 if game.state.remkl + len(game.state.kcmdr) + game.state.nscrem:
1083 def torpedo(origin, bearing, dispersion, number, nburst):
1084 "Let a photon torpedo fly"
1085 if not damaged(DSRSENS) or game.condition == "docked":
1086 setwnd(srscan_window)
1088 setwnd(message_window)
1089 ac = bearing + 0.25*dispersion # dispersion is a random variable
1090 bullseye = (15.0 - bearing)*0.5235988
1091 track = course(bearing=ac, distance=QUADSIZE, origin=cartesian(origin))
1092 bumpto = Coord(0, 0)
1093 # Loop to move a single torpedo
1094 setwnd(message_window)
1095 for step in range(1, QUADSIZE*2):
1096 if not track.nexttok():
1099 if not w.valid_sector():
1101 iquad = game.quad[w.i][w.j]
1102 tracktorpedo(w, step, number, nburst, iquad)
1106 setwnd(message_window)
1107 if not damaged(DSRSENS) or game.condition == "docked":
1108 skip(1) # start new line after text track
1109 if iquad in ('E', 'F'): # Hit our ship
1111 prout(_("Torpedo hits %s.") % crmshp())
1112 hit = 700.0 + randreal(100) - \
1113 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1114 newcnd() # we're blown out of dock
1115 if game.landed or game.condition == "docked":
1116 return hit # Cheat if on a planet
1117 # In the C/FORTRAN version, dispersion was 2.5 radians, which
1118 # is 143 degrees, which is almost exactly 4.8 clockface units
1119 displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
1120 displacement.nexttok()
1121 bumpto = displacement.sector()
1122 if not bumpto.valid_sector():
1124 if game.quad[bumpto.i][bumpto.j] == ' ':
1127 if game.quad[bumpto.i][bumpto.j] != '.':
1128 # can't move into object
1130 game.sector = bumpto
1132 game.quad[w.i][w.j] = '.'
1133 game.quad[bumpto.i][bumpto.j] = iquad
1134 prout(_(" displaced by blast to Sector %s ") % bumpto)
1135 for enemy in game.enemies:
1136 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1139 elif iquad in ('C', 'S', 'R', 'K'): # Hit a regular enemy
1141 if iquad in ('C', 'S') and withprob(0.05):
1142 prout(crmena(True, iquad, "sector", w) + _(" uses anti-photon device;"))
1143 prout(_(" torpedo neutralized."))
1145 for enemy in game.enemies:
1146 if w == enemy.location:
1147 kp = math.fabs(enemy.power)
1148 h1 = 700.0 + randrange(100) - \
1149 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1157 if enemy.power == 0:
1160 proutn(crmena(True, iquad, "sector", w))
1161 displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
1162 displacement.nexttok()
1163 bumpto = displacement.sector()
1164 if not bumpto.valid_sector():
1165 prout(_(" damaged but not destroyed."))
1167 if game.quad[bumpto.i][bumpto.j] == ' ':
1168 prout(_(" buffeted into black hole."))
1169 deadkl(w, iquad, bumpto)
1170 if game.quad[bumpto.i][bumpto.j] != '.':
1171 prout(_(" damaged but not destroyed."))
1173 prout(_(" damaged-- displaced by blast to Sector %s ")%bumpto)
1174 enemy.location = bumpto
1175 game.quad[w.i][w.j] = '.'
1176 game.quad[bumpto.i][bumpto.j] = iquad
1177 for enemy in game.enemies:
1178 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1182 prout("Internal error, no enemy where expected!")
1185 elif iquad == 'B': # Hit a base
1187 prout(_("***STARBASE DESTROYED.."))
1188 game.state.baseq = [x for x in game.state.baseq if x != game.quadrant]
1189 game.quad[w.i][w.j] = '.'
1190 game.base.invalidate()
1191 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
1192 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = False
1193 game.state.basekl += 1
1196 elif iquad == 'P': # Hit a planet
1197 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1198 game.state.nplankl += 1
1199 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1200 game.iplnet.pclass = "destroyed"
1202 game.plnet.invalidate()
1203 game.quad[w.i][w.j] = '.'
1205 # captain perishes on planet
1208 elif iquad == '@': # Hit an inhabited world -- very bad!
1209 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1210 game.state.nworldkl += 1
1211 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1212 game.iplnet.pclass = "destroyed"
1214 game.plnet.invalidate()
1215 game.quad[w.i][w.j] = '.'
1217 # captain perishes on planet
1219 prout(_("The torpedo destroyed an inhabited planet."))
1221 elif iquad == '*': # Hit a star
1225 prout(crmena(True, '*', "sector", w) + _(" unaffected by photon blast."))
1227 elif iquad == '?': # Hit a thingy
1228 if not (game.options & OPTION_THINGY) or withprob(0.3):
1230 prouts(_("AAAAIIIIEEEEEEEEAAAAAAAAUUUUUGGGGGHHHHHHHHHHHH!!!"))
1232 prouts(_(" HACK! HACK! HACK! *CHOKE!* "))
1234 proutn(_("Mr. Spock-"))
1235 prouts(_(" \"Fascinating!\""))
1239 # Stas Sergeev added the possibility that
1240 # you can shove the Thingy and piss it off.
1241 # It then becomes an enemy and may fire at you.
1244 elif iquad == ' ': # Black hole
1246 prout(crmena(True, ' ', "sector", w) + _(" swallows torpedo."))
1248 elif iquad == '#': # hit the web
1250 prout(_("***Torpedo absorbed by Tholian web."))
1252 elif iquad == 'T': # Hit a Tholian
1253 h1 = 700.0 + randrange(100) - \
1254 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1257 game.quad[w.i][w.j] = '.'
1262 proutn(crmena(True, 'T', "sector", w))
1264 prout(_(" survives photon blast."))
1266 prout(_(" disappears."))
1267 game.tholian.move(None)
1268 game.quad[w.i][w.j] = '#'
1273 proutn("Don't know how to handle torpedo collision with ")
1274 proutn(crmena(True, iquad, "sector", w))
1279 setwnd(message_window)
1280 prout(_("Torpedo missed."))
1284 "Critical-hit resolution."
1285 if hit < (275.0-25.0*game.skill)*randreal(1.0, 1.5):
1287 ncrit = int(1.0 + hit/(500.0+randreal(100)))
1288 proutn(_("***CRITICAL HIT--"))
1289 # Select devices and cause damage
1294 # Cheat to prevent shuttle damage unless on ship
1295 if not (game.damage[j]<0.0 or (j == DSHUTTL and game.iscraft != "onship")):
1298 extradm = (hit*game.damfac)/(ncrit*randreal(75, 100))
1299 game.damage[j] += extradm
1302 for (i, j) in enumerate(cdam):
1304 if skipcount % 3 == 2 and i < len(cdam)-1:
1309 prout(_(" damaged."))
1310 if damaged(DSHIELD) and game.shldup:
1311 prout(_("***Shields knocked down."))
1314 def attack(torps_ok):
1315 # bad guy attacks us
1316 # torps_ok == False forces use of phasers in an attack
1317 # game could be over at this point, check
1327 prout("=== ATTACK!")
1328 # Tholian gets to move before attacking
1331 # if you have just entered the RNZ, you'll get a warning
1332 if game.neutz: # The one chance not to be attacked
1335 # commanders get a chance to tac-move towards you
1336 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:
1337 for (bugout, enemy, old, goto) in moveklings():
1339 # we know about this if either short or long range
1340 # sensors are working
1341 if damaged(DSRSENS) and damaged(DLRSENS) \
1342 and game.condition != "docked":
1343 prout(crmena(True, enemy.type, "sector", old) + \
1344 (_(" escapes to Quadrant %s (and regains strength).") % goto))
1345 else: # Enemy still in-sector
1346 if enemy.move(goto):
1347 if not damaged(DSRSENS) or game.condition == "docked":
1348 proutn(_("*** %s from Sector %s") % (cramen(enemy.type), enemy.location))
1349 if enemy.kdist < old:
1350 proutn(_(" advances to "))
1352 proutn(_(" retreats to "))
1353 prout("Sector %s." % goto)
1355 # if no enemies remain after movement, we're done
1356 if len(game.enemies) == 0 or (len(game.enemies) == 1 and thing.at(game.quadrant) and not thing.angered):
1358 # set up partial hits if attack happens during shield status change
1359 pfac = 1.0/game.inshld
1361 chgfac = 0.25 + randreal(0.5)
1363 # message verbosity control
1364 if game.skill <= SKILL_FAIR:
1366 for enemy in game.enemies:
1368 continue # too weak to attack
1369 # compute hit strength and diminish shield power
1371 # Increase chance of photon torpedos if docked or enemy energy is low
1372 if game.condition == "docked":
1374 if enemy.power < 500:
1376 if enemy.type == 'T' or (enemy.type == '?' and not thing.angered):
1378 # different enemies have different probabilities of throwing a torp
1379 usephasers = not torps_ok or \
1380 (enemy.type == 'K' and r > 0.0005) or \
1381 (enemy.type == 'C' and r > 0.015) or \
1382 (enemy.type == 'R' and r > 0.3) or \
1383 (enemy.type == 'S' and r > 0.07) or \
1384 (enemy.type == '?' and r > 0.05)
1385 if usephasers: # Enemy uses phasers
1386 if game.condition == "docked":
1387 continue # Don't waste the effort!
1388 attempt = True # Attempt to attack
1389 dustfac = randreal(0.8, 0.85)
1390 hit = enemy.power*math.pow(dustfac, enemy.kavgd)
1392 else: # Enemy uses photon torpedo
1393 # We should be able to make the bearing() method work here
1394 pcourse = 1.90985*math.atan2(game.sector.j-enemy.location.j, enemy.location.i-game.sector.i)
1396 proutn(_("***TORPEDO INCOMING"))
1397 if not damaged(DSRSENS):
1398 proutn(_(" From ") + crmena(False, enemy.type, where, enemy.location))
1401 dispersion = (randreal()+randreal())*0.5 - 0.5
1402 dispersion += 0.002*enemy.power*dispersion
1403 hit = torpedo(enemy.location, pcourse, dispersion, number=1, nburst=1)
1404 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
1405 finish(FWON) # Klingons did themselves in!
1406 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.alldone:
1407 return # Supernova or finished
1410 # incoming phaser or torpedo, shields may dissipate it
1411 if game.shldup or game.shldchg or game.condition == "docked":
1412 # shields will take hits
1413 propor = pfac * game.shield
1414 if game.condition == "docked":
1418 hitsh = propor*chgfac*hit+1.0
1420 if absorb > game.shield:
1421 absorb = game.shield
1422 game.shield -= absorb
1424 # taking a hit blasts us out of a starbase dock
1425 if game.condition == "docked":
1427 # but the shields may take care of it
1428 if propor > 0.1 and hit < 0.005*game.energy:
1430 # hit from this opponent got through shields, so take damage
1432 proutn(_("%d unit hit") % int(hit))
1433 if (damaged(DSRSENS) and usephasers) or game.skill<=SKILL_FAIR:
1434 proutn(_(" on the ") + crmshp())
1435 if not damaged(DSRSENS) and usephasers:
1436 prout(_(" from ") + crmena(False, enemy.type, where, enemy.location))
1438 # Decide if hit is critical
1444 if game.energy <= 0:
1445 # Returning home upon your shield, not with it...
1448 if not attempt and game.condition == "docked":
1449 prout(_("***Enemies decide against attacking your ship."))
1450 percent = 100.0*pfac*game.shield+0.5
1452 # Shields fully protect ship
1453 proutn(_("Enemy attack reduces shield strength to "))
1455 # Emit message if starship suffered hit(s)
1457 proutn(_("Energy left %2d shields ") % int(game.energy))
1460 elif not damaged(DSHIELD):
1463 proutn(_("damaged, "))
1464 prout(_("%d%%, torpedoes left %d") % (percent, game.torps))
1465 # Check if anyone was hurt
1466 if hitmax >= 200 or hittot >= 500:
1467 icas = randrange(int(hittot * 0.015))
1470 prout(_("Mc Coy- \"Sickbay to bridge. We suffered %d casualties") % icas)
1471 prout(_(" in that last attack.\""))
1473 game.state.crew -= icas
1474 # After attack, reset average distance to enemies
1475 for enemy in game.enemies:
1476 enemy.kavgd = enemy.kdist
1480 def deadkl(w, etype, mv):
1481 "Kill a Klingon, Tholian, Romulan, or Thingy."
1482 # Added mv to allow enemy to "move" before dying
1483 proutn(crmena(True, etype, "sector", mv))
1484 # Decide what kind of enemy it is and update appropriately
1486 # Chalk up a Romulan
1487 game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans -= 1
1489 game.state.nromrem -= 1
1498 # Killed some type of Klingon
1499 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
1502 game.state.kcmdr.remove(game.quadrant)
1504 if game.state.kcmdr:
1505 schedule(FTBEAM, expran(1.0*game.incom/len(game.state.kcmdr)))
1506 if is_scheduled(FCDBAS) and game.battle == game.quadrant:
1509 game.state.remkl -= 1
1511 game.state.nscrem -= 1
1512 game.state.kscmdr.invalidate()
1517 # For each kind of enemy, finish message to player
1518 prout(_(" destroyed."))
1519 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
1522 # Remove enemy ship from arrays describing local conditions
1523 for e in game.enemies:
1530 "Return None if target is invalid, otherwise return a course angle."
1531 if not w.valid_sector():
1535 # C code this was translated from is wacky -- why the sign reversal?
1536 delta.j = (w.j - game.sector.j)
1537 delta.i = (game.sector.i - w.i)
1538 if delta == Coord(0, 0):
1540 prout(_("Spock- \"Bridge to sickbay. Dr. McCoy,"))
1541 prout(_(" I recommend an immediate review of"))
1542 prout(_(" the Captain's psychological profile.\""))
1545 return delta.bearing()
1548 "Launch photon torpedo salvo."
1551 if damaged(DPHOTON):
1552 prout(_("Photon tubes damaged."))
1556 prout(_("No torpedoes left."))
1559 # First, get torpedo count
1562 if scanner.token == "IHALPHA":
1565 elif scanner.token == "IHEOL" or not scanner.waiting():
1566 prout(_("%d torpedoes left.") % game.torps)
1568 proutn(_("Number of torpedoes to fire- "))
1569 continue # Go back around to get a number
1570 else: # key == "IHREAL"
1572 if n <= 0: # abort command
1577 prout(_("Maximum of %d torpedoes per burst.") % MAXBURST)
1580 scanner.chew() # User requested more torps than available
1581 continue # Go back around
1582 break # All is good, go to next stage
1586 key = scanner.nexttok()
1587 if i == 0 and key == "IHEOL":
1588 break # no coordinate waiting, we will try prompting
1589 if i == 1 and key == "IHEOL":
1590 # direct all torpedoes at one target
1592 target.append(target[0])
1593 tcourse.append(tcourse[0])
1596 scanner.push(scanner.token)
1597 target.append(scanner.getcoord())
1598 if target[-1] is None:
1600 tcourse.append(targetcheck(target[-1]))
1601 if tcourse[-1] is None:
1604 if len(target) == 0:
1605 # prompt for each one
1607 proutn(_("Target sector for torpedo number %d- ") % (i+1))
1609 target.append(scanner.getcoord())
1610 if target[-1] is None:
1612 tcourse.append(targetcheck(target[-1]))
1613 if tcourse[-1] is None:
1616 # Loop for moving <n> torpedoes
1618 if game.condition != "docked":
1620 dispersion = (randreal()+randreal())*0.5 -0.5
1621 if math.fabs(dispersion) >= 0.47:
1623 dispersion *= randreal(1.2, 2.2)
1625 prouts(_("***TORPEDO NUMBER %d MISFIRES") % (i+1))
1627 prouts(_("***TORPEDO MISFIRES."))
1630 prout(_(" Remainder of burst aborted."))
1632 prout(_("***Photon tubes damaged by misfire."))
1633 game.damage[DPHOTON] = game.damfac * randreal(1.0, 3.0)
1635 if game.shldup or game.condition == "docked":
1636 dispersion *= 1.0 + 0.0001*game.shield
1637 torpedo(game.sector, tcourse[i], dispersion, number=i, nburst=n)
1638 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
1640 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)<=0:
1644 "Check for phasers overheating."
1646 checkburn = (rpow-1500.0)*0.00038
1647 if withprob(checkburn):
1648 prout(_("Weapons officer Sulu- \"Phasers overheated, sir.\""))
1649 game.damage[DPHASER] = game.damfac* randreal(1.0, 2.0) * (1.0+checkburn)
1651 def checkshctrl(rpow):
1652 "Check shield control."
1655 prout(_("Shields lowered."))
1657 # Something bad has happened
1658 prouts(_("***RED ALERT! RED ALERT!"))
1660 hit = rpow*game.shield/game.inshld
1661 game.energy -= rpow+hit*0.8
1662 game.shield -= hit*0.2
1663 if game.energy <= 0.0:
1664 prouts(_("Sulu- \"Captain! Shield malf***********************\""))
1669 prouts(_("Sulu- \"Captain! Shield malfunction! Phaser fire contained!\""))
1671 prout(_("Lt. Uhura- \"Sir, all decks reporting damage.\""))
1672 icas = randrange(int(hit*0.012))
1677 prout(_("McCoy to bridge- \"Severe radiation burns, Jim."))
1678 prout(_(" %d casualties so far.\"") % icas)
1680 game.state.crew -= icas
1682 prout(_("Phaser energy dispersed by shields."))
1683 prout(_("Enemy unaffected."))
1688 "Register a phaser hit on Klingons and Romulans."
1695 dustfac = randreal(0.9, 1.0)
1696 hit = wham*math.pow(dustfac, game.enemies[kk].kdist)
1697 kpini = game.enemies[kk].power
1698 kp = math.fabs(kpini)
1699 if PHASEFAC*hit < kp:
1701 if game.enemies[kk].power < 0:
1702 game.enemies[kk].power -= -kp
1704 game.enemies[kk].power -= kp
1705 kpow = game.enemies[kk].power
1706 w = game.enemies[kk].location
1708 if not damaged(DSRSENS):
1710 proutn(_("%d unit hit on ") % int(hit))
1712 proutn(_("Very small hit on "))
1713 ienm = game.quad[w.i][w.j]
1716 proutn(crmena(False, ienm, "sector", w))
1720 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1724 kk -= 1 # don't do the increment
1726 else: # decide whether or not to emasculate klingon
1727 if kpow > 0 and withprob(0.9) and kpow <= randreal(0.4, 0.8)*kpini:
1728 prout(_("***Mr. Spock- \"Captain, the vessel at Sector %s")%w)
1729 prout(_(" has just lost its firepower.\""))
1730 game.enemies[kk].power = -kpow
1735 "Fire phasers at bad guys."
1739 irec = 0 # Cheating inhibitor
1748 # SR sensors and Computer are needed for automode
1749 if damaged(DSRSENS) or damaged(DCOMPTR):
1751 if game.condition == "docked":
1752 prout(_("Phasers can't be fired through base shields."))
1755 if damaged(DPHASER):
1756 prout(_("Phaser control damaged."))
1760 if damaged(DSHCTRL):
1761 prout(_("High speed shield control damaged."))
1764 if game.energy <= 200.0:
1765 prout(_("Insufficient energy to activate high-speed shield control."))
1768 prout(_("Weapons Officer Sulu- \"High-speed shield control enabled, sir.\""))
1770 # Original code so convoluted, I re-did it all
1771 # (That was Tom Almy talking about the C code, I think -- ESR)
1772 while automode == "NOTSET":
1773 key = scanner.nexttok()
1774 if key == "IHALPHA":
1775 if scanner.sees("manual"):
1776 if len(game.enemies)==0:
1777 prout(_("There is no enemy present to select."))
1780 automode = "AUTOMATIC"
1783 key = scanner.nexttok()
1784 elif scanner.sees("automatic"):
1785 if (not itarg) and len(game.enemies) != 0:
1786 automode = "FORCEMAN"
1788 if len(game.enemies)==0:
1789 prout(_("Energy will be expended into space."))
1790 automode = "AUTOMATIC"
1791 key = scanner.nexttok()
1792 elif scanner.sees("no"):
1797 elif key == "IHREAL":
1798 if len(game.enemies)==0:
1799 prout(_("Energy will be expended into space."))
1800 automode = "AUTOMATIC"
1802 automode = "FORCEMAN"
1804 automode = "AUTOMATIC"
1807 if len(game.enemies)==0:
1808 prout(_("Energy will be expended into space."))
1809 automode = "AUTOMATIC"
1811 automode = "FORCEMAN"
1813 proutn(_("Manual or automatic? "))
1818 if automode == "AUTOMATIC":
1819 if key == "IHALPHA" and scanner.sees("no"):
1821 key = scanner.nexttok()
1822 if key != "IHREAL" and len(game.enemies) != 0:
1823 prout(_("Phasers locked on target. Energy available: %.2f")%avail)
1828 for i in range(len(game.enemies)):
1829 irec += math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))*randreal(1.01, 1.06) + 1.0
1831 proutn(_("%d units required. ") % irec)
1833 proutn(_("Units to fire= "))
1834 key = scanner.nexttok()
1839 proutn(_("Energy available= %.2f") % avail)
1842 if not rpow > avail:
1848 key = scanner.nexttok()
1849 if key == "IHALPHA" and scanner.sees("no"):
1852 game.energy -= 200 # Go and do it!
1853 if checkshctrl(rpow):
1858 if len(game.enemies):
1861 for i in range(len(game.enemies)):
1865 hits[i] = math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))
1866 over = randreal(1.01, 1.06) * hits[i]
1868 powrem -= hits[i] + over
1869 if powrem <= 0 and temp < hits[i]:
1878 if extra > 0 and not game.alldone:
1880 proutn(_("*** Tholian web absorbs "))
1881 if len(game.enemies)>0:
1882 proutn(_("excess "))
1883 prout(_("phaser energy."))
1885 prout(_("%d expended on empty space.") % int(extra))
1886 elif automode == "FORCEMAN":
1889 if damaged(DCOMPTR):
1890 prout(_("Battle computer damaged, manual fire only."))
1893 prouts(_("---WORKING---"))
1895 prout(_("Short-range-sensors-damaged"))
1896 prout(_("Insufficient-data-for-automatic-phaser-fire"))
1897 prout(_("Manual-fire-must-be-used"))
1899 elif automode == "MANUAL":
1901 for k in range(len(game.enemies)):
1902 aim = game.enemies[k].location
1903 ienm = game.quad[aim.i][aim.j]
1905 proutn(_("Energy available= %.2f") % (avail-0.006))
1909 if damaged(DSRSENS) and \
1910 not game.sector.distance(aim)<2**0.5 and ienm in ('C', 'S'):
1911 prout(cramen(ienm) + _(" can't be located without short range scan."))
1914 hits[k] = 0 # prevent overflow -- thanks to Alexei Voitenko
1919 if itarg and k > kz:
1920 irec = (abs(game.enemies[k].power)/(PHASEFAC*math.pow(0.9, game.enemies[k].kdist))) * randreal(1.01, 1.06) + 1.0
1923 if not damaged(DCOMPTR):
1928 proutn(_("units to fire at %s- ") % crmena(False, ienm, "sector", aim))
1929 key = scanner.nexttok()
1930 if key == "IHALPHA" and scanner.sees("no"):
1932 key = scanner.nexttok()
1934 if key == "IHALPHA":
1938 if k == 1: # Let me say I'm baffled by this
1941 if scanner.real < 0:
1945 hits[k] = scanner.real
1946 rpow += scanner.real
1947 # If total requested is too much, inform and start over
1949 prout(_("Available energy exceeded -- try again."))
1952 key = scanner.nexttok() # scan for next value
1955 # zero energy -- abort
1958 if key == "IHALPHA" and scanner.sees("no"):
1963 game.energy -= 200.0
1964 if checkshctrl(rpow):
1968 # Say shield raised or malfunction, if necessary
1975 prout(_("Sulu- \"Sir, the high-speed shield control has malfunctioned . . ."))
1976 prouts(_(" CLICK CLICK POP . . ."))
1977 prout(_(" No response, sir!"))
1980 prout(_("Shields raised."))
1985 # Code from events,c begins here.
1987 # This isn't a real event queue a la BSD Trek yet -- you can only have one
1988 # event of each type active at any given time. Mostly these means we can
1989 # only have one FDISTR/FENSLV/FREPRO sequence going at any given time
1990 # BSD Trek, from which we swiped the idea, can have up to 5.
1992 def unschedule(evtype):
1993 "Remove an event from the schedule."
1994 game.future[evtype].date = FOREVER
1995 return game.future[evtype]
1997 def is_scheduled(evtype):
1998 "Is an event of specified type scheduled."
1999 return game.future[evtype].date != FOREVER
2001 def scheduled(evtype):
2002 "When will this event happen?"
2003 return game.future[evtype].date
2005 def schedule(evtype, offset):
2006 "Schedule an event of specified type."
2007 game.future[evtype].date = game.state.date + offset
2008 return game.future[evtype]
2010 def postpone(evtype, offset):
2011 "Postpone a scheduled event."
2012 game.future[evtype].date += offset
2015 "Rest period is interrupted by event."
2018 proutn(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
2020 game.resting = False
2026 "Run through the event queue looking for things to do."
2028 fintim = game.state.date + game.optime
2037 def tractorbeam(yank):
2038 "Tractor-beaming cases merge here."
2040 game.optime = (10.0/(7.5*7.5))*yank # 7.5 is yank rate (warp 7.5)
2042 prout("***" + crmshp() + _(" caught in long range tractor beam--"))
2043 # If Kirk & Co. screwing around on planet, handle
2044 atover(True) # atover(true) is Grab
2047 if game.icraft: # Caught in Galileo?
2050 # Check to see if shuttle is aboard
2051 if game.iscraft == "offship":
2054 prout(_("Galileo, left on the planet surface, is captured"))
2055 prout(_("by aliens and made into a flying McDonald's."))
2056 game.damage[DSHUTTL] = -10
2057 game.iscraft = "removed"
2059 prout(_("Galileo, left on the planet surface, is well hidden."))
2061 game.quadrant = game.state.kscmdr
2063 game.quadrant = game.state.kcmdr[i]
2064 game.sector = randplace(QUADSIZE)
2065 prout(crmshp() + _(" is pulled to Quadrant %s, Sector %s") \
2066 % (game.quadrant, game.sector))
2068 prout(_("(Remainder of rest/repair period cancelled.)"))
2069 game.resting = False
2071 if not damaged(DSHIELD) and game.shield > 0:
2072 doshield(shraise=True) # raise shields
2073 game.shldchg = False
2075 prout(_("(Shields not currently useable.)"))
2077 # Adjust finish time to time of tractor beaming?
2078 # fintim = game.state.date+game.optime
2079 attack(torps_ok=False)
2080 if not game.state.kcmdr:
2083 schedule(FTBEAM, game.optime+expran(1.5*game.intime/len(game.state.kcmdr)))
2086 "Code merges here for any commander destroying a starbase."
2087 # Not perfect, but will have to do
2088 # Handle case where base is in same quadrant as starship
2089 if game.battle == game.quadrant:
2090 game.state.chart[game.battle.i][game.battle.j].starbase = False
2091 game.quad[game.base.i][game.base.j] = '.'
2092 game.base.invalidate()
2095 prout(_("Spock- \"Captain, I believe the starbase has been destroyed.\""))
2096 elif game.state.baseq and communicating():
2097 # Get word via subspace radio
2100 prout(_("Lt. Uhura- \"Captain, Starfleet Command reports that"))
2101 proutn(_(" the starbase in Quadrant %s has been destroyed by") % game.battle)
2103 prout(_("the Klingon Super-Commander"))
2105 prout(_("a Klingon Commander"))
2106 game.state.chart[game.battle.i][game.battle.j].starbase = False
2107 # Remove Starbase from galaxy
2108 game.state.galaxy[game.battle.i][game.battle.j].starbase = False
2109 game.state.baseq = [x for x in game.state.baseq if x != game.battle]
2111 # reinstate a commander's base attack
2115 game.battle.invalidate()
2117 prout("=== EVENTS from %.2f to %.2f:" % (game.state.date, fintim))
2118 for i in range(1, NEVENTS):
2119 if i == FSNOVA: proutn("=== Supernova ")
2120 elif i == FTBEAM: proutn("=== T Beam ")
2121 elif i == FSNAP: proutn("=== Snapshot ")
2122 elif i == FBATTAK: proutn("=== Base Attack ")
2123 elif i == FCDBAS: proutn("=== Base Destroy ")
2124 elif i == FSCMOVE: proutn("=== SC Move ")
2125 elif i == FSCDBAS: proutn("=== SC Base Destroy ")
2126 elif i == FDSPROB: proutn("=== Probe Move ")
2127 elif i == FDISTR: proutn("=== Distress Call ")
2128 elif i == FENSLV: proutn("=== Enslavement ")
2129 elif i == FREPRO: proutn("=== Klingon Build ")
2131 prout("%.2f" % (scheduled(i)))
2134 radio_was_broken = damaged(DRADIO)
2137 # Select earliest extraneous event, evcode==0 if no events
2142 for l in range(1, NEVENTS):
2143 if game.future[l].date < datemin:
2146 prout("== Event %d fires" % evcode)
2147 datemin = game.future[l].date
2148 xtime = datemin-game.state.date
2149 game.state.date = datemin
2150 # Decrement Federation resources and recompute remaining time
2151 game.state.remres -= (game.state.remkl+4*len(game.state.kcmdr))*xtime
2153 if game.state.remtime <= 0:
2156 # Any crew left alive?
2157 if game.state.crew <= 0:
2160 # Is life support adequate?
2161 if damaged(DLIFSUP) and game.condition != "docked":
2162 if game.lsupres < xtime and game.damage[DLIFSUP] > game.lsupres:
2165 game.lsupres -= xtime
2166 if game.damage[DLIFSUP] <= xtime:
2167 game.lsupres = game.inlsr
2170 if game.condition == "docked":
2172 # Don't fix Deathray here
2173 for l in range(NDEVICES):
2174 if game.damage[l] > 0.0 and l != DDRAY:
2175 if game.damage[l]-repair > 0.0:
2176 game.damage[l] -= repair
2178 game.damage[l] = 0.0
2179 # If radio repaired, update star chart and attack reports
2180 if radio_was_broken and not damaged(DRADIO):
2181 prout(_("Lt. Uhura- \"Captain, the sub-space radio is working and"))
2182 prout(_(" surveillance reports are coming in."))
2184 if not game.iseenit:
2188 prout(_(" The star chart is now up to date.\""))
2190 # Cause extraneous event EVCODE to occur
2191 game.optime -= xtime
2192 if evcode == FSNOVA: # Supernova
2195 schedule(FSNOVA, expran(0.5*game.intime))
2196 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2198 elif evcode == FSPY: # Check with spy to see if SC should tractor beam
2199 if game.state.nscrem == 0 or \
2200 ictbeam or istract or \
2201 game.condition == "docked" or game.isatb == 1 or game.iscate:
2203 if game.ientesc or \
2204 (game.energy<2000 and game.torps<4 and game.shield < 1250) or \
2205 (damaged(DPHASER) and (damaged(DPHOTON) or game.torps<4)) or \
2206 (damaged(DSHIELD) and \
2207 (game.energy < 2500 or damaged(DPHASER)) and \
2208 (game.torps < 5 or damaged(DPHOTON))):
2210 istract = ictbeam = True
2211 tractorbeam((game.state.kscmdr-game.quadrant).distance())
2214 elif evcode == FTBEAM: # Tractor beam
2215 if not game.state.kcmdr:
2218 i = randrange(len(game.state.kcmdr))
2219 yank = (game.state.kcmdr[i]-game.quadrant).distance()
2220 if istract or game.condition == "docked" or yank == 0:
2221 # Drats! Have to reschedule
2223 game.optime + expran(1.5*game.intime/len(game.state.kcmdr)))
2227 elif evcode == FSNAP: # Snapshot of the universe (for time warp)
2228 game.snapsht = copy.deepcopy(game.state)
2229 game.state.snap = True
2230 schedule(FSNAP, expran(0.5 * game.intime))
2231 elif evcode == FBATTAK: # Commander attacks starbase
2232 if not game.state.kcmdr or not game.state.baseq:
2238 for ibq in game.state.baseq:
2239 for cmdr in game.state.kcmdr:
2240 if ibq == cmdr and ibq != game.quadrant and ibq != game.state.kscmdr:
2243 # no match found -- try later
2244 schedule(FBATTAK, expran(0.3*game.intime))
2249 # commander + starbase combination found -- launch attack
2251 schedule(FCDBAS, randreal(1.0, 4.0))
2252 if game.isatb: # extra time if SC already attacking
2253 postpone(FCDBAS, scheduled(FSCDBAS)-game.state.date)
2254 game.future[FBATTAK].date = game.future[FCDBAS].date + expran(0.3*game.intime)
2255 game.iseenit = False
2256 if not communicating():
2257 continue # No warning :-(
2261 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") % game.battle)
2262 prout(_(" reports that it is under attack and that it can"))
2263 prout(_(" hold out only until stardate %d.\"") % (int(scheduled(FCDBAS))))
2266 elif evcode == FSCDBAS: # Supercommander destroys base
2269 if not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].starbase:
2270 continue # WAS RETURN!
2272 game.battle = game.state.kscmdr
2274 elif evcode == FCDBAS: # Commander succeeds in destroying base
2275 if evcode == FCDBAS:
2277 if not game.state.baseq() \
2278 or not game.state.galaxy[game.battle.i][game.battle.j].starbase:
2279 game.battle.invalidate()
2281 # find the lucky pair
2282 for cmdr in game.state.kcmdr:
2283 if cmdr == game.battle:
2286 # No action to take after all
2289 elif evcode == FSCMOVE: # Supercommander moves
2290 schedule(FSCMOVE, 0.2777)
2291 if not game.ientesc and not istract and game.isatb != 1 and \
2292 (not game.iscate or not game.justin):
2294 elif evcode == FDSPROB: # Move deep space probe
2295 schedule(FDSPROB, 0.01)
2296 if not game.probe.nexttok():
2297 if not game.probe.quadrant().valid_quadrant() or \
2298 game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j].supernova:
2299 # Left galaxy or ran into supernova
2303 proutn(_("Lt. Uhura- \"The deep space probe "))
2304 if not game.probe.quadrant().valid_quadrant():
2305 prout(_("has left the galaxy.\""))
2307 prout(_("is no longer transmitting.\""))
2313 prout(_("Lt. Uhura- \"The deep space probe is now in Quadrant %s.\"") % game.probe.quadrant())
2314 pquad = game.probe.quadrant()
2315 pdest = game.state.galaxy[pquad.i][pquad.j]
2317 game.state.chart[pquad.i][pquad.j].klingons = pdest.klingons
2318 game.state.chart[pquad.i][pquad.j].starbase = pdest.starbase
2319 game.state.chart[pquad.i][pquad.j].stars = pdest.stars
2320 pdest.charted = True
2321 game.probe.moves -= 1 # One less to travel
2322 if game.probe.arrived() and game.isarmed and pdest.stars:
2323 supernova(game.probe) # fire in the hole!
2325 if game.state.galaxy[pquad.i][pquad.j].supernova:
2327 elif evcode == FDISTR: # inhabited system issues distress call
2329 # try a whole bunch of times to find something suitable
2330 for i in range(100):
2331 # need a quadrant which is not the current one,
2332 # which has some stars which are inhabited and
2333 # not already under attack, which is not
2334 # supernova'ed, and which has some Klingons in it
2335 w = randplace(GALSIZE)
2336 q = game.state.galaxy[w.i][w.j]
2337 if not (game.quadrant == w or q.planet is None or \
2338 not q.planet.inhabited or \
2339 q.supernova or q.status!="secure" or q.klingons<=0):
2342 # can't seem to find one; ignore this call
2344 prout("=== Couldn't find location for distress event.")
2346 # got one!! Schedule its enslavement
2347 ev = schedule(FENSLV, expran(game.intime))
2349 q.status = "distressed"
2350 # tell the captain about it if we can
2352 prout(_("Uhura- Captain, %s in Quadrant %s reports it is under attack") \
2353 % (q.planet, repr(w)))
2354 prout(_("by a Klingon invasion fleet."))
2357 elif evcode == FENSLV: # starsystem is enslaved
2358 ev = unschedule(FENSLV)
2359 # see if current distress call still active
2360 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2364 q.status = "enslaved"
2366 # play stork and schedule the first baby
2367 ev2 = schedule(FREPRO, expran(2.0 * game.intime))
2368 ev2.quadrant = ev.quadrant
2370 # report the disaster if we can
2372 prout(_("Uhura- We've lost contact with starsystem %s") % \
2374 prout(_("in Quadrant %s.\n") % ev.quadrant)
2375 elif evcode == FREPRO: # Klingon reproduces
2376 # If we ever switch to a real event queue, we'll need to
2377 # explicitly retrieve and restore the x and y.
2378 ev = schedule(FREPRO, expran(1.0 * game.intime))
2379 # see if current distress call still active
2380 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2384 if game.state.remkl >= MAXKLGAME:
2385 continue # full right now
2386 # reproduce one Klingon
2389 if game.klhere >= MAXKLQUAD:
2391 # this quadrant not ok, pick an adjacent one
2392 for m.i in range(w.i - 1, w.i + 2):
2393 for m.j in range(w.j - 1, w.j + 2):
2394 if not m.valid_quadrant():
2396 q = game.state.galaxy[m.i][m.j]
2397 # check for this quad ok (not full & no snova)
2398 if q.klingons >= MAXKLQUAD or q.supernova:
2402 continue # search for eligible quadrant failed
2406 game.state.remkl += 1
2408 if game.quadrant == w:
2410 game.enemies.append(newkling())
2411 # recompute time left
2414 if game.quadrant == w:
2415 prout(_("Spock- sensors indicate the Klingons have"))
2416 prout(_("launched a warship from %s.") % q.planet)
2418 prout(_("Uhura- Starfleet reports increased Klingon activity"))
2419 if q.planet != None:
2420 proutn(_("near %s ") % q.planet)
2421 prout(_("in Quadrant %s.") % w)
2427 key = scanner.nexttok()
2430 proutn(_("How long? "))
2435 origTime = delay = scanner.real
2438 if delay >= game.state.remtime or len(game.enemies) != 0:
2439 proutn(_("Are you sure? "))
2442 # Alternate resting periods (events) with attacks
2446 game.resting = False
2447 if not game.resting:
2448 prout(_("%d stardates left.") % int(game.state.remtime))
2450 temp = game.optime = delay
2451 if len(game.enemies):
2452 rtime = randreal(1.0, 2.0)
2456 if game.optime < delay:
2457 attack(torps_ok=False)
2465 # Repair Deathray if long rest at starbase
2466 if origTime-delay >= 9.99 and game.condition == "docked":
2467 game.damage[DDRAY] = 0.0
2468 # leave if quadrant supernovas
2469 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2471 game.resting = False
2476 ncourse = (0.0, 10.5, 12.0, 1.5, 9.0, 0.0, 3.0, 7.5, 6.0, 4.5)
2477 newc = Coord(); neighbor = Coord(); bump = Coord(0, 0)
2479 # Wow! We've supernova'ed
2480 supernova(game.quadrant)
2482 # handle initial nova
2483 game.quad[nov.i][nov.j] = '.'
2484 prout(crmena(False, '*', "sector", nov) + _(" novas."))
2485 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2486 game.state.starkl += 1
2487 # Set up queue to recursively trigger adjacent stars
2493 for offset.i in range(-1, 1+1):
2494 for offset.j in range(-1, 1+1):
2495 if offset.j == 0 and offset.i == 0:
2497 neighbor = start + offset
2498 if not neighbor.valid_sector():
2500 iquad = game.quad[neighbor.i][neighbor.j]
2501 # Empty space ends reaction
2502 if iquad in ('.', '?', ' ', 'T', '#'):
2504 elif iquad == '*': # Affect another star
2506 # This star supernovas
2507 supernova(game.quadrant)
2510 hits.append(neighbor)
2511 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2512 game.state.starkl += 1
2513 proutn(crmena(True, '*', "sector", neighbor))
2515 game.quad[neighbor.i][neighbor.j] = '.'
2517 elif iquad in ('P', '@'): # Destroy planet
2518 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
2520 game.state.nplankl += 1
2522 game.state.nworldkl += 1
2523 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2524 game.iplnet.pclass = "destroyed"
2526 game.plnet.invalidate()
2530 game.quad[neighbor.i][neighbor.j] = '.'
2531 elif iquad == 'B': # Destroy base
2532 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
2533 game.state.baseq = [x for x in game.state.baseq if x!= game.quadrant]
2534 game.base.invalidate()
2535 game.state.basekl += 1
2537 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2538 game.quad[neighbor.i][neighbor.j] = '.'
2539 elif iquad in ('E', 'F'): # Buffet ship
2540 prout(_("***Starship buffeted by nova."))
2542 if game.shield >= 2000.0:
2543 game.shield -= 2000.0
2545 diff = 2000.0 - game.shield
2549 prout(_("***Shields knocked out."))
2550 game.damage[DSHIELD] += 0.005*game.damfac*randreal()*diff
2552 game.energy -= 2000.0
2553 if game.energy <= 0:
2556 # add in course nova contributes to kicking starship
2557 bump += (game.sector-hits[-1]).sgn()
2558 elif iquad == 'K': # kill klingon
2559 deadkl(neighbor, iquad, neighbor)
2560 elif iquad in ('C','S','R'): # Damage/destroy big enemies
2561 for ll in range(len(game.enemies)):
2562 if game.enemies[ll].location == neighbor:
2564 game.enemies[ll].power -= 800.0 # If firepower is lost, die
2565 if game.enemies[ll].power <= 0.0:
2566 deadkl(neighbor, iquad, neighbor)
2568 newc = neighbor + neighbor - hits[-1]
2569 proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged"))
2570 if not newc.valid_sector():
2571 # can't leave quadrant
2574 iquad1 = game.quad[newc.i][newc.j]
2576 proutn(_(", blasted into ") + crmena(False, ' ', "sector", newc))
2578 deadkl(neighbor, iquad, newc)
2581 # can't move into something else
2584 proutn(_(", buffeted to Sector %s") % newc)
2585 game.quad[neighbor.i][neighbor.j] = '.'
2586 game.quad[newc.i][newc.j] = iquad
2587 game.enemies[ll].move(newc)
2588 # Starship affected by nova -- kick it away.
2590 direc = ncourse[3*(bump.i+1)+bump.j+2]
2595 scourse = course(bearing=direc, distance=dist)
2596 game.optime = scourse.time(w=4)
2598 prout(_("Force of nova displaces starship."))
2599 imove(scourse, noattack=True)
2600 game.optime = scourse.time(w=4)
2604 "Star goes supernova."
2609 # Scheduled supernova -- select star at random.
2612 for nq.i in range(GALSIZE):
2613 for nq.j in range(GALSIZE):
2614 nstars += game.state.galaxy[nq.i][nq.j].stars
2616 return # nothing to supernova exists
2617 num = randrange(nstars) + 1
2618 for nq.i in range(GALSIZE):
2619 for nq.j in range(GALSIZE):
2620 num -= game.state.galaxy[nq.i][nq.j].stars
2626 proutn("=== Super nova here?")
2629 if not nq == game.quadrant or game.justin:
2630 # it isn't here, or we just entered (treat as enroute)
2633 prout(_("Message from Starfleet Command Stardate %.2f") % game.state.date)
2634 prout(_(" Supernova in Quadrant %s; caution advised.") % nq)
2637 # we are in the quadrant!
2638 num = randrange(game.state.galaxy[nq.i][nq.j].stars) + 1
2639 for ns.i in range(QUADSIZE):
2640 for ns.j in range(QUADSIZE):
2641 if game.quad[ns.i][ns.j]=='*':
2648 prouts(_("***RED ALERT! RED ALERT!"))
2650 prout(_("***Incipient supernova detected at Sector %s") % ns)
2651 if (ns.i-game.sector.i)**2 + (ns.j-game.sector.j)**2 <= 2.1:
2652 proutn(_("Emergency override attempts t"))
2653 prouts("***************")
2657 # destroy any Klingons in supernovaed quadrant
2658 kldead = game.state.galaxy[nq.i][nq.j].klingons
2659 game.state.galaxy[nq.i][nq.j].klingons = 0
2660 if nq == game.state.kscmdr:
2661 # did in the Supercommander!
2662 game.state.nscrem = game.state.kscmdr.i = game.state.kscmdr.j = game.isatb = 0
2666 survivors = filter(lambda w: w != nq, game.state.kcmdr)
2667 comkills = len(game.state.kcmdr) - len(survivors)
2668 game.state.kcmdr = survivors
2670 if not game.state.kcmdr:
2672 game.state.remkl -= kldead
2673 # destroy Romulans and planets in supernovaed quadrant
2674 nrmdead = game.state.galaxy[nq.i][nq.j].romulans
2675 game.state.galaxy[nq.i][nq.j].romulans = 0
2676 game.state.nromrem -= nrmdead
2678 for loop in range(game.inplan):
2679 if game.state.planets[loop].quadrant == nq:
2680 game.state.planets[loop].pclass = "destroyed"
2682 # Destroy any base in supernovaed quadrant
2683 game.state.baseq = [x for x in game.state.baseq if x != nq]
2684 # If starship caused supernova, tally up destruction
2686 game.state.starkl += game.state.galaxy[nq.i][nq.j].stars
2687 game.state.basekl += game.state.galaxy[nq.i][nq.j].starbase
2688 game.state.nplankl += npdead
2689 # mark supernova in galaxy and in star chart
2690 if game.quadrant == nq or communicating():
2691 game.state.galaxy[nq.i][nq.j].supernova = True
2692 # If supernova destroys last Klingons give special message
2693 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0 and not nq == game.quadrant:
2696 prout(_("Lucky you!"))
2697 proutn(_("A supernova in %s has just destroyed the last Klingons.") % nq)
2700 # if some Klingons remain, continue or die in supernova
2705 # Code from finish.c ends here.
2708 "Self-destruct maneuver. Finish with a BANG!"
2710 if damaged(DCOMPTR):
2711 prout(_("Computer damaged; cannot execute destruct sequence."))
2713 prouts(_("---WORKING---")); skip(1)
2714 prouts(_("SELF-DESTRUCT-SEQUENCE-ACTIVATED")); skip(1)
2715 prouts(" 10"); skip(1)
2716 prouts(" 9"); skip(1)
2717 prouts(" 8"); skip(1)
2718 prouts(" 7"); skip(1)
2719 prouts(" 6"); skip(1)
2721 prout(_("ENTER-CORRECT-PASSWORD-TO-CONTINUE-"))
2723 prout(_("SELF-DESTRUCT-SEQUENCE-OTHERWISE-"))
2725 prout(_("SELF-DESTRUCT-SEQUENCE-WILL-BE-ABORTED"))
2728 if game.passwd != scanner.token:
2729 prouts(_("PASSWORD-REJECTED;"))
2731 prouts(_("CONTINUITY-EFFECTED"))
2734 prouts(_("PASSWORD-ACCEPTED")); skip(1)
2735 prouts(" 5"); skip(1)
2736 prouts(" 4"); skip(1)
2737 prouts(" 3"); skip(1)
2738 prouts(" 2"); skip(1)
2739 prouts(" 1"); skip(1)
2741 prouts(_("GOODBYE-CRUEL-WORLD"))
2749 prouts(_("********* Entropy of %s maximized *********") % crmshp())
2753 if len(game.enemies) != 0:
2754 whammo = 25.0 * game.energy
2755 for l in range(len(game.enemies)):
2756 if game.enemies[l].power*game.enemies[l].kdist <= whammo:
2757 deadkl(game.enemies[l].location, game.quad[game.enemies[l].location.i][game.enemies[l].location.j], game.enemies[l].location)
2761 "Compute our rate of kils over time."
2762 elapsed = game.state.date - game.indate
2763 if elapsed == 0: # Avoid divide-by-zero error if calculated on turn 0
2766 starting = (game.inkling + game.incom + game.inscom)
2767 remaining = (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)
2768 return (starting - remaining)/elapsed
2772 badpt = 5.0*game.state.starkl + \
2774 10.0*game.state.nplankl + \
2775 300*game.state.nworldkl + \
2777 100.0*game.state.basekl +\
2779 if game.ship == 'F':
2781 elif game.ship is None:
2786 # end the game, with appropriate notfications
2790 prout(_("It is stardate %.1f.") % game.state.date)
2792 if ifin == FWON: # Game has been won
2793 if game.state.nromrem != 0:
2794 prout(_("The remaining %d Romulans surrender to Starfleet Command.") %
2797 prout(_("You have smashed the Klingon invasion fleet and saved"))
2798 prout(_("the Federation."))
2803 badpt = 0.0 # Close enough!
2804 # killsPerDate >= RateMax
2805 if game.state.date-game.indate < 5.0 or \
2806 killrate() >= 0.1*game.skill*(game.skill+1.0) + 0.1 + 0.008*badpt:
2808 prout(_("In fact, you have done so well that Starfleet Command"))
2809 if game.skill == SKILL_NOVICE:
2810 prout(_("promotes you one step in rank from \"Novice\" to \"Fair\"."))
2811 elif game.skill == SKILL_FAIR:
2812 prout(_("promotes you one step in rank from \"Fair\" to \"Good\"."))
2813 elif game.skill == SKILL_GOOD:
2814 prout(_("promotes you one step in rank from \"Good\" to \"Expert\"."))
2815 elif game.skill == SKILL_EXPERT:
2816 prout(_("promotes you to Commodore Emeritus."))
2818 prout(_("Now that you think you're really good, try playing"))
2819 prout(_("the \"Emeritus\" game. It will splatter your ego."))
2820 elif game.skill == SKILL_EMERITUS:
2822 proutn(_("Computer- "))
2823 prouts(_("ERROR-ERROR-ERROR-ERROR"))
2825 prouts(_(" YOUR-SKILL-HAS-EXCEEDED-THE-CAPACITY-OF-THIS-PROGRAM"))
2827 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2829 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2831 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2833 prouts(_(" THIS-PROGRAM-MUST?- MUST ? - SUR? ? -? VI"))
2835 prout(_("Now you can retire and write your own Star Trek game!"))
2837 elif game.skill >= SKILL_EXPERT:
2838 if game.thawed and not game.idebug:
2839 prout(_("You cannot get a citation, so..."))
2841 proutn(_("Do you want your Commodore Emeritus Citation printed? "))
2845 # Only grant long life if alive (original didn't!)
2847 prout(_("LIVE LONG AND PROSPER."))
2852 elif ifin == FDEPLETE: # Federation Resources Depleted
2853 prout(_("Your time has run out and the Federation has been"))
2854 prout(_("conquered. Your starship is now Klingon property,"))
2855 prout(_("and you are put on trial as a war criminal. On the"))
2856 proutn(_("basis of your record, you are "))
2857 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)*3.0 > (game.inkling + game.incom + game.inscom):
2858 prout(_("acquitted."))
2860 prout(_("LIVE LONG AND PROSPER."))
2862 prout(_("found guilty and"))
2863 prout(_("sentenced to death by slow torture."))
2867 elif ifin == FLIFESUP:
2868 prout(_("Your life support reserves have run out, and"))
2869 prout(_("you die of thirst, starvation, and asphyxiation."))
2870 prout(_("Your starship is a derelict in space."))
2872 prout(_("Your energy supply is exhausted."))
2874 prout(_("Your starship is a derelict in space."))
2875 elif ifin == FBATTLE:
2876 prout(_("The %s has been destroyed in battle.") % crmshp())
2878 prout(_("Dulce et decorum est pro patria mori."))
2880 prout(_("You have made three attempts to cross the negative energy"))
2881 prout(_("barrier which surrounds the galaxy."))
2883 prout(_("Your navigation is abominable."))
2886 prout(_("Your starship has been destroyed by a nova."))
2887 prout(_("That was a great shot."))
2889 elif ifin == FSNOVAED:
2890 prout(_("The %s has been fried by a supernova.") % crmshp())
2891 prout(_("...Not even cinders remain..."))
2892 elif ifin == FABANDN:
2893 prout(_("You have been captured by the Klingons. If you still"))
2894 prout(_("had a starbase to be returned to, you would have been"))
2895 prout(_("repatriated and given another chance. Since you have"))
2896 prout(_("no starbases, you will be mercilessly tortured to death."))
2897 elif ifin == FDILITHIUM:
2898 prout(_("Your starship is now an expanding cloud of subatomic particles"))
2899 elif ifin == FMATERIALIZE:
2900 prout(_("Starbase was unable to re-materialize your starship."))
2901 prout(_("Sic transit gloria mundi"))
2902 elif ifin == FPHASER:
2903 prout(_("The %s has been cremated by its own phasers.") % crmshp())
2905 prout(_("You and your landing party have been"))
2906 prout(_("converted to energy, disipating through space."))
2907 elif ifin == FMINING:
2908 prout(_("You are left with your landing party on"))
2909 prout(_("a wild jungle planet inhabited by primitive cannibals."))
2911 prout(_("They are very fond of \"Captain Kirk\" soup."))
2913 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
2914 elif ifin == FDPLANET:
2915 prout(_("You and your mining party perish."))
2917 prout(_("That was a great shot."))
2920 prout(_("The Galileo is instantly annihilated by the supernova."))
2921 prout(_("You and your mining party are atomized."))
2923 prout(_("Mr. Spock takes command of the %s and") % crmshp())
2924 prout(_("joins the Romulans, wreaking terror on the Federation."))
2925 elif ifin == FPNOVA:
2926 prout(_("You and your mining party are atomized."))
2928 prout(_("Mr. Spock takes command of the %s and") % crmshp())
2929 prout(_("joins the Romulans, wreaking terror on the Federation."))
2930 elif ifin == FSTRACTOR:
2931 prout(_("The shuttle craft Galileo is also caught,"))
2932 prout(_("and breaks up under the strain."))
2934 prout(_("Your debris is scattered for millions of miles."))
2935 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
2937 prout(_("The mutants attack and kill Spock."))
2938 prout(_("Your ship is captured by Klingons, and"))
2939 prout(_("your crew is put on display in a Klingon zoo."))
2940 elif ifin == FTRIBBLE:
2941 prout(_("Tribbles consume all remaining water,"))
2942 prout(_("food, and oxygen on your ship."))
2944 prout(_("You die of thirst, starvation, and asphyxiation."))
2945 prout(_("Your starship is a derelict in space."))
2947 prout(_("Your ship is drawn to the center of the black hole."))
2948 prout(_("You are crushed into extremely dense matter."))
2950 prout(_("Your last crew member has died."))
2951 if game.ship == 'F':
2953 elif game.ship == 'E':
2956 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0:
2957 goodies = game.state.remres/game.inresor
2958 baddies = (game.state.remkl + 2.0*len(game.state.kcmdr))/(game.inkling+2.0*game.incom)
2959 if goodies/baddies >= randreal(1.0, 1.5):
2960 prout(_("As a result of your actions, a treaty with the Klingon"))
2961 prout(_("Empire has been signed. The terms of the treaty are"))
2962 if goodies/baddies >= randreal(3.0):
2963 prout(_("favorable to the Federation."))
2965 prout(_("Congratulations!"))
2967 prout(_("highly unfavorable to the Federation."))
2969 prout(_("The Federation will be destroyed."))
2971 prout(_("Since you took the last Klingon with you, you are a"))
2972 prout(_("martyr and a hero. Someday maybe they'll erect a"))
2973 prout(_("statue in your memory. Rest in peace, and try not"))
2974 prout(_("to think about pigeons."))
2979 "Compute player's score."
2980 timused = game.state.date - game.indate
2981 if (timused == 0 or (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0) and timused < 5.0:
2983 game.perdate = killrate()
2984 ithperd = 500*game.perdate + 0.5
2987 iwon = 100*game.skill
2988 if game.ship == 'E':
2990 elif game.ship == 'F':
2994 game.score = 10*(game.inkling - game.state.remkl) \
2995 + 50*(game.incom - len(game.state.kcmdr)) \
2997 + 20*(game.inrom - game.state.nromrem) \
2998 + 200*(game.inscom - game.state.nscrem) \
2999 - game.state.nromrem \
3004 prout(_("Your score --"))
3005 if game.inrom - game.state.nromrem:
3006 prout(_("%6d Romulans destroyed %5d") %
3007 (game.inrom - game.state.nromrem, 20*(game.inrom - game.state.nromrem)))
3008 if game.state.nromrem and game.gamewon:
3009 prout(_("%6d Romulans captured %5d") %
3010 (game.state.nromrem, game.state.nromrem))
3011 if game.inkling - game.state.remkl:
3012 prout(_("%6d ordinary Klingons destroyed %5d") %
3013 (game.inkling - game.state.remkl, 10*(game.inkling - game.state.remkl)))
3014 if game.incom - len(game.state.kcmdr):
3015 prout(_("%6d Klingon commanders destroyed %5d") %
3016 (game.incom - len(game.state.kcmdr), 50*(game.incom - len(game.state.kcmdr))))
3017 if game.inscom - game.state.nscrem:
3018 prout(_("%6d Super-Commander destroyed %5d") %
3019 (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem)))
3021 prout(_("%6.2f Klingons per stardate %5d") %
3022 (game.perdate, ithperd))
3023 if game.state.starkl:
3024 prout(_("%6d stars destroyed by your action %5d") %
3025 (game.state.starkl, -5*game.state.starkl))
3026 if game.state.nplankl:
3027 prout(_("%6d planets destroyed by your action %5d") %
3028 (game.state.nplankl, -10*game.state.nplankl))
3029 if (game.options & OPTION_WORLDS) and game.state.nworldkl:
3030 prout(_("%6d inhabited planets destroyed by your action %5d") %
3031 (game.state.nworldkl, -300*game.state.nworldkl))
3032 if game.state.basekl:
3033 prout(_("%6d bases destroyed by your action %5d") %
3034 (game.state.basekl, -100*game.state.basekl))
3036 prout(_("%6d calls for help from starbase %5d") %
3037 (game.nhelp, -45*game.nhelp))
3039 prout(_("%6d casualties incurred %5d") %
3040 (game.casual, -game.casual))
3042 prout(_("%6d crew abandoned in space %5d") %
3043 (game.abandoned, -3*game.abandoned))
3045 prout(_("%6d ship(s) lost or destroyed %5d") %
3046 (klship, -100*klship))
3048 prout(_("Penalty for getting yourself killed -200"))
3050 proutn(_("Bonus for winning "))
3051 if game.skill == SKILL_NOVICE: proutn(_("Novice game "))
3052 elif game.skill == SKILL_FAIR: proutn(_("Fair game "))
3053 elif game.skill == SKILL_GOOD: proutn(_("Good game "))
3054 elif game.skill == SKILL_EXPERT: proutn(_("Expert game "))
3055 elif game.skill == SKILL_EMERITUS: proutn(_("Emeritus game"))
3056 prout(" %5d" % iwon)
3058 prout(_("TOTAL SCORE %5d") % game.score)
3061 "Emit winner's commemmorative plaque."
3064 proutn(_("File or device name for your plaque: "))
3067 fp = open(winner, "w")
3070 prout(_("Invalid name."))
3072 proutn(_("Enter name to go on plaque (up to 30 characters): "))
3074 # The 38 below must be 64 for 132-column paper
3075 nskip = 38 - len(winner)/2
3076 fp.write("\n\n\n\n")
3077 # --------DRAW ENTERPRISE PICTURE.
3078 fp.write(" EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n" )
3079 fp.write(" EEE E : : : E\n" )
3080 fp.write(" EE EEE E : : NCC-1701 : E\n")
3081 fp.write("EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEE : : : E\n")
3082 fp.write(" E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n")
3083 fp.write(" EEEEEEEEE EEEEEEEEEEEEE E E\n")
3084 fp.write(" EEEEEEE EEEEE E E E E\n")
3085 fp.write(" EEE E E E E\n")
3086 fp.write(" E E E E\n")
3087 fp.write(" EEEEEEEEEEEEE E E\n")
3088 fp.write(" EEE : EEEEEEE EEEEEEEE\n")
3089 fp.write(" :E : EEEE E\n")
3090 fp.write(" .-E -:----- E\n")
3091 fp.write(" :E : E\n")
3092 fp.write(" EE : EEEEEEEE\n")
3093 fp.write(" EEEEEEEEEEEEEEEEEEEEEEE\n")
3095 fp.write(_(" U. S. S. ENTERPRISE\n"))
3096 fp.write("\n\n\n\n")
3097 fp.write(_(" For demonstrating outstanding ability as a starship captain\n"))
3099 fp.write(_(" Starfleet Command bestows to you\n"))
3101 fp.write("%*s%s\n\n" % (nskip, "", winner))
3102 fp.write(_(" the rank of\n\n"))
3103 fp.write(_(" \"Commodore Emeritus\"\n\n"))
3105 if game.skill == SKILL_EXPERT:
3106 fp.write(_(" Expert level\n\n"))
3107 elif game.skill == SKILL_EMERITUS:
3108 fp.write(_("Emeritus level\n\n"))
3110 fp.write(_(" Cheat level\n\n"))
3111 timestring = time.ctime()
3112 fp.write(_(" This day of %.6s %.4s, %.8s\n\n") %
3113 (timestring+4, timestring+20, timestring+11))
3114 fp.write(_(" Your score: %d\n\n") % game.score)
3115 fp.write(_(" Klingons per stardate: %.2f\n") % game.perdate)
3118 # Code from io.c begins here
3120 rows = linecount = 0 # for paging
3123 fullscreen_window = None
3124 srscan_window = None # Short range scan
3125 report_window = None # Report legends for status window
3126 status_window = None # The status window itself
3127 lrscan_window = None # Long range scan
3128 message_window = None # Main window for scrolling text
3129 prompt_window = None # Prompt window at bottom of display
3134 # for some recent versions of python2, the following enables UTF8
3135 # for the older ones we probably need to set C locale, and python3
3136 # has no problems at all
3137 if sys.version_info[0] < 3:
3139 locale.setlocale(locale.LC_ALL, "")
3140 gettext.bindtextdomain("sst", "/usr/local/share/locale")
3141 gettext.textdomain("sst")
3142 if not (game.options & OPTION_CURSES):
3143 ln_env = os.getenv("LINES")
3149 stdscr = curses.initscr()
3153 if game.options & OPTION_COLOR:
3154 curses.start_color()
3155 curses.use_default_colors()
3156 curses.init_pair(curses.COLOR_BLACK, curses.COLOR_BLACK, -1)
3157 curses.init_pair(curses.COLOR_GREEN, curses.COLOR_GREEN, -1)
3158 curses.init_pair(curses.COLOR_RED, curses.COLOR_RED, -1)
3159 curses.init_pair(curses.COLOR_CYAN, curses.COLOR_CYAN, -1)
3160 curses.init_pair(curses.COLOR_WHITE, curses.COLOR_WHITE, -1)
3161 curses.init_pair(curses.COLOR_MAGENTA, curses.COLOR_MAGENTA, -1)
3162 curses.init_pair(curses.COLOR_BLUE, curses.COLOR_BLUE, -1)
3163 curses.init_pair(curses.COLOR_YELLOW, curses.COLOR_YELLOW, -1)
3164 global fullscreen_window, srscan_window, report_window, status_window
3165 global lrscan_window, message_window, prompt_window
3166 (rows, _columns) = stdscr.getmaxyx()
3167 fullscreen_window = stdscr
3168 srscan_window = curses.newwin(12, 25, 0, 0)
3169 report_window = curses.newwin(11, 0, 1, 25)
3170 status_window = curses.newwin(10, 0, 1, 39)
3171 lrscan_window = curses.newwin(5, 0, 0, 64)
3172 message_window = curses.newwin(0, 0, 12, 0)
3173 prompt_window = curses.newwin(1, 0, rows-2, 0)
3174 message_window.scrollok(True)
3175 setwnd(fullscreen_window)
3179 if game.options & OPTION_CURSES:
3180 stdscr.keypad(False)
3186 "Wait for user action -- OK to do nothing if on a TTY"
3187 if game.options & OPTION_CURSES:
3192 prouts(_("[ANNOUNCEMENT ARRIVING...]"))
3196 if game.skill > SKILL_FAIR:
3197 prompt = _("[CONTINUE?]")
3199 prompt = _("[PRESS ENTER TO CONTINUE]")
3201 if game.options & OPTION_CURSES:
3203 setwnd(prompt_window)
3204 prompt_window.clear()
3205 prompt_window.addstr(prompt)
3206 prompt_window.getstr()
3207 prompt_window.clear()
3208 prompt_window.refresh()
3209 setwnd(message_window)
3212 sys.stdout.write('\n')
3216 sys.stdout.write('\n' * rows)
3220 "Skip i lines. Pause game if this would cause a scrolling event."
3221 for _dummy in range(i):
3222 if game.options & OPTION_CURSES:
3223 (y, _x) = curwnd.getyx()
3226 except curses.error:
3231 if rows and linecount >= rows:
3234 sys.stdout.write('\n')
3236 def proutn(proutntline):
3237 "Utter a line with no following line feed."
3238 if game.options & OPTION_CURSES:
3239 (y, x) = curwnd.getyx()
3240 (my, _mx) = curwnd.getmaxyx()
3241 if curwnd == message_window and y >= my - 2:
3244 # Uncomment this to debug curses problems
3246 logfp.write("#curses: at %s proutn(%s)\n" % ((y, x), repr(proutntline)))
3247 curwnd.addstr(proutntline)
3250 sys.stdout.write(proutntline)
3253 def prout(proutline):
3257 def prouts(proutsline):
3259 for c in proutsline:
3260 if not replayfp or replayfp.closed: # Don't slow down replays
3263 if game.options & OPTION_CURSES:
3267 if not replayfp or replayfp.closed:
3271 "Get a line of input."
3272 if game.options & OPTION_CURSES:
3273 linein = curwnd.getstr() + "\n"
3276 if replayfp and not replayfp.closed:
3278 linein = replayfp.readline()
3281 prout("*** Replay finished")
3284 elif linein[0] != "#":
3287 linein = eval(input()) + "\n"
3293 "Change windows -- OK for this to be a no-op in tty mode."
3295 if game.options & OPTION_CURSES:
3296 # Uncomment this to debug curses problems
3298 if wnd == fullscreen_window:
3299 legend = "fullscreen"
3300 elif wnd == srscan_window:
3302 elif wnd == report_window:
3304 elif wnd == status_window:
3306 elif wnd == lrscan_window:
3308 elif wnd == message_window:
3310 elif wnd == prompt_window:
3314 logfp.write("#curses: setwnd(%s)\n" % legend)
3316 # Some curses implementations get confused when you try this.
3318 curses.curs_set(wnd in (fullscreen_window, message_window, prompt_window))
3319 except curses.error:
3323 "Clear to end of line -- can be a no-op in tty mode"
3324 if game.options & OPTION_CURSES:
3329 "Clear screen -- can be a no-op in tty mode."
3331 if game.options & OPTION_CURSES:
3337 def textcolor(color=DEFAULT):
3338 if game.options & OPTION_COLOR:
3339 if color == DEFAULT:
3341 elif color == BLACK:
3342 curwnd.attron(curses.color_pair(curses.COLOR_BLACK))
3344 curwnd.attron(curses.color_pair(curses.COLOR_BLUE))
3345 elif color == GREEN:
3346 curwnd.attron(curses.color_pair(curses.COLOR_GREEN))
3348 curwnd.attron(curses.color_pair(curses.COLOR_CYAN))
3350 curwnd.attron(curses.color_pair(curses.COLOR_RED))
3351 elif color == MAGENTA:
3352 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA))
3353 elif color == BROWN:
3354 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW))
3355 elif color == LIGHTGRAY:
3356 curwnd.attron(curses.color_pair(curses.COLOR_WHITE))
3357 elif color == DARKGRAY:
3358 curwnd.attron(curses.color_pair(curses.COLOR_BLACK) | curses.A_BOLD)
3359 elif color == LIGHTBLUE:
3360 curwnd.attron(curses.color_pair(curses.COLOR_BLUE) | curses.A_BOLD)
3361 elif color == LIGHTGREEN:
3362 curwnd.attron(curses.color_pair(curses.COLOR_GREEN) | curses.A_BOLD)
3363 elif color == LIGHTCYAN:
3364 curwnd.attron(curses.color_pair(curses.COLOR_CYAN) | curses.A_BOLD)
3365 elif color == LIGHTRED:
3366 curwnd.attron(curses.color_pair(curses.COLOR_RED) | curses.A_BOLD)
3367 elif color == LIGHTMAGENTA:
3368 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA) | curses.A_BOLD)
3369 elif color == YELLOW:
3370 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW) | curses.A_BOLD)
3371 elif color == WHITE:
3372 curwnd.attron(curses.color_pair(curses.COLOR_WHITE) | curses.A_BOLD)
3375 if game.options & OPTION_COLOR:
3376 curwnd.attron(curses.A_REVERSE)
3379 # Things past this point have policy implications.
3383 "Hook to be called after moving to redraw maps."
3384 if game.options & OPTION_CURSES:
3387 setwnd(srscan_window)
3391 setwnd(status_window)
3392 status_window.clear()
3393 status_window.move(0, 0)
3394 setwnd(report_window)
3395 report_window.clear()
3396 report_window.move(0, 0)
3398 setwnd(lrscan_window)
3399 lrscan_window.clear()
3400 lrscan_window.move(0, 0)
3401 lrscan(silent=False)
3403 def put_srscan_sym(w, sym):
3404 "Emit symbol for short-range scan."
3405 srscan_window.move(w.i+1, w.j*2+2)
3406 srscan_window.addch(sym)
3407 srscan_window.refresh()
3410 "Enemy fall down, go boom."
3411 if game.options & OPTION_CURSES:
3413 setwnd(srscan_window)
3414 srscan_window.attron(curses.A_REVERSE)
3415 put_srscan_sym(w, game.quad[w.i][w.j])
3419 srscan_window.attroff(curses.A_REVERSE)
3420 put_srscan_sym(w, game.quad[w.i][w.j])
3421 curses.delay_output(500)
3422 setwnd(message_window)
3425 "Sound and visual effects for teleportation."
3426 if game.options & OPTION_CURSES:
3428 setwnd(message_window)
3430 prouts(" . . . . . ")
3431 if game.options & OPTION_CURSES:
3432 #curses.delay_output(1000)
3436 def tracktorpedo(w, step, i, n, iquad):
3437 "Torpedo-track animation."
3438 if not game.options & OPTION_CURSES:
3442 proutn(_("Track for torpedo number %d- ") % (i+1))
3445 proutn(_("Torpedo track- "))
3446 elif step==4 or step==9:
3450 if not damaged(DSRSENS) or game.condition=="docked":
3451 if i != 0 and step == 1:
3454 if (iquad=='.') or (iquad==' '):
3455 put_srscan_sym(w, '+')
3459 put_srscan_sym(w, iquad)
3461 curwnd.attron(curses.A_REVERSE)
3462 put_srscan_sym(w, iquad)
3466 curwnd.attroff(curses.A_REVERSE)
3467 put_srscan_sym(w, iquad)
3472 "Display the current galaxy chart."
3473 if game.options & OPTION_CURSES:
3474 setwnd(message_window)
3475 message_window.clear()
3477 if game.options & OPTION_TTY:
3482 def prstat(txt, data):
3484 if game.options & OPTION_CURSES:
3486 setwnd(status_window)
3488 proutn(" " * (NSYM - len(txt)))
3491 if game.options & OPTION_CURSES:
3492 setwnd(report_window)
3494 # Code from moving.c begins here
3496 def imove(icourse=None, noattack=False):
3497 "Movement execution for warp, impulse, supernova, and tractor-beam events."
3500 def newquadrant(noattack):
3501 # Leaving quadrant -- allow final enemy attack
3502 # Don't do it if being pushed by Nova
3503 if len(game.enemies) != 0 and not noattack:
3505 for enemy in game.enemies:
3506 finald = (w - enemy.location).distance()
3507 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3508 # Stas Sergeev added the condition
3509 # that attacks only happen if Klingons
3510 # are present and your skill is good.
3511 if game.skill > SKILL_GOOD and game.klhere > 0 and not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3512 attack(torps_ok=False)
3515 # check for edge of galaxy
3519 if icourse.final.i < 0:
3520 icourse.final.i = -icourse.final.i
3522 if icourse.final.j < 0:
3523 icourse.final.j = -icourse.final.j
3525 if icourse.final.i >= GALSIZE*QUADSIZE:
3526 icourse.final.i = (GALSIZE*QUADSIZE*2) - icourse.final.i
3528 if icourse.final.j >= GALSIZE*QUADSIZE:
3529 icourse.final.j = (GALSIZE*QUADSIZE*2) - icourse.final.j
3537 if game.nkinks == 3:
3538 # Three strikes -- you're out!
3542 prout(_("YOU HAVE ATTEMPTED TO CROSS THE NEGATIVE ENERGY BARRIER"))
3543 prout(_("AT THE EDGE OF THE GALAXY. THE THIRD TIME YOU TRY THIS,"))
3544 prout(_("YOU WILL BE DESTROYED."))
3545 # Compute final position in new quadrant
3546 if trbeam: # Don't bother if we are to be beamed
3548 game.quadrant = icourse.final.quadrant()
3549 game.sector = icourse.final.sector()
3551 prout(_("Entering Quadrant %s.") % game.quadrant)
3552 game.quad[game.sector.i][game.sector.j] = game.ship
3554 if game.skill>SKILL_NOVICE:
3555 attack(torps_ok=False)
3557 def check_collision(h):
3558 iquad = game.quad[h.i][h.j]
3560 # object encountered in flight path
3561 stopegy = 50.0*icourse.distance/game.optime
3562 if iquad in ('T', 'K', 'C', 'S', 'R', '?'):
3563 for enemy in game.enemies:
3564 if enemy.location == game.sector:
3566 collision(rammed=False, enemy=enemy)
3570 prouts(_("***RED ALERT! RED ALERT!"))
3572 proutn("***" + crmshp())
3573 proutn(_(" pulled into black hole at Sector %s") % h)
3574 # Getting pulled into a black hole was certain
3575 # death in Almy's original. Stas Sergeev added a
3576 # possibility that you'll get timewarped instead.
3578 for m in range(NDEVICES):
3579 if game.damage[m]>0:
3581 probf=math.pow(1.4,(game.energy+game.shield)/5000.0-1.0)*math.pow(1.3,1.0/(n+1)-1.0)
3582 if (game.options & OPTION_BLKHOLE) and withprob(1-probf):
3592 prout(_(" encounters Tholian web at %s;") % h)
3594 prout(_(" blocked by object at %s;") % h)
3595 proutn(_("Emergency stop required "))
3596 prout(_("%2d units of energy.") % int(stopegy))
3597 game.energy -= stopegy
3598 if game.energy <= 0:
3605 prout(_("Helmsman Sulu- \"Leaving standard orbit.\""))
3606 game.inorbit = False
3607 # If tractor beam is to occur, don't move full distance
3608 if game.state.date+game.optime >= scheduled(FTBEAM):
3610 game.condition = "red"
3611 icourse.distance = icourse.distance*(scheduled(FTBEAM)-game.state.date)/game.optime + 0.1
3612 game.optime = scheduled(FTBEAM) - game.state.date + 1e-5
3614 game.quad[game.sector.i][game.sector.j] = '.'
3615 for _m in range(icourse.moves):
3617 w = icourse.sector()
3618 if icourse.origin.quadrant() != icourse.location.quadrant():
3619 newquadrant(noattack)
3621 elif check_collision(w):
3622 print("Collision detected")
3626 # We're in destination quadrant -- compute new average enemy distances
3627 game.quad[game.sector.i][game.sector.j] = game.ship
3629 for enemy in game.enemies:
3630 finald = (w-enemy.location).distance()
3631 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3632 enemy.kdist = finald
3634 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3635 attack(torps_ok=False)
3636 for enemy in game.enemies:
3637 enemy.kavgd = enemy.kdist
3640 setwnd(message_window)
3644 "Dock our ship at a starbase."
3646 if game.condition == "docked" and verbose:
3647 prout(_("Already docked."))
3650 prout(_("You must first leave standard orbit."))
3652 if not game.base.is_valid() or abs(game.sector.i-game.base.i) > 1 or abs(game.sector.j-game.base.j) > 1:
3653 prout(crmshp() + _(" not adjacent to base."))
3655 game.condition = "docked"
3659 if game.energy < game.inenrg:
3660 game.energy = game.inenrg
3661 game.shield = game.inshld
3662 game.torps = game.intorps
3663 game.lsupres = game.inlsr
3664 game.state.crew = FULLCREW
3665 if not damaged(DRADIO) and \
3666 ((is_scheduled(FCDBAS) or game.isatb == 1) and not game.iseenit):
3667 # get attack report from base
3668 prout(_("Lt. Uhura- \"Captain, an important message from the starbase:\""))
3672 def cartesian(loc1=None, loc2=None):
3674 return game.quadrant * QUADSIZE + game.sector
3676 return game.quadrant * QUADSIZE + loc1
3678 return loc1 * QUADSIZE + loc2
3680 def getcourse(isprobe):
3681 "Get a course and distance from the user."
3683 dquad = copy.copy(game.quadrant)
3684 navmode = "unspecified"
3688 if game.landed and not isprobe:
3689 prout(_("Dummy! You can't leave standard orbit until you"))
3690 proutn(_("are back aboard the ship."))
3693 while navmode == "unspecified":
3694 if damaged(DNAVSYS):
3696 prout(_("Computer damaged; manual navigation only"))
3698 prout(_("Computer damaged; manual movement only"))
3703 key = scanner.nexttok()
3705 proutn(_("Manual or automatic- "))
3708 elif key == "IHALPHA":
3709 if scanner.sees("manual"):
3711 key = scanner.nexttok()
3713 elif scanner.sees("automatic"):
3714 navmode = "automatic"
3715 key = scanner.nexttok()
3723 prout(_("(Manual navigation assumed.)"))
3725 prout(_("(Manual movement assumed.)"))
3729 if navmode == "automatic":
3730 while key == "IHEOL":
3732 proutn(_("Target quadrant or quadrant§or- "))
3734 proutn(_("Destination sector or quadrant§or- "))
3737 key = scanner.nexttok()
3741 xi = int(round(scanner.real))-1
3742 key = scanner.nexttok()
3746 xj = int(round(scanner.real))-1
3747 key = scanner.nexttok()
3749 # both quadrant and sector specified
3750 xk = int(round(scanner.real))-1
3751 key = scanner.nexttok()
3755 xl = int(round(scanner.real))-1
3761 # only one pair of numbers was specified
3763 # only quadrant specified -- go to center of dest quad
3766 dsect.j = dsect.i = 4 # preserves 1-origin behavior
3768 # only sector specified
3772 if not dquad.valid_quadrant() or not dsect.valid_sector():
3779 prout(_("Helmsman Sulu- \"Course locked in for Sector %s.\"") % dsect)
3781 prout(_("Ensign Chekov- \"Course laid in, Captain.\""))
3782 # the actual deltas get computed here
3783 delta.j = dquad.j-game.quadrant.j + (dsect.j-game.sector.j)/(QUADSIZE*1.0)
3784 delta.i = game.quadrant.i-dquad.i + (game.sector.i-dsect.i)/(QUADSIZE*1.0)
3786 while key == "IHEOL":
3787 proutn(_("X and Y displacements- "))
3790 key = scanner.nexttok()
3795 delta.j = scanner.real
3796 key = scanner.nexttok()
3800 delta.i = scanner.real
3801 # Check for zero movement
3802 if delta.i == 0 and delta.j == 0:
3805 if itemp == "verbose" and not isprobe:
3807 prout(_("Helmsman Sulu- \"Aye, Sir.\""))
3809 return course(bearing=delta.bearing(), distance=delta.distance())
3812 def __init__(self, bearing, distance, origin=None):
3813 self.distance = distance
3814 self.bearing = bearing
3816 self.origin = cartesian(game.quadrant, game.sector)
3818 self.origin = origin
3819 # The bearing() code we inherited from FORTRAN is actually computing
3820 # clockface directions!
3821 if self.bearing < 0.0:
3822 self.bearing += 12.0
3823 self.angle = ((15.0 - self.bearing) * 0.5235988)
3825 self.origin = cartesian(game.quadrant, game.sector)
3827 self.origin = cartesian(game.quadrant, origin)
3828 self.increment = Coord(-math.sin(self.angle), math.cos(self.angle))
3829 bigger = max(abs(self.increment.i), abs(self.increment.j))
3830 self.increment /= bigger
3831 self.moves = int(round(10*self.distance*bigger))
3833 self.final = (self.location + self.moves*self.increment).roundtogrid()
3835 self.location = self.origin
3838 return self.location.roundtogrid() == self.final
3840 "Next step on course."
3842 self.nextlocation = self.location + self.increment
3843 samequad = (self.location.quadrant() == self.nextlocation.quadrant())
3844 self.location = self.nextlocation
3847 return self.location.quadrant()
3849 return self.location.sector()
3851 return self.distance*(w**3)*(game.shldup+1)
3853 return 10.0*self.distance/w**2
3856 "Move under impulse power."
3858 if damaged(DIMPULS):
3861 prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
3863 if game.energy > 30.0:
3865 icourse = getcourse(isprobe=False)
3868 power = 20.0 + 100.0*icourse.distance
3871 if power >= game.energy:
3872 # Insufficient power for trip
3874 prout(_("First Officer Spock- \"Captain, the impulse engines"))
3875 prout(_("require 20.0 units to engage, plus 100.0 units per"))
3876 if game.energy > 30:
3877 proutn(_("quadrant. We can go, therefore, a maximum of %d") %
3878 int(0.01 * (game.energy-20.0)-0.05))
3879 prout(_(" quadrants.\""))
3881 prout(_("quadrant. They are, therefore, useless.\""))
3884 # Make sure enough time is left for the trip
3885 game.optime = icourse.distance/0.095
3886 if game.optime >= game.state.remtime:
3887 prout(_("First Officer Spock- \"Captain, our speed under impulse"))
3888 prout(_("power is only 0.95 sectors per stardate. Are you sure"))
3889 proutn(_("we dare spend the time?\" "))
3892 # Activate impulse engines and pay the cost
3893 imove(icourse, noattack=False)
3897 power = 20.0 + 100.0*icourse.distance
3898 game.energy -= power
3899 game.optime = icourse.distance/0.095
3900 if game.energy <= 0:
3904 def warp(wcourse, involuntary):
3905 "ove under warp drive."
3906 blooey = False; twarp = False
3907 if not involuntary: # Not WARPX entry
3909 if game.damage[DWARPEN] > 10.0:
3912 prout(_("Engineer Scott- \"The warp engines are damaged, Sir.\""))
3914 if damaged(DWARPEN) and game.warpfac > 4.0:
3917 prout(_("Engineer Scott- \"Sorry, Captain. Until this damage"))
3918 prout(_(" is repaired, I can only give you warp 4.\""))
3920 # Read in course and distance
3923 wcourse = getcourse(isprobe=False)
3926 # Make sure starship has enough energy for the trip
3927 # Note: this formula is slightly different from the C version,
3928 # and lets you skate a bit closer to the edge.
3929 if wcourse.power(game.warpfac) >= game.energy:
3930 # Insufficient power for trip
3933 prout(_("Engineering to bridge--"))
3934 if not game.shldup or 0.5*wcourse.power(game.warpfac) > game.energy:
3935 iwarp = (game.energy/(wcourse.distance+0.05)) ** 0.333333333
3937 prout(_("We can't do it, Captain. We don't have enough energy."))
3939 proutn(_("We don't have enough energy, but we could do it at warp %d") % iwarp)
3942 prout(_("if you'll lower the shields."))
3946 prout(_("We haven't the energy to go that far with the shields up."))
3948 # Make sure enough time is left for the trip
3949 game.optime = wcourse.time(game.warpfac)
3950 if game.optime >= 0.8*game.state.remtime:
3952 prout(_("First Officer Spock- \"Captain, I compute that such"))
3953 proutn(_(" a trip would require approximately %2.0f") %
3954 (100.0*game.optime/game.state.remtime))
3955 prout(_(" percent of our"))
3956 proutn(_(" remaining time. Are you sure this is wise?\" "))
3962 if game.warpfac > 6.0:
3963 # Decide if engine damage will occur
3964 # ESR: Seems wrong. Probability of damage goes *down* with distance?
3965 prob = wcourse.distance*(6.0-game.warpfac)**2/66.666666666
3966 if prob > randreal():
3968 wcourse.distance = randreal(wcourse.distance)
3969 # Decide if time warp will occur
3970 if 0.5*wcourse.distance*math.pow(7.0,game.warpfac-10.0) > randreal():
3972 if game.idebug and game.warpfac==10 and not twarp:
3974 proutn("=== Force time warp? ")
3978 # If time warp or engine damage, check path
3979 # If it is obstructed, don't do warp or damage
3980 look = wcourse.moves
3984 w = wcourse.sector()
3985 if not w.valid_sector():
3987 if game.quad[w.i][w.j] != '.':
3991 # Activate Warp Engines and pay the cost
3992 imove(wcourse, noattack=False)
3995 game.energy -= wcourse.power(game.warpfac)
3996 if game.energy <= 0:
3998 game.optime = wcourse.time(game.warpfac)
4002 game.damage[DWARPEN] = game.damfac * randreal(1.0, 4.0)
4004 prout(_("Engineering to bridge--"))
4005 prout(_(" Scott here. The warp engines are damaged."))
4006 prout(_(" We'll have to reduce speed to warp 4."))
4011 "Change the warp factor."
4013 key=scanner.nexttok()
4017 proutn(_("Warp factor- "))
4021 if game.damage[DWARPEN] > 10.0:
4022 prout(_("Warp engines inoperative."))
4024 if damaged(DWARPEN) and scanner.real > 4.0:
4025 prout(_("Engineer Scott- \"I'm doing my best, Captain,"))
4026 prout(_(" but right now we can only go warp 4.\""))
4028 if scanner.real > 10.0:
4029 prout(_("Helmsman Sulu- \"Our top speed is warp 10, Captain.\""))
4031 if scanner.real < 1.0:
4032 prout(_("Helmsman Sulu- \"We can't go below warp 1, Captain.\""))
4034 oldfac = game.warpfac
4035 game.warpfac = scanner.real
4036 if game.warpfac <= oldfac or game.warpfac <= 6.0:
4037 prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\"") %
4040 if game.warpfac < 8.00:
4041 prout(_("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\""))
4043 if game.warpfac == 10.0:
4044 prout(_("Engineer Scott- \"Aye, Captain, we'll try it.\""))
4046 prout(_("Engineer Scott- \"Aye, Captain, but our engines may not take it.\""))
4050 "Cope with being tossed out of quadrant by supernova or yanked by beam."
4052 # is captain on planet?
4054 if damaged(DTRANSP):
4057 prout(_("Scotty rushes to the transporter controls."))
4059 prout(_("But with the shields up it's hopeless."))
4061 prouts(_("His desperate attempt to rescue you . . ."))
4066 prout(_("SUCCEEDS!"))
4069 proutn(_("The crystals mined were "))
4077 # Check to see if captain in shuttle craft
4082 # Inform captain of attempt to reach safety
4086 prouts(_("***RED ALERT! RED ALERT!"))
4088 proutn(_("The %s has stopped in a quadrant containing") % crmshp())
4089 prouts(_(" a supernova."))
4091 prout(_("***Emergency automatic override attempts to hurl ")+crmshp())
4092 prout(_("safely out of quadrant."))
4093 if not damaged(DRADIO):
4094 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
4095 # Try to use warp engines
4096 if damaged(DWARPEN):
4098 prout(_("Warp engines damaged."))
4101 game.warpfac = randreal(6.0, 8.0)
4102 prout(_("Warp factor set to %d") % int(game.warpfac))
4103 power = 0.75*game.energy
4104 dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1))
4105 dist = max(dist, randreal(math.sqrt(2)))
4106 bugout = course(bearing=randreal(12), distance=dist) # How dumb!
4107 game.optime = bugout.time(game.warpfac)
4109 game.inorbit = False
4110 warp(bugout, involuntary=True)
4112 # This is bad news, we didn't leave quadrant.
4116 prout(_("Insufficient energy to leave quadrant."))
4119 # Repeat if another snova
4120 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
4122 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
4123 finish(FWON) # Snova killed remaining enemy.
4126 "Let's do the time warp again."
4127 prout(_("***TIME WARP ENTERED."))
4128 if game.state.snap and withprob(0.5):
4130 prout(_("You are traveling backwards in time %d stardates.") %
4131 int(game.state.date-game.snapsht.date))
4132 game.state = game.snapsht
4133 game.state.snap = False
4134 if len(game.state.kcmdr):
4135 schedule(FTBEAM, expran(game.intime/len(game.state.kcmdr)))
4136 schedule(FBATTAK, expran(0.3*game.intime))
4137 schedule(FSNOVA, expran(0.5*game.intime))
4138 # next snapshot will be sooner
4139 schedule(FSNAP, expran(0.25*game.state.remtime))
4141 if game.state.nscrem:
4142 schedule(FSCMOVE, 0.2777)
4146 game.battle.invalidate()
4147 # Make sure Galileo is consistant -- Snapshot may have been taken
4148 # when on planet, which would give us two Galileos!
4150 for l in range(game.inplan):
4151 if game.state.planets[l].known == "shuttle_down":
4153 if game.iscraft == "onship" and game.ship=='E':
4154 prout(_("Chekov- \"Security reports the Galileo has disappeared, Sir!"))
4155 game.iscraft = "offship"
4156 # Likewise, if in the original time the Galileo was abandoned, but
4157 # was on ship earlier, it would have vanished -- let's restore it.
4158 if game.iscraft == "offship" and not gotit and game.damage[DSHUTTL] >= 0.0:
4159 prout(_("Chekov- \"Security reports the Galileo has reappeared in the dock!\""))
4160 game.iscraft = "onship"
4161 # There used to be code to do the actual reconstrction here,
4162 # but the starchart is now part of the snapshotted galaxy state.
4163 prout(_("Spock has reconstructed a correct star chart from memory"))
4165 # Go forward in time
4166 game.optime = expran(0.5*game.intime)
4167 prout(_("You are traveling forward in time %d stardates.") % int(game.optime))
4168 # cheat to make sure no tractor beams occur during time warp
4169 postpone(FTBEAM, game.optime)
4170 game.damage[DRADIO] += game.optime
4172 events() # Stas Sergeev added this -- do pending events
4175 "Launch deep-space probe."
4176 # New code to launch a deep space probe
4177 if game.nprobes == 0:
4180 if game.ship == 'E':
4181 prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\""))
4183 prout(_("Ye Faerie Queene has no deep space probes."))
4188 prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\""))
4190 if is_scheduled(FDSPROB):
4193 if damaged(DRADIO) and game.condition != "docked":
4194 prout(_("Spock- \"Records show the previous probe has not yet"))
4195 prout(_(" reached its destination.\""))
4197 prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""))
4199 key = scanner.nexttok()
4201 if game.nprobes == 1:
4202 prout(_("1 probe left."))
4204 prout(_("%d probes left") % game.nprobes)
4205 proutn(_("Are you sure you want to fire a probe? "))
4208 game.isarmed = False
4209 if key == "IHALPHA" and scanner.token == "armed":
4211 key = scanner.nexttok()
4212 elif key == "IHEOL":
4213 proutn(_("Arm NOVAMAX warhead? "))
4215 elif key == "IHREAL": # first element of course
4216 scanner.push(scanner.token)
4218 game.probe = getcourse(isprobe=True)
4222 schedule(FDSPROB, 0.01) # Time to move one sector
4223 prout(_("Ensign Chekov- \"The deep space probe is launched, Captain.\""))
4228 "Yell for help from nearest starbase."
4229 # There's more than one way to move in this game!
4231 # Test for conditions which prevent calling for help
4232 if game.condition == "docked":
4233 prout(_("Lt. Uhura- \"But Captain, we're already docked.\""))
4236 prout(_("Subspace radio damaged."))
4238 if not game.state.baseq:
4239 prout(_("Lt. Uhura- \"Captain, I'm not getting any response from Starbase.\""))
4242 prout(_("You must be aboard the %s.") % crmshp())
4244 # OK -- call for help from nearest starbase
4247 # There's one in this quadrant
4248 ddist = (game.base - game.sector).distance()
4250 ibq = None # Force base-quadrant game to persist past loop
4252 for ibq in game.state.baseq:
4253 xdist = QUADSIZE * (ibq - game.quadrant).distance()
4257 prout(_("No starbases remain. You are alone in a hostile galaxy."))
4259 # Since starbase not in quadrant, set up new quadrant
4262 # dematerialize starship
4263 game.quad[game.sector.i][game.sector.j]='.'
4264 proutn(_("Starbase in Quadrant %s responds--%s dematerializes") \
4265 % (game.quadrant, crmshp()))
4266 game.sector.invalidate()
4267 for m in range(1, 5+1):
4268 w = game.base.scatter()
4269 if w.valid_sector() and game.quad[w.i][w.j]=='.':
4270 # found one -- finish up
4273 if not game.sector.is_valid():
4274 prout(_("You have been lost in space..."))
4275 finish(FMATERIALIZE)
4277 # Give starbase three chances to rematerialize starship
4278 probf = math.pow((1.0 - math.pow(0.98,ddist)), 0.33333333)
4279 for m in range(1, 3+1):
4280 if m == 1: proutn(_("1st"))
4281 elif m == 2: proutn(_("2nd"))
4282 elif m == 3: proutn(_("3rd"))
4283 proutn(_(" attempt to re-materialize ") + crmshp())
4284 game.quad[game.sector.i][game.sector.j]=('-','o','O')[m-1]
4287 if randreal() > probf:
4291 curses.delay_output(500)
4293 game.quad[game.sector.i][game.sector.j]='?'
4296 setwnd(message_window)
4297 finish(FMATERIALIZE)
4299 game.quad[game.sector.i][game.sector.j]=game.ship
4301 prout(_("succeeds."))
4305 prout(_("Lt. Uhura- \"Captain, we made it!\""))
4310 if game.condition=="docked":
4312 prout(_("You cannot abandon Ye Faerie Queene."))
4315 # Must take shuttle craft to exit
4316 if game.damage[DSHUTTL]==-1:
4317 prout(_("Ye Faerie Queene has no shuttle craft."))
4319 if game.damage[DSHUTTL]<0:
4320 prout(_("Shuttle craft now serving Big Macs."))
4322 if game.damage[DSHUTTL]>0:
4323 prout(_("Shuttle craft damaged."))
4326 prout(_("You must be aboard the ship."))
4328 if game.iscraft != "onship":
4329 prout(_("Shuttle craft not currently available."))
4331 # Emit abandon ship messages
4333 prouts(_("***ABANDON SHIP! ABANDON SHIP!"))
4335 prouts(_("***ALL HANDS ABANDON SHIP!"))
4337 prout(_("Captain and crew escape in shuttle craft."))
4338 if not game.state.baseq:
4339 # Oops! no place to go...
4342 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
4344 if not (game.options & OPTION_WORLDS) and not damaged(DTRANSP):
4345 prout(_("Remainder of ship's complement beam down"))
4346 prout(_("to nearest habitable planet."))
4347 elif q.planet != None and not damaged(DTRANSP):
4348 prout(_("Remainder of ship's complement beam down to %s.") %
4351 prout(_("Entire crew of %d left to die in outer space.") %
4353 game.casual += game.state.crew
4354 game.abandoned += game.state.crew
4355 # If at least one base left, give 'em the Faerie Queene
4357 game.icrystl = False # crystals are lost
4358 game.nprobes = 0 # No probes
4359 prout(_("You are captured by Klingons and released to"))
4360 prout(_("the Federation in a prisoner-of-war exchange."))
4361 nb = randrange(len(game.state.baseq))
4362 # Set up quadrant and position FQ adjacient to base
4363 if not game.quadrant == game.state.baseq[nb]:
4364 game.quadrant = game.state.baseq[nb]
4365 game.sector.i = game.sector.j = 5
4368 # position next to base by trial and error
4369 game.quad[game.sector.i][game.sector.j] = '.'
4370 for l in range(QUADSIZE):
4371 game.sector = game.base.scatter()
4372 if game.sector.valid_sector() and \
4373 game.quad[game.sector.i][game.sector.j] == '.':
4376 break # found a spot
4377 game.sector.i=QUADSIZE/2
4378 game.sector.j=QUADSIZE/2
4380 # Get new commission
4381 game.quad[game.sector.i][game.sector.j] = game.ship = 'F'
4382 game.state.crew = FULLCREW
4383 prout(_("Starfleet puts you in command of another ship,"))
4384 prout(_("the Faerie Queene, which is antiquated but,"))
4385 prout(_("still useable."))
4387 prout(_("The dilithium crystals have been moved."))
4389 game.iscraft = "offship" # Galileo disappears
4391 game.condition="docked"
4392 for l in range(NDEVICES):
4393 game.damage[l] = 0.0
4394 game.damage[DSHUTTL] = -1
4395 game.energy = game.inenrg = 3000.0
4396 game.shield = game.inshld = 1250.0
4397 game.torps = game.intorps = 6
4398 game.lsupres=game.inlsr=3.0
4403 # Code from planets.c begins here.
4406 "Abort a lengthy operation if an event interrupts it."
4409 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.justin:
4414 "Report on (uninhabited) planets in the galaxy."
4418 prout(_("Spock- \"Planet report follows, Captain.\""))
4420 for i in range(game.inplan):
4421 if game.state.planets[i].pclass == "destroyed":
4423 if (game.state.planets[i].known != "unknown" \
4424 and not game.state.planets[i].inhabited) \
4427 if game.idebug and game.state.planets[i].known=="unknown":
4428 proutn("(Unknown) ")
4429 proutn(_("Quadrant %s") % game.state.planets[i].quadrant)
4430 proutn(_(" class "))
4431 proutn(game.state.planets[i].pclass)
4433 if game.state.planets[i].crystals != "present":
4435 prout(_("dilithium crystals present."))
4436 if game.state.planets[i].known=="shuttle_down":
4437 prout(_(" Shuttle Craft Galileo on surface."))
4439 prout(_("No information available."))
4442 "Enter standard orbit."
4446 prout(_("Already in standard orbit."))
4448 if damaged(DWARPEN) and damaged(DIMPULS):
4449 prout(_("Both warp and impulse engines damaged."))
4451 if not game.plnet.is_valid():
4452 prout("There is no planet in this sector.")
4454 if abs(game.sector.i-game.plnet.i)>1 or abs(game.sector.j-game.plnet.j)>1:
4455 prout(crmshp() + _(" not adjacent to planet."))
4458 game.optime = randreal(0.02, 0.05)
4459 prout(_("Helmsman Sulu- \"Entering standard orbit, Sir.\""))
4463 game.height = randreal(1400, 8600)
4464 prout(_("Sulu- \"Entered orbit at altitude %.2f kilometers.\"") % game.height)
4469 "Examine planets in this quadrant."
4470 if damaged(DSRSENS):
4471 if game.options & OPTION_TTY:
4472 prout(_("Short range sensors damaged."))
4474 if game.iplnet is None:
4475 if game.options & OPTION_TTY:
4476 prout(_("Spock- \"No planet in this quadrant, Captain.\""))
4478 if game.iplnet.known == "unknown":
4479 prout(_("Spock- \"Sensor scan for Quadrant %s-") % game.quadrant)
4481 prout(_(" Planet at Sector %s is of class %s.") %
4482 (game.plnet, game.iplnet.pclass))
4483 if game.iplnet.known=="shuttle_down":
4484 prout(_(" Sensors show Galileo still on surface."))
4485 proutn(_(" Readings indicate"))
4486 if game.iplnet.crystals != "present":
4488 prout(_(" dilithium crystals present.\""))
4489 if game.iplnet.known == "unknown":
4490 game.iplnet.known = "known"
4491 elif game.iplnet.inhabited:
4492 prout(_("Spock- \"The inhabited planet %s ") % game.iplnet.name)
4493 prout(_(" is located at Sector %s, Captain.\"") % game.plnet)
4496 "Use the transporter."
4500 if damaged(DTRANSP):
4501 prout(_("Transporter damaged."))
4502 if not damaged(DSHUTTL) and (game.iplnet.known=="shuttle_down" or game.iscraft == "onship"):
4504 proutn(_("Spock- \"May I suggest the shuttle craft, Sir?\" "))
4508 if not game.inorbit:
4509 prout(crmshp() + _(" not in standard orbit."))
4512 prout(_("Impossible to transport through shields."))
4514 if game.iplnet.known=="unknown":
4515 prout(_("Spock- \"Captain, we have no information on this planet"))
4516 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4517 prout(_(" you may not go down.\""))
4519 if not game.landed and game.iplnet.crystals=="absent":
4520 prout(_("Spock- \"Captain, I fail to see the logic in"))
4521 prout(_(" exploring a planet with no dilithium crystals."))
4522 proutn(_(" Are you sure this is wise?\" "))
4526 if not (game.options & OPTION_PLAIN):
4527 nrgneed = 50 * game.skill + game.height / 100.0
4528 if nrgneed > game.energy:
4529 prout(_("Engineering to bridge--"))
4530 prout(_(" Captain, we don't have enough energy for transportation."))
4532 if not game.landed and nrgneed * 2 > game.energy:
4533 prout(_("Engineering to bridge--"))
4534 prout(_(" Captain, we have enough energy only to transport you down to"))
4535 prout(_(" the planet, but there wouldn't be an energy for the trip back."))
4536 if game.iplnet.known == "shuttle_down":
4537 prout(_(" Although the Galileo shuttle craft may still be on a surface."))
4538 proutn(_(" Are you sure this is wise?\" "))
4543 # Coming from planet
4544 if game.iplnet.known=="shuttle_down":
4545 proutn(_("Spock- \"Wouldn't you rather take the Galileo?\" "))
4549 prout(_("Your crew hides the Galileo to prevent capture by aliens."))
4550 prout(_("Landing party assembled, ready to beam up."))
4552 prout(_("Kirk whips out communicator..."))
4553 prouts(_("BEEP BEEP BEEP"))
4555 prout(_("\"Kirk to enterprise- Lock on coordinates...energize.\""))
4558 prout(_("Scotty- \"Transporter room ready, Sir.\""))
4560 prout(_("Kirk and landing party prepare to beam down to planet surface."))
4562 prout(_("Kirk- \"Energize.\""))
4565 prouts("WWHOOOIIIIIRRRRREEEE.E.E. . . . . . .")
4567 if not withprob(0.98):
4568 prouts("BOOOIIIOOOIIOOOOIIIOIING . . .")
4570 prout(_("Scotty- \"Oh my God! I've lost them.\""))
4573 prouts(". . . . . . .E.E.EEEERRRRRIIIIIOOOHWW")
4574 game.landed = not game.landed
4575 game.energy -= nrgneed
4577 prout(_("Transport complete."))
4578 if game.landed and game.iplnet.known=="shuttle_down":
4579 prout(_("The shuttle craft Galileo is here!"))
4580 if not game.landed and game.imine:
4587 "Strip-mine a world for dilithium."
4591 prout(_("Mining party not on planet."))
4593 if game.iplnet.crystals == "mined":
4594 prout(_("This planet has already been strip-mined for dilithium."))
4596 elif game.iplnet.crystals == "absent":
4597 prout(_("No dilithium crystals on this planet."))
4600 prout(_("You've already mined enough crystals for this trip."))
4602 if game.icrystl and game.cryprob == 0.05:
4603 prout(_("With all those fresh crystals aboard the ") + crmshp())
4604 prout(_("there's no reason to mine more at this time."))
4606 game.optime = randreal(0.1, 0.3)*(ord(game.iplnet.pclass)-ord("L"))
4609 prout(_("Mining operation complete."))
4610 game.iplnet.crystals = "mined"
4611 game.imine = game.ididit = True
4614 "Use dilithium crystals."
4618 if not game.icrystl:
4619 prout(_("No dilithium crystals available."))
4621 if game.energy >= 1000:
4622 prout(_("Spock- \"Captain, Starfleet Regulations prohibit such an operation"))
4623 prout(_(" except when Condition Yellow exists."))
4625 prout(_("Spock- \"Captain, I must warn you that loading"))
4626 prout(_(" raw dilithium crystals into the ship's power"))
4627 prout(_(" system may risk a severe explosion."))
4628 proutn(_(" Are you sure this is wise?\" "))
4633 prout(_("Engineering Officer Scott- \"(GULP) Aye Sir."))
4634 prout(_(" Mr. Spock and I will try it.\""))
4636 prout(_("Spock- \"Crystals in place, Sir."))
4637 prout(_(" Ready to activate circuit.\""))
4639 prouts(_("Scotty- \"Keep your fingers crossed, Sir!\""))
4641 if withprob(game.cryprob):
4642 prouts(_(" \"Activating now! - - No good! It's***"))
4644 prouts(_("***RED ALERT! RED A*L********************************"))
4647 prouts(_("****************** KA-BOOM!!!! *******************"))
4651 game.energy += randreal(5000.0, 5500.0)
4652 prouts(_(" \"Activating now! - - "))
4653 prout(_("The instruments"))
4654 prout(_(" are going crazy, but I think it's"))
4655 prout(_(" going to work!! Congratulations, Sir!\""))
4660 "Use shuttlecraft for planetary jaunt."
4663 if damaged(DSHUTTL):
4664 if game.damage[DSHUTTL] == -1.0:
4665 if game.inorbit and game.iplnet.known == "shuttle_down":
4666 prout(_("Ye Faerie Queene has no shuttle craft bay to dock it at."))
4668 prout(_("Ye Faerie Queene had no shuttle craft."))
4669 elif game.damage[DSHUTTL] > 0:
4670 prout(_("The Galileo is damaged."))
4671 else: # game.damage[DSHUTTL] < 0
4672 prout(_("Shuttle craft is now serving Big Macs."))
4674 if not game.inorbit:
4675 prout(crmshp() + _(" not in standard orbit."))
4677 if (game.iplnet.known != "shuttle_down") and game.iscraft != "onship":
4678 prout(_("Shuttle craft not currently available."))
4680 if not game.landed and game.iplnet.known=="shuttle_down":
4681 prout(_("You will have to beam down to retrieve the shuttle craft."))
4683 if game.shldup or game.condition == "docked":
4684 prout(_("Shuttle craft cannot pass through shields."))
4686 if game.iplnet.known=="unknown":
4687 prout(_("Spock- \"Captain, we have no information on this planet"))
4688 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4689 prout(_(" you may not fly down.\""))
4691 game.optime = 3.0e-5*game.height
4692 if game.optime >= 0.8*game.state.remtime:
4693 prout(_("First Officer Spock- \"Captain, I compute that such"))
4694 proutn(_(" a maneuver would require approximately %2d%% of our") % \
4695 int(100*game.optime/game.state.remtime))
4696 prout(_("remaining time."))
4697 proutn(_("Are you sure this is wise?\" "))
4703 if game.iscraft == "onship":
4705 if not damaged(DTRANSP):
4706 proutn(_("Spock- \"Would you rather use the transporter?\" "))
4710 proutn(_("Shuttle crew"))
4712 proutn(_("Rescue party"))
4713 prout(_(" boards Galileo and swoops toward planet surface."))
4714 game.iscraft = "offship"
4718 game.iplnet.known="shuttle_down"
4719 prout(_("Trip complete."))
4722 # Ready to go back to ship
4723 prout(_("You and your mining party board the"))
4724 prout(_("shuttle craft for the trip back to the Enterprise."))
4726 prouts(_("The short hop begins . . ."))
4728 game.iplnet.known="known"
4734 game.iscraft = "onship"
4740 prout(_("Trip complete."))
4743 # Kirk on ship and so is Galileo
4744 prout(_("Mining party assembles in the hangar deck,"))
4745 prout(_("ready to board the shuttle craft \"Galileo\"."))
4747 prouts(_("The hangar doors open; the trip begins."))
4750 game.iscraft = "offship"
4753 game.iplnet.known = "shuttle_down"
4756 prout(_("Trip complete."))
4760 "Use the big zapper."
4764 if game.ship != 'E':
4765 prout(_("Ye Faerie Queene has no death ray."))
4767 if len(game.enemies)==0:
4768 prout(_("Sulu- \"But Sir, there are no enemies in this quadrant.\""))
4771 prout(_("Death Ray is damaged."))
4773 prout(_("Spock- \"Captain, the 'Experimental Death Ray'"))
4774 prout(_(" is highly unpredictible. Considering the alternatives,"))
4775 proutn(_(" are you sure this is wise?\" "))
4778 prout(_("Spock- \"Acknowledged.\""))
4781 prouts(_("WHOOEE ... WHOOEE ... WHOOEE ... WHOOEE"))
4783 prout(_("Crew scrambles in emergency preparation."))
4784 prout(_("Spock and Scotty ready the death ray and"))
4785 prout(_("prepare to channel all ship's power to the device."))
4787 prout(_("Spock- \"Preparations complete, sir.\""))
4788 prout(_("Kirk- \"Engage!\""))
4790 prouts(_("WHIRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"))
4793 if game.options & OPTION_PLAIN:
4797 prouts(_("Sulu- \"Captain! It's working!\""))
4799 while len(game.enemies) > 0:
4800 deadkl(game.enemies[1].location, game.quad[game.enemies[1].location.i][game.enemies[1].location.j],game.enemies[1].location)
4801 prout(_("Ensign Chekov- \"Congratulations, Captain!\""))
4802 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
4804 if (game.options & OPTION_PLAIN) == 0:
4805 prout(_("Spock- \"Captain, I believe the `Experimental Death Ray'"))
4807 prout(_(" is still operational.\""))
4809 prout(_(" has been rendered nonfunctional.\""))
4810 game.damage[DDRAY] = 39.95
4812 r = randreal() # Pick failure method
4814 prouts(_("Sulu- \"Captain! It's working!\""))
4816 prouts(_("***RED ALERT! RED ALERT!"))
4818 prout(_("***MATTER-ANTIMATTER IMPLOSION IMMINENT!"))
4820 prouts(_("***RED ALERT! RED A*L********************************"))
4823 prouts(_("****************** KA-BOOM!!!! *******************"))
4828 prouts(_("Sulu- \"Captain! Yagabandaghangrapl, brachriigringlanbla!\""))
4830 prout(_("Lt. Uhura- \"Graaeek! Graaeek!\""))
4832 prout(_("Spock- \"Fascinating! . . . All humans aboard"))
4833 prout(_(" have apparently been transformed into strange mutations."))
4834 prout(_(" Vulcans do not seem to be affected."))
4836 prout(_("Kirk- \"Raauch! Raauch!\""))
4840 prouts(_("Sulu- \"Captain! It's --WHAT?!?!\""))
4842 proutn(_("Spock- \"I believe the word is"))
4843 prouts(_(" *ASTONISHING*"))
4844 prout(_(" Mr. Sulu."))
4845 for i in range(QUADSIZE):
4846 for j in range(QUADSIZE):
4847 if game.quad[i][j] == '.':
4848 game.quad[i][j] = '?'
4849 prout(_(" Captain, our quadrant is now infested with"))
4850 prouts(_(" - - - - - - *THINGS*."))
4852 prout(_(" I have no logical explanation.\""))
4854 prouts(_("Sulu- \"Captain! The Death Ray is creating tribbles!\""))
4856 prout(_("Scotty- \"There are so many tribbles down here"))
4857 prout(_(" in Engineering, we can't move for 'em, Captain.\""))
4861 # Code from reports.c begins here
4863 def attackreport(curt):
4864 "eport status of bases under attack."
4866 if is_scheduled(FCDBAS):
4867 prout(_("Starbase in Quadrant %s is currently under Commander attack.") % game.battle)
4868 prout(_("It can hold out until Stardate %d.") % int(scheduled(FCDBAS)))
4869 elif game.isatb == 1:
4870 prout(_("Starbase in Quadrant %s is under Super-commander attack.") % game.state.kscmdr)
4871 prout(_("It can hold out until Stardate %d.") % int(scheduled(FSCDBAS)))
4873 prout(_("No Starbase is currently under attack."))
4875 if is_scheduled(FCDBAS):
4876 proutn(_("Base in %s attacked by C. Alive until %.1f") % (game.battle, scheduled(FCDBAS)))
4878 proutn(_("Base in %s attacked by S. Alive until %.1f") % (game.state.kscmdr, scheduled(FSCDBAS)))
4882 # report on general game status
4884 s1 = (game.thawed and _("thawed ")) or ""
4885 s2 = {1:"short", 2:"medium", 4:"long"}[game.length]
4886 s3 = (None, _("novice"), _("fair"),
4887 _("good"), _("expert"), _("emeritus"))[game.skill]
4888 prout(_("You %s a %s%s %s game.") % ((_("were playing"), _("are playing"))[game.alldone], s1, s2, s3))
4889 if game.skill>SKILL_GOOD and game.thawed and not game.alldone:
4890 prout(_("No plaque is allowed."))
4892 prout(_("This is tournament game %d.") % game.tourn)
4893 prout(_("Your secret password is \"%s\"") % game.passwd)
4894 proutn(_("%d of %d Klingons have been killed") % (((game.inkling + game.incom + game.inscom) - (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)),
4895 (game.inkling + game.incom + game.inscom)))
4896 if game.incom - len(game.state.kcmdr):
4897 prout(_(", including %d Commander%s.") % (game.incom - len(game.state.kcmdr), (_("s"), "")[(game.incom - len(game.state.kcmdr))==1]))
4898 elif game.inkling - game.state.remkl + (game.inscom - game.state.nscrem) > 0:
4899 prout(_(", but no Commanders."))
4902 if game.skill > SKILL_FAIR:
4903 prout(_("The Super Commander has %sbeen destroyed.") % ("", _("not "))[game.state.nscrem])
4904 if len(game.state.baseq) != game.inbase:
4906 if game.inbase-len(game.state.baseq)==1:
4907 proutn(_("has been 1 base"))
4909 proutn(_("have been %d bases") % (game.inbase-len(game.state.baseq)))
4910 prout(_(" destroyed, %d remaining.") % len(game.state.baseq))
4912 prout(_("There are %d bases.") % game.inbase)
4913 if communicating() or game.iseenit:
4914 # Don't report this if not seen and
4915 # either the radio is dead or not at base!
4919 prout(_("%d casualt%s suffered so far.") % (game.casual, ("y", "ies")[game.casual!=1]))
4921 prout(_("There were %d call%s for help.") % (game.nhelp, ("" , _("s"))[game.nhelp!=1]))
4922 if game.ship == 'E':
4923 proutn(_("You have "))
4925 proutn("%d" % (game.nprobes))
4928 proutn(_(" deep space probe"))
4932 if communicating() and is_scheduled(FDSPROB):
4934 proutn(_("An armed deep space probe is in "))
4936 proutn(_("A deep space probe is in "))
4937 prout("Quadrant %s." % game.probec)
4939 if game.cryprob <= .05:
4940 prout(_("Dilithium crystals aboard ship... not yet used."))
4944 while game.cryprob > ai:
4947 prout(_("Dilithium crystals have been used %d time%s.") % \
4948 (i, (_("s"), "")[i==1]))
4952 "Long-range sensor scan."
4953 if damaged(DLRSENS):
4954 # Now allow base's sensors if docked
4955 if game.condition != "docked":
4957 prout(_("LONG-RANGE SENSORS DAMAGED."))
4960 prout(_("Starbase's long-range scan"))
4962 prout(_("Long-range scan"))
4963 for x in range(game.quadrant.i-1, game.quadrant.i+2):
4966 for y in range(game.quadrant.j-1, game.quadrant.j+2):
4967 if not Coord(x, y).valid_quadrant():
4971 if not damaged(DRADIO):
4972 game.state.galaxy[x][y].charted = True
4973 game.state.chart[x][y].klingons = game.state.galaxy[x][y].klingons
4974 game.state.chart[x][y].starbase = game.state.galaxy[x][y].starbase
4975 game.state.chart[x][y].stars = game.state.galaxy[x][y].stars
4976 if not silent and game.state.galaxy[x][y].supernova:
4979 proutn(" %3d" % (game.state.chart[x][y].klingons*100 + game.state.chart[x][y].starbase * 10 + game.state.chart[x][y].stars))
4987 for i in range(NDEVICES):
4990 prout(_("\tDEVICE\t\t\t-REPAIR TIMES-"))
4991 prout(_("\t\t\tIN FLIGHT\t\tDOCKED"))
4993 prout(" %-26s\t%8.2f\t\t%8.2f" % (device[i],
4994 game.damage[i]+0.05,
4995 DOCKFAC*game.damage[i]+0.005))
4997 prout(_("All devices functional."))
5000 "Update the chart in the Enterprise's computer from galaxy data."
5001 game.lastchart = game.state.date
5002 for i in range(GALSIZE):
5003 for j in range(GALSIZE):
5004 if game.state.galaxy[i][j].charted:
5005 game.state.chart[i][j].klingons = game.state.galaxy[i][j].klingons
5006 game.state.chart[i][j].starbase = game.state.galaxy[i][j].starbase
5007 game.state.chart[i][j].stars = game.state.galaxy[i][j].stars
5010 "Display the star chart."
5012 if (game.options & OPTION_AUTOSCAN):
5014 if not damaged(DRADIO):
5016 if game.lastchart < game.state.date and game.condition == "docked":
5017 prout(_("Spock- \"I revised the Star Chart from the starbase's records.\""))
5019 prout(_(" STAR CHART FOR THE KNOWN GALAXY"))
5020 if game.state.date > game.lastchart:
5021 prout(_("(Last surveillance update %d stardates ago).") % ((int)(game.state.date-game.lastchart)))
5022 prout(" 1 2 3 4 5 6 7 8")
5023 for i in range(GALSIZE):
5024 proutn("%d |" % (i+1))
5025 for j in range(GALSIZE):
5026 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5030 if game.state.galaxy[i][j].supernova:
5032 elif not game.state.galaxy[i][j].charted and game.state.galaxy[i][j].starbase:
5034 elif game.state.galaxy[i][j].charted:
5035 show = "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars)
5039 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5047 def sectscan(goodScan, i, j):
5048 "Light up an individual dot in a sector."
5049 if goodScan or (abs(i-game.sector.i)<= 1 and abs(j-game.sector.j) <= 1):
5050 textcolor({"green":GREEN,
5054 "dead":BROWN}[game.condition])
5055 if game.quad[i][j] != game.ship:
5057 proutn("%c " % game.quad[i][j])
5063 "Emit status report lines"
5064 if not req or req == 1:
5065 prstat(_("Stardate"), _("%.1f, Time Left %.2f") \
5066 % (game.state.date, game.state.remtime))
5067 if not req or req == 2:
5068 if game.condition != "docked":
5070 prstat(_("Condition"), _("%s, %i DAMAGES") % \
5071 (game.condition.upper(), sum([x > 0 for x in game.damage])))
5072 if not req or req == 3:
5073 prstat(_("Position"), "%s , %s" % (game.quadrant, game.sector))
5074 if not req or req == 4:
5075 if damaged(DLIFSUP):
5076 if game.condition == "docked":
5077 s = _("DAMAGED, Base provides")
5079 s = _("DAMAGED, reserves=%4.2f") % game.lsupres
5082 prstat(_("Life Support"), s)
5083 if not req or req == 5:
5084 prstat(_("Warp Factor"), "%.1f" % game.warpfac)
5085 if not req or req == 6:
5087 if game.icrystl and (game.options & OPTION_SHOWME):
5088 extra = _(" (have crystals)")
5089 prstat(_("Energy"), "%.2f%s" % (game.energy, extra))
5090 if not req or req == 7:
5091 prstat(_("Torpedoes"), "%d" % (game.torps))
5092 if not req or req == 8:
5093 if damaged(DSHIELD):
5099 data = _(" %d%% %.1f units") \
5100 % (int((100.0*game.shield)/game.inshld + 0.5), game.shield)
5101 prstat(_("Shields"), s+data)
5102 if not req or req == 9:
5103 prstat(_("Klingons Left"), "%d" \
5104 % (game.state.remkl+len(game.state.kcmdr)+game.state.nscrem))
5105 if not req or req == 10:
5106 if game.options & OPTION_WORLDS:
5107 plnet = game.state.galaxy[game.quadrant.i][game.quadrant.j].planet
5108 if plnet and plnet.inhabited:
5109 prstat(_("Major system"), plnet.name)
5111 prout(_("Sector is uninhabited"))
5112 elif not req or req == 11:
5113 attackreport(not req)
5116 "Request specified status data, a historical relic from slow TTYs."
5117 requests = ("da","co","po","ls","wa","en","to","sh","kl","sy", "ti")
5118 while scanner.nexttok() == "IHEOL":
5119 proutn(_("Information desired? "))
5121 if scanner.token in requests:
5122 status(requests.index(scanner.token))
5124 prout(_("UNRECOGNIZED REQUEST. Legal requests are:"))
5125 prout((" date, condition, position, lsupport, warpfactor,"))
5126 prout((" energy, torpedoes, shields, klingons, system, time."))
5131 if damaged(DSRSENS):
5132 # Allow base's sensors if docked
5133 if game.condition != "docked":
5134 prout(_(" S.R. SENSORS DAMAGED!"))
5137 prout(_(" [Using Base's sensors]"))
5139 prout(_(" Short-range scan"))
5140 if goodScan and not damaged(DRADIO):
5141 game.state.chart[game.quadrant.i][game.quadrant.j].klingons = game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons
5142 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase
5143 game.state.chart[game.quadrant.i][game.quadrant.j].stars = game.state.galaxy[game.quadrant.i][game.quadrant.j].stars
5144 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
5145 prout(" 1 2 3 4 5 6 7 8 9 10")
5146 if game.condition != "docked":
5148 for i in range(QUADSIZE):
5149 proutn("%2d " % (i+1))
5150 for j in range(QUADSIZE):
5151 sectscan(goodScan, i, j)
5155 "Use computer to get estimated time of arrival for a warp jump."
5156 w1 = Coord(); w2 = Coord()
5158 if damaged(DCOMPTR):
5159 prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR."))
5162 if scanner.nexttok() != "IHREAL":
5165 proutn(_("Destination quadrant and/or sector? "))
5166 if scanner.nexttok()!="IHREAL":
5169 w1.j = int(scanner.real-0.5)
5170 if scanner.nexttok() != "IHREAL":
5173 w1.i = int(scanner.real-0.5)
5174 if scanner.nexttok() == "IHREAL":
5175 w2.j = int(scanner.real-0.5)
5176 if scanner.nexttok() != "IHREAL":
5179 w2.i = int(scanner.real-0.5)
5181 if game.quadrant.j>w1.i:
5185 if game.quadrant.i>w1.j:
5189 if not w1.valid_quadrant() or not w2.valid_sector():
5192 dist = math.sqrt((w1.j-game.quadrant.j+(w2.j-game.sector.j)/(QUADSIZE*1.0))**2+
5193 (w1.i-game.quadrant.i+(w2.i-game.sector.i)/(QUADSIZE*1.0))**2)
5196 prout(_("Answer \"no\" if you don't know the value:"))
5199 proutn(_("Time or arrival date? "))
5200 if scanner.nexttok()=="IHREAL":
5201 ttime = scanner.real
5202 if ttime > game.state.date:
5203 ttime -= game.state.date # Actually a star date
5204 twarp=(math.floor(math.sqrt((10.0*dist)/ttime)*10.0)+1.0)/10.0
5205 if ttime <= 1e-10 or twarp > 10:
5206 prout(_("We'll never make it, sir."))
5213 proutn(_("Warp factor? "))
5214 if scanner.nexttok()== "IHREAL":
5216 twarp = scanner.real
5217 if twarp<1.0 or twarp > 10.0:
5221 prout(_("Captain, certainly you can give me one of these."))
5224 ttime = (10.0*dist)/twarp**2
5225 tpower = dist*twarp*twarp*twarp*(game.shldup+1)
5226 if tpower >= game.energy:
5227 prout(_("Insufficient energy, sir."))
5228 if not game.shldup or tpower > game.energy*2.0:
5231 proutn(_("New warp factor to try? "))
5232 if scanner.nexttok() == "IHREAL":
5234 twarp = scanner.real
5235 if twarp<1.0 or twarp > 10.0:
5243 prout(_("But if you lower your shields,"))
5244 proutn(_("remaining"))
5247 proutn(_("Remaining"))
5248 prout(_(" energy will be %.2f.") % (game.energy-tpower))
5250 prout(_("And we will arrive at stardate %.2f.") % (game.state.date+ttime))
5252 prout(_("Any warp speed is adequate."))
5254 prout(_("Minimum warp needed is %.2f,") % (twarp))
5255 prout(_("and we will arrive at stardate %.2f.") % (game.state.date+ttime))
5256 if game.state.remtime < ttime:
5257 prout(_("Unfortunately, the Federation will be destroyed by then."))
5259 prout(_("You'll be taking risks at that speed, Captain"))
5260 if (game.isatb==1 and game.state.kscmdr == w1 and \
5261 scheduled(FSCDBAS)< ttime+game.state.date) or \
5262 (scheduled(FCDBAS)<ttime+game.state.date and game.battle == w1):
5263 prout(_("The starbase there will be destroyed by then."))
5264 proutn(_("New warp factor to try? "))
5265 if scanner.nexttok() == "IHREAL":
5267 twarp = scanner.real
5268 if twarp<1.0 or twarp > 10.0:
5276 # Code from setup.c begins here
5279 "Issue a historically correct banner."
5281 prout(_("-SUPER- STAR TREK"))
5283 # From the FORTRAN original
5284 # prout(_("Latest update-21 Sept 78"))
5290 scanner.push("emsave.trk")
5291 key = scanner.nexttok()
5293 proutn(_("File name: "))
5294 key = scanner.nexttok()
5295 if key != "IHALPHA":
5298 if '.' not in scanner.token:
5299 scanner.token += ".trk"
5301 fp = open(scanner.token, "wb")
5303 prout(_("Can't freeze game as file %s") % scanner.token)
5305 pickle.dump(game, fp)
5310 "Retrieve saved game."
5313 key = scanner.nexttok()
5315 proutn(_("File name: "))
5316 key = scanner.nexttok()
5317 if key != "IHALPHA":
5320 if '.' not in scanner.token:
5321 scanner.token += ".trk"
5323 fp = open(scanner.token, "rb")
5325 prout(_("Can't thaw game in %s") % scanner.token)
5327 game = pickle.load(fp)
5332 # I used <http://www.memory-alpha.org> to find planets
5333 # with references in ST:TOS. Earth and the Alpha Centauri
5334 # Colony have been omitted.
5336 # Some planets marked Class G and P here will be displayed as class M
5337 # because of the way planets are generated. This is a known bug.
5340 _("Andoria (Fesoan)"), # several episodes
5341 _("Tellar Prime (Miracht)"), # TOS: "Journey to Babel"
5342 _("Vulcan (T'Khasi)"), # many episodes
5343 _("Medusa"), # TOS: "Is There in Truth No Beauty?"
5344 _("Argelius II (Nelphia)"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5345 _("Ardana"), # TOS: "The Cloud Minders"
5346 _("Catulla (Cendo-Prae)"), # TOS: "The Way to Eden"
5347 _("Gideon"), # TOS: "The Mark of Gideon"
5348 _("Aldebaran III"), # TOS: "The Deadly Years"
5349 _("Alpha Majoris I"), # TOS: "Wolf in the Fold"
5350 _("Altair IV"), # TOS: "Amok Time
5351 _("Ariannus"), # TOS: "Let That Be Your Last Battlefield"
5352 _("Benecia"), # TOS: "The Conscience of the King"
5353 _("Beta Niobe I (Sarpeidon)"), # TOS: "All Our Yesterdays"
5354 _("Alpha Carinae II"), # TOS: "The Ultimate Computer"
5355 _("Capella IV (Kohath)"), # TOS: "Friday's Child" (Class G)
5356 _("Daran V"), # TOS: "For the World is Hollow and I Have Touched the Sky"
5357 _("Deneb II"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5358 _("Eminiar VII"), # TOS: "A Taste of Armageddon"
5359 _("Gamma Canaris IV"), # TOS: "Metamorphosis"
5360 _("Gamma Tranguli VI (Vaalel)"), # TOS: "The Apple"
5361 _("Ingraham B"), # TOS: "Operation: Annihilate"
5362 _("Janus IV"), # TOS: "The Devil in the Dark"
5363 _("Makus III"), # TOS: "The Galileo Seven"
5364 _("Marcos XII"), # TOS: "And the Children Shall Lead",
5365 _("Omega IV"), # TOS: "The Omega Glory"
5366 _("Regulus V"), # TOS: "Amok Time
5367 _("Deneva"), # TOS: "Operation -- Annihilate!"
5368 # Worlds from BSD Trek
5369 _("Rigel II"), # TOS: "Shore Leave" ("III" in BSD)
5370 _("Beta III"), # TOS: "The Return of the Archons"
5371 _("Triacus"), # TOS: "And the Children Shall Lead",
5372 _("Exo III"), # TOS: "What Are Little Girls Made Of?" (Class P)
5374 # _("Hansen's Planet"), # TOS: "The Galileo Seven"
5375 # _("Taurus IV"), # TOS: "The Galileo Seven" (class G)
5376 # _("Antos IV (Doraphane)"), # TOS: "Whom Gods Destroy", "Who Mourns for Adonais?"
5377 # _("Izar"), # TOS: "Whom Gods Destroy"
5378 # _("Tiburon"), # TOS: "The Way to Eden"
5379 # _("Merak II"), # TOS: "The Cloud Minders"
5380 # _("Coridan (Desotriana)"), # TOS: "Journey to Babel"
5381 # _("Iotia"), # TOS: "A Piece of the Action"
5385 _("S. R. Sensors"), \
5386 _("L. R. Sensors"), \
5388 _("Photon Tubes"), \
5389 _("Life Support"), \
5390 _("Warp Engines"), \
5391 _("Impulse Engines"), \
5393 _("Subspace Radio"), \
5394 _("Shuttle Craft"), \
5396 _("Navigation System"), \
5398 _("Shield Control"), \
5404 "Prepare to play, set up cosmos."
5406 # Decide how many of everything
5408 return # frozen game
5409 # Prepare the Enterprise
5410 game.alldone = game.gamewon = game.shldchg = game.shldup = False
5412 game.state.crew = FULLCREW
5413 game.energy = game.inenrg = 5000.0
5414 game.shield = game.inshld = 2500.0
5417 game.quadrant = randplace(GALSIZE)
5418 game.sector = randplace(QUADSIZE)
5419 game.torps = game.intorps = 10
5420 game.nprobes = randrange(2, 5)
5422 for i in range(NDEVICES):
5423 game.damage[i] = 0.0
5424 # Set up assorted game parameters
5425 game.battle = Coord()
5426 game.state.date = game.indate = 100.0 * randreal(20, 51)
5427 game.nkinks = game.nhelp = game.casual = game.abandoned = 0
5428 game.iscate = game.resting = game.imine = game.icrystl = game.icraft = False
5429 game.isatb = game.state.nplankl = 0
5430 game.state.starkl = game.state.basekl = game.state.nworldkl = 0
5431 game.iscraft = "onship"
5436 game.state.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
5438 game.state.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
5440 game.state.planets = [] # Planet information
5441 game.state.baseq = [] # Base quadrant coordinates
5442 game.state.kcmdr = [] # Commander quadrant coordinates
5443 game.statekscmdr = Coord() # Supercommander quadrant coordinates
5445 # Starchart is functional but we've never seen it
5446 game.lastchart = FOREVER
5447 # Put stars in the galaxy
5449 for i in range(GALSIZE):
5450 for j in range(GALSIZE):
5451 # Can't have more stars per quadrant than fit in one decimal digit,
5452 # if we do the chart representation will break.
5453 k = randrange(1, min(10, QUADSIZE**2/10))
5455 game.state.galaxy[i][j].stars = k
5456 # Locate star bases in galaxy
5458 prout("=== Allocating %d bases" % game.inbase)
5459 for i in range(game.inbase):
5462 w = randplace(GALSIZE)
5463 if not game.state.galaxy[w.i][w.j].starbase:
5466 # C version: for (j = i-1; j > 0; j--)
5467 # so it did them in the opposite order.
5468 for j in range(1, i):
5469 # Improved placement algorithm to spread out bases
5470 distq = (w - game.state.baseq[j]).distance()
5471 if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75):
5474 prout("=== Abandoning base #%d at %s" % (i, w))
5476 elif distq < 6.0 * (BASEMAX+1-game.inbase):
5478 prout("=== Saving base #%d, close to #%d" % (i, j))
5482 prout("=== Placing base #%d in quadrant %s" % (i, w))
5483 game.state.baseq.append(w)
5484 game.state.galaxy[w.i][w.j].starbase = game.state.chart[w.i][w.j].starbase = True
5485 # Position ordinary Klingon Battle Cruisers
5487 klumper = 0.25*game.skill*(9.0-game.length)+1.0
5488 if klumper > MAXKLQUAD:
5492 klump = (1.0 - r*r)*klumper
5497 w = randplace(GALSIZE)
5498 if not game.state.galaxy[w.i][w.j].supernova and \
5499 game.state.galaxy[w.i][w.j].klingons + klump <= MAXKLQUAD:
5501 game.state.galaxy[w.i][w.j].klingons += int(klump)
5504 # Position Klingon Commander Ships
5505 for i in range(game.incom):
5507 w = randplace(GALSIZE)
5508 if not welcoming(w) or w in game.state.kcmdr:
5510 if (game.state.galaxy[w.i][w.j].klingons or withprob(0.25)):
5512 game.state.galaxy[w.i][w.j].klingons += 1
5513 game.state.kcmdr.append(w)
5514 # Locate planets in galaxy
5515 for i in range(game.inplan):
5517 w = randplace(GALSIZE)
5518 if game.state.galaxy[w.i][w.j].planet is None:
5522 new.crystals = "absent"
5523 if (game.options & OPTION_WORLDS) and i < NINHAB:
5524 new.pclass = "M" # All inhabited planets are class M
5525 new.crystals = "absent"
5527 new.name = systnames[i]
5528 new.inhabited = True
5530 new.pclass = ("M", "N", "O")[randrange(0, 3)]
5532 new.crystals = "present"
5533 new.known = "unknown"
5534 new.inhabited = False
5535 game.state.galaxy[w.i][w.j].planet = new
5536 game.state.planets.append(new)
5538 for i in range(game.state.nromrem):
5539 w = randplace(GALSIZE)
5540 game.state.galaxy[w.i][w.j].romulans += 1
5541 # Place the Super-Commander if needed
5542 if game.state.nscrem > 0:
5544 w = randplace(GALSIZE)
5547 game.state.kscmdr = w
5548 game.state.galaxy[w.i][w.j].klingons += 1
5549 # Initialize times for extraneous events
5550 schedule(FSNOVA, expran(0.5 * game.intime))
5551 schedule(FTBEAM, expran(1.5 * (game.intime / len(game.state.kcmdr))))
5552 schedule(FSNAP, randreal(1.0, 2.0)) # Force an early snapshot
5553 schedule(FBATTAK, expran(0.3*game.intime))
5555 if game.state.nscrem:
5556 schedule(FSCMOVE, 0.2777)
5561 if (game.options & OPTION_WORLDS) and game.skill >= SKILL_GOOD:
5562 schedule(FDISTR, expran(1.0 + game.intime))
5567 # Place thing (in tournament game, we don't want one!)
5568 # New in SST2K: never place the Thing near a starbase.
5569 # This makes sense and avoids a special case in the old code.
5571 if game.tourn is None:
5573 thing = randplace(GALSIZE)
5574 if thing not in game.state.baseq:
5577 game.state.snap = False
5578 if game.skill == SKILL_NOVICE:
5579 prout(_("It is stardate %d. The Federation is being attacked by") % int(game.state.date))
5580 prout(_("a deadly Klingon invasion force. As captain of the United"))
5581 prout(_("Starship U.S.S. Enterprise, it is your mission to seek out"))
5582 prout(_("and destroy this invasion force of %d battle cruisers.") % ((game.inkling + game.incom + game.inscom)))
5583 prout(_("You have an initial allotment of %d stardates to complete") % int(game.intime))
5584 prout(_("your mission. As you proceed you may be given more time."))
5586 prout(_("You will have %d supporting starbases.") % (game.inbase))
5587 proutn(_("Starbase locations- "))
5589 prout(_("Stardate %d.") % int(game.state.date))
5591 prout(_("%d Klingons.") % (game.inkling + game.incom + game.inscom))
5592 prout(_("An unknown number of Romulans."))
5593 if game.state.nscrem:
5594 prout(_("And one (GULP) Super-Commander."))
5595 prout(_("%d stardates.") % int(game.intime))
5596 proutn(_("%d starbases in ") % game.inbase)
5597 for i in range(game.inbase):
5598 proutn(repr(game.state.baseq[i]))
5601 proutn(_("The Enterprise is currently in Quadrant %s") % game.quadrant)
5602 proutn(_(" Sector %s") % game.sector)
5604 prout(_("Good Luck!"))
5605 if game.state.nscrem:
5606 prout(_(" YOU'LL NEED IT."))
5609 setwnd(message_window)
5611 if len(game.enemies) - (thing == game.quadrant) - (game.tholian != None):
5613 if game.neutz: # bad luck to start in a Romulan Neutral Zone
5614 attack(torps_ok=False)
5617 "Choose your game type."
5619 game.tourn = game.length = 0
5621 game.skill = SKILL_NONE
5623 # if not scanner.inqueue: # Can start with command line options
5624 proutn(_("Would you like a regular, tournament, or saved game? "))
5626 if scanner.sees("tournament"):
5627 while scanner.nexttok() == "IHEOL":
5628 proutn(_("Type in tournament number-"))
5629 if scanner.real == 0:
5631 continue # We don't want a blank entry
5632 game.tourn = int(round(scanner.real))
5633 random.seed(scanner.real)
5635 logfp.write("# random.seed(%d)\n" % scanner.real)
5637 if scanner.sees("saved") or scanner.sees("frozen"):
5641 if game.passwd is None:
5643 if not game.alldone:
5644 game.thawed = True # No plaque if not finished
5648 if scanner.sees("regular"):
5650 proutn(_("What is \"%s\"? ") % scanner.token)
5652 while game.length==0 or game.skill==SKILL_NONE:
5653 if scanner.nexttok() == "IHALPHA":
5654 if scanner.sees("short"):
5656 elif scanner.sees("medium"):
5658 elif scanner.sees("long"):
5660 elif scanner.sees("novice"):
5661 game.skill = SKILL_NOVICE
5662 elif scanner.sees("fair"):
5663 game.skill = SKILL_FAIR
5664 elif scanner.sees("good"):
5665 game.skill = SKILL_GOOD
5666 elif scanner.sees("expert"):
5667 game.skill = SKILL_EXPERT
5668 elif scanner.sees("emeritus"):
5669 game.skill = SKILL_EMERITUS
5671 proutn(_("What is \""))
5672 proutn(scanner.token)
5677 proutn(_("Would you like a Short, Medium, or Long game? "))
5678 elif game.skill == SKILL_NONE:
5679 proutn(_("Are you a Novice, Fair, Good, Expert, or Emeritus player? "))
5680 # Choose game options -- added by ESR for SST2K
5681 if scanner.nexttok() != "IHALPHA":
5683 proutn(_("Choose your game style (plain, almy, fancy or just press enter): "))
5685 if scanner.sees("plain"):
5686 # Approximates the UT FORTRAN version.
5687 game.options &=~ (OPTION_THOLIAN | OPTION_PLANETS | OPTION_THINGY | OPTION_PROBE | OPTION_RAMMING | OPTION_MVBADDY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
5688 game.options |= OPTION_PLAIN
5689 elif scanner.sees("almy"):
5690 # Approximates Tom Almy's version.
5691 game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
5692 game.options |= OPTION_ALMY
5693 elif scanner.sees("fancy") or scanner.sees("\n"):
5695 elif len(scanner.token):
5696 proutn(_("What is \"%s\"?") % scanner.token)
5697 game.options &=~ OPTION_COLOR
5699 if game.passwd == "debug":
5701 prout("=== Debug mode enabled.")
5702 # Use parameters to generate initial values of things
5703 game.damfac = 0.5 * game.skill
5704 game.inbase = randrange(BASEMIN, BASEMAX+1)
5706 if game.options & OPTION_PLANETS:
5707 game.inplan += randrange(MAXUNINHAB/2, MAXUNINHAB+1)
5708 if game.options & OPTION_WORLDS:
5709 game.inplan += int(NINHAB)
5710 game.state.nromrem = game.inrom = randrange(2 *game.skill)
5711 game.state.nscrem = game.inscom = (game.skill > SKILL_FAIR)
5712 game.state.remtime = 7.0 * game.length
5713 game.intime = game.state.remtime
5714 game.state.remkl = game.inkling = 2.0*game.intime*((game.skill+1 - 2*randreal())*game.skill*0.1+.15)
5715 game.incom = min(MINCMDR, int(game.skill + 0.0625*game.inkling*randreal()))
5716 game.state.remres = (game.inkling+4*game.incom)*game.intime
5717 game.inresor = game.state.remres
5718 if game.inkling > 50:
5722 def dropin(iquad=None):
5723 "Drop a feature on a random dot in the current quadrant."
5725 w = randplace(QUADSIZE)
5726 if game.quad[w.i][w.j] == '.':
5728 if iquad is not None:
5729 game.quad[w.i][w.j] = iquad
5733 "Update our alert status."
5734 game.condition = "green"
5735 if game.energy < 1000.0:
5736 game.condition = "yellow"
5737 if game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons or game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans:
5738 game.condition = "red"
5740 game.condition="dead"
5743 "Drop new Klingon into current quadrant."
5744 return Enemy('K', loc=dropin(), power=randreal(300,450)+25.0*game.skill)
5747 "Sort enemies by distance so 'nearest' is meaningful."
5748 game.enemies.sort(key=lambda x: x.kdist)
5751 "Set up a new state of quadrant, for when we enter or re-enter it."
5754 game.neutz = game.inorbit = game.landed = False
5755 game.ientesc = game.iseenit = False
5756 # Create a blank quadrant
5757 game.quad = fill2d(QUADSIZE, lambda i, j: '.')
5759 # Attempt to escape Super-commander, so tbeam back!
5762 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
5763 # cope with supernova
5766 game.klhere = q.klingons
5767 game.irhere = q.romulans
5769 game.quad[game.sector.i][game.sector.j] = game.ship
5772 # Position ordinary Klingons
5773 for _i in range(game.klhere):
5775 # If we need a commander, promote a Klingon
5776 for cmdr in game.state.kcmdr:
5777 if cmdr == game.quadrant:
5778 e = game.enemies[game.klhere-1]
5779 game.quad[e.location.i][e.location.j] = 'C'
5780 e.power = randreal(950,1350) + 50.0*game.skill
5782 # If we need a super-commander, promote a Klingon
5783 if game.quadrant == game.state.kscmdr:
5785 game.quad[e.location.i][e.location.j] = 'S'
5786 e.power = randreal(1175.0, 1575.0) + 125.0*game.skill
5787 game.iscate = (game.state.remkl > 1)
5788 # Put in Romulans if needed
5789 for _i in range(q.romulans):
5790 Enemy('R', loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill)
5791 # If quadrant needs a starbase, put it in
5793 game.base = dropin('B')
5794 # If quadrant needs a planet, put it in
5796 game.iplnet = q.planet
5797 if not q.planet.inhabited:
5798 game.plnet = dropin('P')
5800 game.plnet = dropin('@')
5801 # Check for condition
5804 if game.irhere > 0 and game.klhere == 0:
5806 if not damaged(DRADIO):
5808 prout(_("LT. Uhura- \"Captain, an urgent message."))
5809 prout(_(" I'll put it on audio.\" CLICK"))
5811 prout(_("INTRUDER! YOU HAVE VIOLATED THE ROMULAN NEUTRAL ZONE."))
5812 prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!"))
5813 # Put in THING if needed
5814 if thing == game.quadrant:
5815 Enemy(etype='?', loc=dropin(),
5816 power=randreal(6000,6500.0)+250.0*game.skill)
5817 if not damaged(DSRSENS):
5819 prout(_("Mr. Spock- \"Captain, this is most unusual."))
5820 prout(_(" Please examine your short-range scan.\""))
5821 # Decide if quadrant needs a Tholian; lighten up if skill is low
5822 if game.options & OPTION_THOLIAN:
5823 if (game.skill < SKILL_GOOD and withprob(0.02)) or \
5824 (game.skill == SKILL_GOOD and withprob(0.05)) or \
5825 (game.skill > SKILL_GOOD and withprob(0.08)):
5828 w.i = withprob(0.5) * (QUADSIZE-1)
5829 w.j = withprob(0.5) * (QUADSIZE-1)
5830 if game.quad[w.i][w.j] == '.':
5832 game.tholian = Enemy(etype='T', loc=w,
5833 power=randrange(100, 500) + 25.0*game.skill)
5834 # Reserve unoccupied corners
5835 if game.quad[0][0]=='.':
5836 game.quad[0][0] = 'X'
5837 if game.quad[0][QUADSIZE-1]=='.':
5838 game.quad[0][QUADSIZE-1] = 'X'
5839 if game.quad[QUADSIZE-1][0]=='.':
5840 game.quad[QUADSIZE-1][0] = 'X'
5841 if game.quad[QUADSIZE-1][QUADSIZE-1]=='.':
5842 game.quad[QUADSIZE-1][QUADSIZE-1] = 'X'
5844 # And finally the stars
5845 for _i in range(q.stars):
5847 # Put in a few black holes
5848 for _i in range(1, 3+1):
5851 # Take out X's in corners if Tholian present
5853 if game.quad[0][0]=='X':
5854 game.quad[0][0] = '.'
5855 if game.quad[0][QUADSIZE-1]=='X':
5856 game.quad[0][QUADSIZE-1] = '.'
5857 if game.quad[QUADSIZE-1][0]=='X':
5858 game.quad[QUADSIZE-1][0] = '.'
5859 if game.quad[QUADSIZE-1][QUADSIZE-1]=='X':
5860 game.quad[QUADSIZE-1][QUADSIZE-1] = '.'
5863 "Set the self-destruct password."
5864 if game.options & OPTION_PLAIN:
5867 proutn(_("Please type in a secret password- "))
5869 game.passwd = scanner.token
5870 if game.passwd != None:
5874 game.passwd += chr(ord('a')+randrange(26))
5875 game.passwd += chr(ord('a')+randrange(26))
5876 game.passwd += chr(ord('a')+randrange(26))
5878 # Code from sst.c begins here
5881 ("SRSCAN", OPTION_TTY),
5882 ("STATUS", OPTION_TTY),
5883 ("REQUEST", OPTION_TTY),
5884 ("LRSCAN", OPTION_TTY),
5897 ("SENSORS", OPTION_PLANETS),
5898 ("ORBIT", OPTION_PLANETS),
5899 ("TRANSPORT", OPTION_PLANETS),
5900 ("MINE", OPTION_PLANETS),
5901 ("CRYSTALS", OPTION_PLANETS),
5902 ("SHUTTLE", OPTION_PLANETS),
5903 ("PLANETS", OPTION_PLANETS),
5908 ("PROBE", OPTION_PROBE),
5910 ("FREEZE", 0), # Synonym for SAVE
5916 ("SOS", 0), # Synonym for MAYDAY
5917 ("CALL", 0), # Synonym for MAYDAY
5924 "Generate a list of legal commands."
5925 prout(_("LEGAL COMMANDS ARE:"))
5927 for (key, opt) in commands:
5928 if not opt or (opt & game.options):
5929 proutn("%-12s " % key)
5931 if emitted % 5 == 4:
5936 "Browse on-line help."
5937 key = scanner.nexttok()
5940 setwnd(prompt_window)
5941 proutn(_("Help on what command? "))
5942 key = scanner.nexttok()
5943 setwnd(message_window)
5946 cmds = [x[0] for x in commands]
5947 if scanner.token.upper() in cmds or scanner.token.upper() == "ABBREV":
5954 cmd = scanner.token.upper()
5955 for directory in docpath:
5957 fp = open(os.path.join(directory, "sst.doc"), "r")
5962 prout(_("Spock- \"Captain, that information is missing from the"))
5963 prout(_(" computer. You need to find sst.doc and put it somewhere"))
5964 proutn(_(" in these directories: %s") % ":".join(docpath))
5966 # This used to continue: "You need to find SST.DOC and put
5967 # it in the current directory."
5970 linebuf = fp.readline()
5972 prout(_("Spock- \"Captain, there is no information on that command.\""))
5975 if linebuf[0] == '%' and linebuf[1] == '%' and linebuf[2] == ' ':
5976 linebuf = linebuf[3:].strip()
5977 if cmd.upper() == linebuf:
5980 prout(_("Spock- \"Captain, I've found the following information:\""))
5983 linebuf = fp.readline()
5984 if "******" in linebuf:
5990 "Command-interpretation loop."
5991 while True: # command loop
5993 while True: # get a command
5995 game.optime = game.justin = False
5997 setwnd(prompt_window)
6000 if scanner.nexttok() == "IHEOL":
6001 if game.options & OPTION_CURSES:
6004 elif scanner.token == "":
6008 setwnd(message_window)
6010 abandon_passed = False
6011 cmd = "" # Force cmd to persist after loop
6012 opt = 0 # Force opt to persist after loop
6013 for (cmd, opt) in commands:
6014 # commands after ABANDON cannot be abbreviated
6015 if cmd == "ABANDON":
6016 abandon_passed = True
6017 if cmd == scanner.token.upper() or (not abandon_passed \
6018 and cmd.startswith(scanner.token.upper())):
6023 elif opt and not (opt & game.options):
6027 if cmd == "SRSCAN": # srscan
6029 elif cmd == "STATUS": # status
6031 elif cmd == "REQUEST": # status request
6033 elif cmd == "LRSCAN": # long range scan
6034 lrscan(silent=False)
6035 elif cmd == "PHASERS": # phasers
6039 elif cmd in ("TORPEDO", "PHOTONS"): # photon torpedos
6043 elif cmd == "MOVE": # move under warp
6044 warp(wcourse=None, involuntary=False)
6045 elif cmd == "SHIELDS": # shields
6046 doshield(shraise=False)
6049 game.shldchg = False
6050 elif cmd == "DOCK": # dock at starbase
6053 attack(torps_ok=False)
6054 elif cmd == "DAMAGES": # damage reports
6056 elif cmd == "CHART": # chart
6058 elif cmd == "IMPULSE": # impulse
6060 elif cmd == "REST": # rest
6064 elif cmd == "WARP": # warp
6066 elif cmd == "SCORE": # score
6068 elif cmd == "SENSORS": # sensors
6070 elif cmd == "ORBIT": # orbit
6074 elif cmd == "TRANSPORT": # transport "beam"
6076 elif cmd == "MINE": # mine
6080 elif cmd == "CRYSTALS": # crystals
6084 elif cmd == "SHUTTLE": # shuttle
6088 elif cmd == "PLANETS": # Planet list
6090 elif cmd == "REPORT": # Game Report
6092 elif cmd == "COMPUTER": # use COMPUTER!
6094 elif cmd == "COMMANDS":
6096 elif cmd == "EMEXIT": # Emergency exit
6097 clrscr() # Hide screen
6098 freeze(True) # forced save
6099 raise SystemExit(1) # And quick exit
6100 elif cmd == "PROBE":
6101 probe() # Launch probe
6104 elif cmd == "ABANDON": # Abandon Ship
6106 elif cmd == "DESTRUCT": # Self Destruct
6108 elif cmd == "SAVE": # Save Game
6111 if game.skill > SKILL_GOOD:
6112 prout(_("WARNING--Saved games produce no plaques!"))
6113 elif cmd == "DEATHRAY": # Try a desparation measure
6117 elif cmd == "DEBUGCMD": # What do we want for debug???
6119 elif cmd == "MAYDAY": # Call for help
6124 game.alldone = True # quit the game
6129 break # Game has ended
6130 if game.optime != 0.0:
6133 break # Events did us in
6134 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6137 if hitme and not game.justin:
6138 attack(torps_ok=True)
6141 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6152 "Emit the name of an enemy or feature."
6153 if ch == 'R': s = _("Romulan")
6154 elif ch == 'K': s = _("Klingon")
6155 elif ch == 'C': s = _("Commander")
6156 elif ch == 'S': s = _("Super-commander")
6157 elif ch == '*': s = _("Star")
6158 elif ch == 'P': s = _("Planet")
6159 elif ch == 'B': s = _("Starbase")
6160 elif ch == ' ': s = _("Black hole")
6161 elif ch == 'T': s = _("Tholian")
6162 elif ch == '#': s = _("Tholian web")
6163 elif ch == '?': s = _("Stranger")
6164 elif ch == '@': s = _("Inhabited World")
6165 else: s = "Unknown??"
6168 def crmena(loud, enemy, loctype, w):
6169 "Emit the name of an enemy and his location."
6173 buf += cramen(enemy) + _(" at ")
6174 if loctype == "quadrant":
6175 buf += _("Quadrant ")
6176 elif loctype == "sector":
6178 return buf + repr(w)
6181 "Emit our ship name."
6182 return{'E':_("Enterprise"),'F':_("Faerie Queene")}.get(game.ship,"Ship???")
6185 "Emit a line of stars"
6186 prouts("******************************************************")
6190 return -avrage*math.log(1e-7 + randreal())
6192 def randplace(size):
6193 "Choose a random location."
6195 w.i = randrange(size)
6196 w.j = randrange(size)
6206 # Get a token from the user
6209 # Fill the token quue if nothing here
6210 while not self.inqueue:
6212 if curwnd==prompt_window:
6214 setwnd(message_window)
6221 self.inqueue = sline.lstrip().split() + ["\n"]
6222 # From here on in it's all looking at the queue
6223 self.token = self.inqueue.pop(0)
6224 if self.token == "\n":
6228 self.real = float(self.token)
6229 self.type = "IHREAL"
6234 self.token = self.token.lower()
6235 self.type = "IHALPHA"
6238 def append(self, tok):
6239 self.inqueue.append(tok)
6240 def push(self, tok):
6241 self.inqueue.insert(0, tok)
6245 # Demand input for next scan
6247 self.real = self.token = None
6249 # compares s to item and returns true if it matches to the length of s
6250 return s.startswith(self.token)
6252 # Round token value to nearest integer
6253 return int(round(self.real))
6257 if self.type != "IHREAL":
6262 if self.type != "IHREAL":
6268 return "<sstcanner: token=%s, type=%s, queue=%s>" % (self.token, self.type, self.inqueue)
6271 "Yes-or-no confirmation."
6275 if scanner.token == 'y':
6277 if scanner.token == 'n':
6280 proutn(_("Please answer with \"y\" or \"n\": "))
6283 "Complain about unparseable input."
6286 prout(_("Beg your pardon, Captain?"))
6289 "Access to the internals for debugging."
6290 proutn("Reset levels? ")
6292 if game.energy < game.inenrg:
6293 game.energy = game.inenrg
6294 game.shield = game.inshld
6295 game.torps = game.intorps
6296 game.lsupres = game.inlsr
6297 proutn("Reset damage? ")
6299 for i in range(NDEVICES):
6300 if game.damage[i] > 0.0:
6301 game.damage[i] = 0.0
6302 proutn("Toggle debug flag? ")
6304 game.idebug = not game.idebug
6306 prout("Debug output ON")
6308 prout("Debug output OFF")
6309 proutn("Cause selective damage? ")
6311 for i in range(NDEVICES):
6312 proutn("Kill %s?" % device[i])
6314 key = scanner.nexttok()
6315 if key == "IHALPHA" and scanner.sees("y"):
6316 game.damage[i] = 10.0
6317 proutn("Examine/change events? ")
6322 FSNOVA: "Supernova ",
6325 FBATTAK: "Base Attack ",
6326 FCDBAS: "Base Destroy ",
6327 FSCMOVE: "SC Move ",
6328 FSCDBAS: "SC Base Destroy ",
6329 FDSPROB: "Probe Move ",
6330 FDISTR: "Distress Call ",
6331 FENSLV: "Enslavement ",
6332 FREPRO: "Klingon Build ",
6334 for i in range(1, NEVENTS):
6337 proutn("%.2f" % (scheduled(i)-game.state.date))
6338 if i == FENSLV or i == FREPRO:
6340 proutn(" in %s" % ev.quadrant)
6345 key = scanner.nexttok()
6349 elif key == "IHREAL":
6350 ev = schedule(i, scanner.real)
6351 if i == FENSLV or i == FREPRO:
6353 proutn("In quadrant- ")
6354 key = scanner.nexttok()
6355 # "IHEOL" says to leave coordinates as they are
6358 prout("Event %d canceled, no x coordinate." % (i))
6361 w.i = int(round(scanner.real))
6362 key = scanner.nexttok()
6364 prout("Event %d canceled, no y coordinate." % (i))
6367 w.j = int(round(scanner.real))
6370 proutn("Induce supernova here? ")
6372 game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova = True
6375 if __name__ == '__main__':
6376 import getopt, socket
6378 #global line, thing, game
6382 game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY)
6383 if os.getenv("TERM"):
6384 game.options |= OPTION_CURSES
6386 game.options |= OPTION_TTY
6387 seed = int(time.time())
6388 (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:txV")
6390 for (switch, val) in options:
6393 replayfp = open(val, "r")
6395 sys.stderr.write("sst: can't open replay file %s\n" % val)
6398 line = replayfp.readline().strip()
6399 (leader, __, seed) = line.split()
6401 sys.stderr.write("sst2k: seed set to %s\n" % seed)
6402 line = replayfp.readline().strip()
6403 arguments += line.split()[2:]
6406 sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
6408 game.options |= OPTION_TTY
6409 game.options &=~ OPTION_CURSES
6410 elif switch == '-s':
6412 elif switch == '-t':
6413 game.options |= OPTION_TTY
6414 game.options &=~ OPTION_CURSES
6415 elif switch == '-x':
6417 elif switch == '-V':
6418 print("SST2K", version)
6421 sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n")
6423 # where to save the input in case of bugs
6424 if "TMPDIR" in os.environ:
6425 tmpdir = os.environ['TMPDIR']
6429 logfp = open(os.path.join(tmpdir, "sst-input.log"), "w")
6431 sys.stderr.write("sst: warning, can't open logfile\n")
6434 logfp.write("# seed %s\n" % seed)
6435 logfp.write("# options %s\n" % " ".join(arguments))
6436 logfp.write("# SST2K version %s\n" % version)
6437 logfp.write("# recorded by %s@%s on %s\n" % \
6438 (getpass.getuser(),socket.gethostname(),time.ctime()))
6440 scanner = sstscanner()
6441 for arg in arguments:
6445 while True: # Play a game
6446 setwnd(fullscreen_window)
6452 game.alldone = False
6460 if game.tourn and game.alldone:
6461 proutn(_("Do you want your score recorded?"))
6467 proutn(_("Do you want to play again? "))
6471 prout(_("May the Great Bird of the Galaxy roost upon your home planet."))
6475 except KeyboardInterrupt: