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, readline, pickle, random, copy, gettext, getpass
18 docpath = (".", "../doc", "/usr/share/doc/sst")
21 return gettext.gettext(st)
23 GALSIZE = 8 # Galaxy size in quadrants
24 NINHAB = (GALSIZE * GALSIZE // 2) # Number of inhabited worlds
25 MAXUNINHAB = 10 # Maximum uninhabited worlds
26 QUADSIZE = 10 # Quadrant size in sectors
27 BASEMIN = 2 # Minimum starbases
28 BASEMAX = (GALSIZE * GALSIZE // 12) # Maximum starbases
29 MAXKLGAME = 127 # Maximum Klingons per game
30 MAXKLQUAD = 9 # Maximum Klingons per quadrant
31 FULLCREW = 428 # Crew size. BSD Trek was 387, that's wrong
32 FOREVER = 1e30 # Time for the indefinite future
33 MAXBURST = 3 # Max # of torps you can launch in one turn
34 MINCMDR = 10 # Minimum number of Klingon commanders
35 DOCKFAC = 0.25 # Repair faster when docked
36 PHASEFAC = 2.0 # Unclear what this is, it was in the C version
56 class TrekError(Exception):
59 class JumpOut(Exception):
63 def __init__(self, x=None, y=None):
66 def valid_quadrant(self):
67 return self.i >= 0 and self.i < GALSIZE and self.j >= 0 and self.j < GALSIZE
68 def valid_sector(self):
69 return self.i >= 0 and self.i < QUADSIZE and self.j >= 0 and self.j < QUADSIZE
71 self.i = self.j = None
73 return self.i != None and self.j != None
74 def __eq__(self, other):
75 return other != None and self.i == other.i and self.j == other.j
76 def __ne__(self, other):
77 return other == None or self.i != other.i or self.j != other.j
78 def __add__(self, other):
79 return Coord(self.i+other.i, self.j+other.j)
80 def __sub__(self, other):
81 return Coord(self.i-other.i, self.j-other.j)
82 def __mul__(self, other):
83 return Coord(self.i*other, self.j*other)
84 def __rmul__(self, other):
85 return Coord(self.i*other, self.j*other)
86 def __div__(self, other):
87 return Coord(self.i/other, self.j/other)
88 def __mod__(self, other):
89 return Coord(self.i % other, self.j % other)
90 def __rdiv__(self, other):
91 return Coord(self.i/other, self.j/other)
92 def roundtogrid(self):
93 return Coord(int(round(self.i)), int(round(self.j)))
94 def distance(self, other=None):
97 return math.sqrt((self.i - other.i)**2 + (self.j - other.j)**2)
99 return 1.90985*math.atan2(self.j, self.i)
105 s.i = self.i / abs(self.i)
109 s.j = self.j / abs(self.j)
112 #print "Location %s -> %s" % (self, (self / QUADSIZE).roundtogrid())
113 return self.roundtogrid() / QUADSIZE
115 return self.roundtogrid() % QUADSIZE
118 s.i = self.i + randrange(-1, 2)
119 s.j = self.j + randrange(-1, 2)
122 if self.i == None or self.j == None:
124 return "%s - %s" % (self.i+1, self.j+1)
128 "Do not anger the Space Thingy!"
135 return (q.i, q.j) == (self.i, self.j)
139 self.name = None # string-valued if inhabited
140 self.quadrant = Coord() # quadrant located
141 self.pclass = None # could be ""M", "N", "O", or "destroyed"
142 self.crystals = "absent"# could be "mined", "present", "absent"
143 self.known = "unknown" # could be "unknown", "known", "shuttle_down"
144 self.inhabited = False # is it inhabited?
152 self.starbase = False
155 self.supernova = False
157 self.status = "secure" # Could be "secure", "distressed", "enslaved"
162 self.starbase = False
165 return "<%s,%s,%s>" % (self.klingons, self.starbase, self.stars)
167 def fill2d(size, fillfun):
168 "Fill an empty list in 2D."
170 for i in range(size):
172 for j in range(size):
173 lst[i].append(fillfun(i, j))
178 self.snap = False # snapshot taken
179 self.crew = 0 # crew complement
180 self.remkl = 0 # remaining klingons
181 self.nscrem = 0 # remaining super commanders
182 self.starkl = 0 # destroyed stars
183 self.basekl = 0 # destroyed bases
184 self.nromrem = 0 # Romulans remaining
185 self.nplankl = 0 # destroyed uninhabited planets
186 self.nworldkl = 0 # destroyed inhabited planets
187 self.planets = [] # Planet information
188 self.date = 0.0 # stardate
189 self.remres = 0 # remaining resources
190 self.remtime = 0 # remaining time
191 self.baseq = [] # Base quadrant coordinates
192 self.kcmdr = [] # Commander quadrant coordinates
193 self.kscmdr = Coord() # Supercommander quadrant coordinates
195 self.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
197 self.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
201 self.date = None # A real number
202 self.quadrant = None # A coord structure
205 OPTION_ALL = 0xffffffff
206 OPTION_TTY = 0x00000001 # old interface
207 OPTION_CURSES = 0x00000002 # new interface
208 OPTION_IOMODES = 0x00000003 # cover both interfaces
209 OPTION_PLANETS = 0x00000004 # planets and mining
210 OPTION_THOLIAN = 0x00000008 # Tholians and their webs (UT 1979 version)
211 OPTION_THINGY = 0x00000010 # Space Thingy can shoot back (Stas, 2005)
212 OPTION_PROBE = 0x00000020 # deep-space probes (DECUS version, 1980)
213 OPTION_SHOWME = 0x00000040 # bracket Enterprise in chart
214 OPTION_RAMMING = 0x00000080 # enemies may ram Enterprise (Almy)
215 OPTION_MVBADDY = 0x00000100 # more enemies can move (Almy)
216 OPTION_BLKHOLE = 0x00000200 # black hole may timewarp you (Stas, 2005)
217 OPTION_BASE = 0x00000400 # bases have good shields (Stas, 2005)
218 OPTION_WORLDS = 0x00000800 # logic for inhabited worlds (ESR, 2006)
219 OPTION_AUTOSCAN = 0x00001000 # automatic LRSCAN before CHART (ESR, 2006)
220 OPTION_PLAIN = 0x01000000 # user chose plain game
221 OPTION_ALMY = 0x02000000 # user chose Almy variant
222 OPTION_COLOR = 0x04000000 # enable color display (experimental, ESR, 2010)
241 NDEVICES = 16 # Number of devices
251 return (game.damage[dev] != 0.0)
253 return not damaged(DRADIO) or game.condition=="docked"
255 # Define future events
256 FSPY = 0 # Spy event happens always (no future[] entry)
257 # can cause SC to tractor beam Enterprise
258 FSNOVA = 1 # Supernova
259 FTBEAM = 2 # Commander tractor beams Enterprise
260 FSNAP = 3 # Snapshot for time warp
261 FBATTAK = 4 # Commander attacks base
262 FCDBAS = 5 # Commander destroys base
263 FSCMOVE = 6 # Supercommander moves (might attack base)
264 FSCDBAS = 7 # Supercommander destroys base
265 FDSPROB = 8 # Move deep space probe
266 FDISTR = 9 # Emit distress call from an inhabited world
267 FENSLV = 10 # Inhabited word is enslaved */
268 FREPRO = 11 # Klingons build a ship in an enslaved system
271 # Abstract out the event handling -- underlying data structures will change
272 # when we implement stateful events
273 def findevent(evtype):
274 return game.future[evtype]
277 def __init__(self, etype=None, loc=None, power=None):
279 self.location = Coord()
284 self.power = power # enemy energy level
285 game.enemies.append(self)
287 motion = (loc != self.location)
288 if self.location.i is not None and self.location.j is not None:
291 game.quad[self.location.i][self.location.j] = '#'
293 game.quad[self.location.i][self.location.j] = '.'
295 self.location = copy.copy(loc)
296 game.quad[self.location.i][self.location.j] = self.type
297 self.kdist = self.kavgd = (game.sector - loc).distance()
299 self.location = Coord()
300 self.kdist = self.kavgd = None
301 game.enemies.remove(self)
304 return "<%s,%s.%f>" % (self.type, self.location, self.power) # For debugging
308 self.options = None # Game options
309 self.state = Snapshot() # A snapshot structure
310 self.snapsht = Snapshot() # Last snapshot taken for time-travel purposes
311 self.quad = None # contents of our quadrant
312 self.damage = [0.0] * NDEVICES # damage encountered
313 self.future = [] # future events
317 self.future.append(Event())
318 self.passwd = None # Self Destruct password
320 self.quadrant = None # where we are in the large
321 self.sector = None # where we are in the small
322 self.tholian = None # Tholian enemy object
323 self.base = None # position of base in current quadrant
324 self.battle = None # base coordinates being attacked
325 self.plnet = None # location of planet in quadrant
326 self.gamewon = False # Finished!
327 self.ididit = False # action taken -- allows enemy to attack
328 self.alive = False # we are alive (not killed)
329 self.justin = False # just entered quadrant
330 self.shldup = False # shields are up
331 self.shldchg = False # shield is changing (affects efficiency)
332 self.iscate = False # super commander is here
333 self.ientesc = False # attempted escape from supercommander
334 self.resting = False # rest time
335 self.icraft = False # Kirk in Galileo
336 self.landed = False # party on planet (true), on ship (false)
337 self.alldone = False # game is now finished
338 self.neutz = False # Romulan Neutral Zone
339 self.isarmed = False # probe is armed
340 self.inorbit = False # orbiting a planet
341 self.imine = False # mining
342 self.icrystl = False # dilithium crystals aboard
343 self.iseenit = False # seen base attack report
344 self.thawed = False # thawed game
345 self.condition = None # "green", "yellow", "red", "docked", "dead"
346 self.iscraft = None # "onship", "offship", "removed"
347 self.skill = None # Player skill level
348 self.inkling = 0 # initial number of klingons
349 self.inbase = 0 # initial number of bases
350 self.incom = 0 # initial number of commanders
351 self.inscom = 0 # initial number of commanders
352 self.inrom = 0 # initial number of commanders
353 self.instar = 0 # initial stars
354 self.intorps = 0 # initial/max torpedoes
355 self.torps = 0 # number of torpedoes
356 self.ship = 0 # ship type -- 'E' is Enterprise
357 self.abandoned = 0 # count of crew abandoned in space
358 self.length = 0 # length of game
359 self.klhere = 0 # klingons here
360 self.casual = 0 # causalties
361 self.nhelp = 0 # calls for help
362 self.nkinks = 0 # count of energy-barrier crossings
363 self.iplnet = None # planet # in quadrant
364 self.inplan = 0 # initial planets
365 self.irhere = 0 # Romulans in quadrant
366 self.isatb = 0 # =2 if super commander is attacking base
367 self.tourn = None # tournament number
368 self.nprobes = 0 # number of probes available
369 self.inresor = 0.0 # initial resources
370 self.intime = 0.0 # initial time
371 self.inenrg = 0.0 # initial/max energy
372 self.inshld = 0.0 # initial/max shield
373 self.inlsr = 0.0 # initial life support resources
374 self.indate = 0.0 # initial date
375 self.energy = 0.0 # energy level
376 self.shield = 0.0 # shield level
377 self.warpfac = 0.0 # warp speed
378 self.lsupres = 0.0 # life support reserves
379 self.optime = 0.0 # time taken by current operation
380 self.damfac = 0.0 # damage factor
381 self.lastchart = 0.0 # time star chart was last updated
382 self.cryprob = 0.0 # probability that crystal will work
383 self.probe = None # object holding probe course info
384 self.height = 0.0 # height of orbit around planet
385 self.score = 0.0 # overall score
386 self.perdate = 0.0 # rate of kills
387 self.idebug = False # Debugging instrumentation enabled?
388 self.statekscmdr = None # No SuperCommander coordinates yet.
390 # Stas thinks this should be (C expression):
391 # game.state.remkl + len(game.state.kcmdr) > 0 ?
392 # game.state.remres/(game.state.remkl + 4*len(game.state.kcmdr)) : 99
393 # He says the existing expression is prone to divide-by-zero errors
394 # after killing the last klingon when score is shown -- perhaps also
395 # if the only remaining klingon is SCOM.
396 self.state.remtime = self.state.remres/(self.state.remkl + 4*len(self.state.kcmdr))
422 return random.random() < p
424 def randrange(*args):
425 return random.randrange(*args)
430 v *= args[0] # from [0, args[0])
432 v = args[0] + v*(args[1]-args[0]) # from [args[0], args[1])
435 # Code from ai.c begins here
438 "Would this quadrant welcome another Klingon?"
439 return iq.valid_quadrant() and \
440 not game.state.galaxy[iq.i][iq.j].supernova and \
441 game.state.galaxy[iq.i][iq.j].klingons < MAXKLQUAD
443 def tryexit(enemy, look, irun):
444 "A bad guy attempts to bug out."
446 iq.i = game.quadrant.i+(look.i+(QUADSIZE-1))/QUADSIZE - 1
447 iq.j = game.quadrant.j+(look.j+(QUADSIZE-1))/QUADSIZE - 1
448 if not welcoming(iq):
450 if enemy.type == 'R':
451 return False # Romulans cannot escape!
453 # avoid intruding on another commander's territory
454 if enemy.type == 'C':
455 if iq in game.state.kcmdr:
457 # refuse to leave if currently attacking starbase
458 if game.battle == game.quadrant:
460 # don't leave if over 1000 units of energy
461 if enemy.power > 1000.0:
463 oldloc = copy.copy(enemy.location)
464 # handle local matters related to escape
467 if game.condition != "docked":
469 # Handle global matters related to escape
470 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
471 game.state.galaxy[iq.i][iq.j].klingons += 1
472 if enemy.type == 'S':
476 schedule(FSCMOVE, 0.2777)
478 game.state.kscmdr = iq
480 for cmdr in game.state.kcmdr:
481 if cmdr == game.quadrant:
482 game.state.kcmdr.append(iq)
484 # report move out of quadrant.
485 return [(True, enemy, oldloc, ibq)]
487 # The bad-guy movement algorithm:
489 # 1. Enterprise has "force" based on condition of phaser and photon torpedoes.
490 # If both are operating full strength, force is 1000. If both are damaged,
491 # force is -1000. Having shields down subtracts an additional 1000.
493 # 2. Enemy has forces equal to the energy of the attacker plus
494 # 100*(K+R) + 500*(C+S) - 400 for novice through good levels OR
495 # 346*K + 400*R + 500*(C+S) - 400 for expert and emeritus.
497 # Attacker Initial energy levels (nominal):
498 # Klingon Romulan Commander Super-Commander
499 # Novice 400 700 1200
501 # Good 450 800 1300 1750
502 # Expert 475 850 1350 1875
503 # Emeritus 500 900 1400 2000
504 # VARIANCE 75 200 200 200
506 # Enemy vessels only move prior to their attack. In Novice - Good games
507 # only commanders move. In Expert games, all enemy vessels move if there
508 # is a commander present. In Emeritus games all enemy vessels move.
510 # 3. If Enterprise is not docked, an aggressive action is taken if enemy
511 # forces are 1000 greater than Enterprise.
513 # Agressive action on average cuts the distance between the ship and
514 # the enemy to 1/4 the original.
516 # 4. At lower energy advantage, movement units are proportional to the
517 # advantage with a 650 advantage being to hold ground, 800 to move forward
518 # 1, 950 for two, 150 for back 4, etc. Variance of 100.
520 # If docked, is reduced by roughly 1.75*game.skill, generally forcing a
521 # retreat, especially at high skill levels.
523 # 5. Motion is limited to skill level, except for SC hi-tailing it out.
525 def movebaddy(enemy):
526 "Tactical movement for the bad guys."
530 # This should probably be just (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
531 if game.skill >= SKILL_EXPERT:
532 nbaddys = (((game.quadrant in game.state.kcmdr)*2 + (game.state.kscmdr==game.quadrant)*2+game.klhere*1.23+game.irhere*1.5)/2.0)
534 nbaddys = (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
535 old_dist = enemy.kdist
536 mdist = int(old_dist + 0.5) # Nearest integer distance
537 # If SC, check with spy to see if should hi-tail it
538 if enemy.type == 'S' and \
539 (enemy.power <= 500.0 or (game.condition=="docked" and not damaged(DPHOTON))):
543 # decide whether to advance, retreat, or hold position
544 forces = enemy.power+100.0*len(game.enemies)+400*(nbaddys-1)
546 forces += 1000 # Good for enemy if shield is down!
547 if not damaged(DPHASER) or not damaged(DPHOTON):
548 if damaged(DPHASER): # phasers damaged
551 forces -= 0.2*(game.energy - 2500.0)
552 if damaged(DPHOTON): # photon torpedoes damaged
555 forces -= 50.0*game.torps
557 # phasers and photon tubes both out!
560 if forces <= 1000.0 and game.condition != "docked": # Typical situation
561 motion = ((forces + randreal(200))/150.0) - 5.0
563 if forces > 1000.0: # Very strong -- move in for kill
564 motion = (1.0 - randreal())**2 * old_dist + 1.0
565 if game.condition == "docked" and (game.options & OPTION_BASE): # protected by base -- back off !
566 motion -= game.skill*(2.0-randreal()**2)
568 proutn("=== MOTION = %d, FORCES = %1.2f, " % (motion, forces))
569 # don't move if no motion
572 # Limit motion according to skill
573 if abs(motion) > game.skill:
578 # calculate preferred number of steps
579 nsteps = abs(int(motion))
580 if motion > 0 and nsteps > mdist:
581 nsteps = mdist # don't overshoot
582 if nsteps > QUADSIZE:
583 nsteps = QUADSIZE # This shouldn't be necessary
585 nsteps = 1 # This shouldn't be necessary
587 proutn("NSTEPS = %d:" % nsteps)
588 # Compute preferred values of delta X and Y
589 m = game.sector - enemy.location
590 if 2.0 * abs(m.i) < abs(m.j):
592 if 2.0 * abs(m.j) < abs(game.sector.i-enemy.location.i):
594 m = (motion * m).sgn()
595 goto = enemy.location
597 for ll in range(nsteps):
599 proutn(" %d" % (ll+1))
600 # Check if preferred position available
611 attempts = 0 # Settle mysterious hang problem
612 while attempts < 20 and not success:
614 if look.i < 0 or look.i >= QUADSIZE:
616 return tryexit(enemy, look, irun)
617 if krawli == m.i or m.j == 0:
619 look.i = goto.i + krawli
621 elif look.j < 0 or look.j >= QUADSIZE:
623 return tryexit(enemy, look, irun)
624 if krawlj == m.j or m.i == 0:
626 look.j = goto.j + krawlj
628 elif (game.options & OPTION_RAMMING) and game.quad[look.i][look.j] != '.':
629 # See if enemy should ram ship
630 if game.quad[look.i][look.j] == game.ship and \
631 (enemy.type == 'C' or enemy.type == 'S'):
632 collision(rammed=True, enemy=enemy)
634 if krawli != m.i and m.j != 0:
635 look.i = goto.i + krawli
637 elif krawlj != m.j and m.i != 0:
638 look.j = goto.j + krawlj
641 break # we have failed
652 # Enemy moved, but is still in sector
653 return [(False, enemy, old_dist, goto)]
656 "Sequence Klingon tactical movement."
659 # Figure out which Klingon is the commander (or Supercommander)
662 if game.quadrant in game.state.kcmdr:
663 for enemy in game.enemies:
664 if enemy.type == 'C':
665 tacmoves += movebaddy(enemy)
666 if game.state.kscmdr == game.quadrant:
667 for enemy in game.enemies:
668 if enemy.type == 'S':
669 tacmoves += movebaddy(enemy)
671 # If skill level is high, move other Klingons and Romulans too!
672 # Move these last so they can base their actions on what the
674 if game.skill >= SKILL_EXPERT and (game.options & OPTION_MVBADDY):
675 for enemy in game.enemies:
676 if enemy.type in ('K', 'R'):
677 tacmoves += movebaddy(enemy)
680 def movescom(iq, avoid):
681 "Commander movement helper."
682 # Avoid quadrants with bases if we want to avoid Enterprise
683 if not welcoming(iq) or (avoid and iq in game.state.baseq):
685 if game.justin and not game.iscate:
688 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons -= 1
689 game.state.kscmdr = iq
690 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons += 1
691 if game.state.kscmdr == game.quadrant:
692 # SC has scooted, remove him from current quadrant
697 for enemy in game.enemies:
698 if enemy.type == 'S':
701 if game.condition != "docked":
704 # check for a helpful planet
705 for i in range(game.inplan):
706 if game.state.planets[i].quadrant == game.state.kscmdr and \
707 game.state.planets[i].crystals == "present":
709 game.state.planets[i].pclass = "destroyed"
710 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].planet = None
713 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
714 proutn(_(" a planet in Quadrant %s has been destroyed") % game.state.kscmdr)
715 prout(_(" by the Super-commander.\""))
717 return True # looks good!
719 def supercommander():
720 "Move the Super Commander."
727 prout("== SUPERCOMMANDER")
728 # Decide on being active or passive
729 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 \
730 (game.state.date-game.indate) < 3.0)
731 if not game.iscate and avoid:
732 # compute move away from Enterprise
733 idelta = game.state.kscmdr-game.quadrant
734 if idelta.distance() > 2.0:
736 idelta.i = game.state.kscmdr.j-game.quadrant.j
737 idelta.j = game.quadrant.i-game.state.kscmdr.i
739 # compute distances to starbases
740 if not game.state.baseq:
744 sc = game.state.kscmdr
745 for (i, base) in enumerate(game.state.baseq):
746 basetbl.append((i, (base - sc).distance()))
747 if game.state.baseq > 1:
748 basetbl.sort(key=lambda x: x[1])
749 # look for nearest base without a commander, no Enterprise, and
750 # without too many Klingons, and not already under attack.
751 ifindit = iwhichb = 0
752 for (i2, base) in enumerate(game.state.baseq):
753 i = basetbl[i2][0] # bug in original had it not finding nearest
754 if base == game.quadrant or base == game.battle or not welcoming(base):
756 # if there is a commander, and no other base is appropriate,
757 # we will take the one with the commander
758 for cmdr in game.state.kcmdr:
759 if base == cmdr and ifindit != 2:
763 else: # no commander -- use this one
768 return # Nothing suitable -- wait until next time
769 ibq = game.state.baseq[iwhichb]
770 # decide how to move toward base
771 idelta = ibq - game.state.kscmdr
772 # Maximum movement is 1 quadrant in either or both axes
773 idelta = idelta.sgn()
774 # try moving in both x and y directions
775 # there was what looked like a bug in the Almy C code here,
776 # but it might be this translation is just wrong.
777 iq = game.state.kscmdr + idelta
778 if not movescom(iq, avoid):
779 # failed -- try some other maneuvers
780 if idelta.i == 0 or idelta.j == 0:
783 iq.j = game.state.kscmdr.j + 1
784 if not movescom(iq, avoid):
785 iq.j = game.state.kscmdr.j - 1
788 iq.i = game.state.kscmdr.i + 1
789 if not movescom(iq, avoid):
790 iq.i = game.state.kscmdr.i - 1
793 # try moving just in x or y
794 iq.j = game.state.kscmdr.j
795 if not movescom(iq, avoid):
796 iq.j = game.state.kscmdr.j + idelta.j
797 iq.i = game.state.kscmdr.i
800 if len(game.state.baseq) == 0:
803 for ibq in game.state.baseq:
804 if ibq == game.state.kscmdr and game.state.kscmdr == game.battle:
807 return # no, don't attack base!
810 schedule(FSCDBAS, randreal(1.0, 3.0))
811 if is_scheduled(FCDBAS):
812 postpone(FSCDBAS, scheduled(FCDBAS)-game.state.date)
813 if not communicating():
817 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") \
819 prout(_(" reports that it is under attack from the Klingon Super-commander."))
820 proutn(_(" It can survive until stardate %d.\"") \
821 % int(scheduled(FSCDBAS)))
824 prout(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
828 game.optime = 0.0 # actually finished
830 # Check for intelligence report
831 if not game.idebug and \
833 (not communicating()) or \
834 not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].charted):
837 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
838 proutn(_(" the Super-commander is in Quadrant %s,") % game.state.kscmdr)
843 if not game.tholian or game.justin:
846 if game.tholian.location.i == 0 and game.tholian.location.j == 0:
849 elif game.tholian.location.i == 0 and game.tholian.location.j == QUADSIZE-1:
852 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == QUADSIZE-1:
855 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == 0:
859 # something is wrong!
860 game.tholian.move(None)
861 prout("***Internal error: Tholian in a bad spot.")
863 # do nothing if we are blocked
864 if game.quad[tid.i][tid.j] not in ('.', '#'):
866 here = copy.copy(game.tholian.location)
867 delta = (tid - game.tholian.location).sgn()
869 while here.i != tid.i:
871 if game.quad[here.i][here.j] == '.':
872 game.tholian.move(here)
874 while here.j != tid.j:
876 if game.quad[here.i][here.j] == '.':
877 game.tholian.move(here)
878 # check to see if all holes plugged
879 for i in range(QUADSIZE):
880 if game.quad[0][i] != '#' and game.quad[0][i] != 'T':
882 if game.quad[QUADSIZE-1][i] != '#' and game.quad[QUADSIZE-1][i] != 'T':
884 if game.quad[i][0] != '#' and game.quad[i][0] != 'T':
886 if game.quad[i][QUADSIZE-1] != '#' and game.quad[i][QUADSIZE-1] != 'T':
888 # All plugged up -- Tholian splits
889 game.quad[game.tholian.location.i][game.tholian.location.j] = '#'
891 prout(crmena(True, 'T', "sector", game.tholian) + _(" completes web."))
892 game.tholian.move(None)
895 # Code from battle.c begins here
897 def doshield(shraise):
898 "Change shield status."
904 key = scanner.nexttok()
906 if scanner.sees("transfer"):
910 prout(_("Shields damaged and down."))
912 if scanner.sees("up"):
914 elif scanner.sees("down"):
917 proutn(_("Do you wish to change shield energy? "))
920 elif damaged(DSHIELD):
921 prout(_("Shields damaged and down."))
924 proutn(_("Shields are up. Do you want them down? "))
931 proutn(_("Shields are down. Do you want them up? "))
937 if action == "SHUP": # raise shields
939 prout(_("Shields already up."))
943 if game.condition != "docked":
945 prout(_("Shields raised."))
948 prout(_("Shields raising uses up last of energy."))
953 elif action == "SHDN":
955 prout(_("Shields already down."))
959 prout(_("Shields lowered."))
962 elif action == "NRG":
963 while scanner.nexttok() != "IHREAL":
965 proutn(_("Energy to transfer to shields- "))
970 if nrg > game.energy:
971 prout(_("Insufficient ship energy."))
974 if game.shield+nrg >= game.inshld:
975 prout(_("Shield energy maximized."))
976 if game.shield+nrg > game.inshld:
977 prout(_("Excess energy requested returned to ship energy"))
978 game.energy -= game.inshld-game.shield
979 game.shield = game.inshld
981 if nrg < 0.0 and game.energy-nrg > game.inenrg:
982 # Prevent shield drain loophole
984 prout(_("Engineering to bridge--"))
985 prout(_(" Scott here. Power circuit problem, Captain."))
986 prout(_(" I can't drain the shields."))
989 if game.shield+nrg < 0:
990 prout(_("All shield energy transferred to ship."))
991 game.energy += game.shield
994 proutn(_("Scotty- \""))
996 prout(_("Transferring energy to shields.\""))
998 prout(_("Draining energy from shields.\""))
1004 "Choose a device to damage, at random."
1006 105, # DSRSENS: short range scanners 10.5%
1007 105, # DLRSENS: long range scanners 10.5%
1008 120, # DPHASER: phasers 12.0%
1009 120, # DPHOTON: photon torpedoes 12.0%
1010 25, # DLIFSUP: life support 2.5%
1011 65, # DWARPEN: warp drive 6.5%
1012 70, # DIMPULS: impulse engines 6.5%
1013 145, # DSHIELD: deflector shields 14.5%
1014 30, # DRADIO: subspace radio 3.0%
1015 45, # DSHUTTL: shuttle 4.5%
1016 15, # DCOMPTR: computer 1.5%
1017 20, # NAVCOMP: navigation system 2.0%
1018 75, # DTRANSP: transporter 7.5%
1019 20, # DSHCTRL: high-speed shield controller 2.0%
1020 10, # DDRAY: death ray 1.0%
1021 30, # DDSP: deep-space probes 3.0%
1023 assert(sum(weights) == 1000)
1024 idx = randrange(1000)
1026 for (i, w) in enumerate(weights):
1030 return None # we should never get here
1032 def collision(rammed, enemy):
1033 "Collision handling for rammong events."
1034 prouts(_("***RED ALERT! RED ALERT!"))
1036 prout(_("***COLLISION IMMINENT."))
1040 hardness = {'R':1.5, 'C':2.0, 'S':2.5, 'T':0.5, '?':4.0}.get(enemy.type, 1.0)
1042 proutn(_(" rammed by "))
1045 proutn(crmena(False, enemy.type, "sector", enemy.location))
1047 proutn(_(" (original position)"))
1049 deadkl(enemy.location, enemy.type, game.sector)
1050 proutn("***" + crmshp() + " heavily damaged.")
1051 icas = randrange(10, 30)
1052 prout(_("***Sickbay reports %d casualties") % icas)
1054 game.state.crew -= icas
1055 # In the pre-SST2K version, all devices got equiprobably damaged,
1056 # which was silly. Instead, pick up to half the devices at
1057 # random according to our weighting table,
1058 ncrits = randrange(NDEVICES/2)
1062 if game.damage[dev] < 0:
1064 extradm = (10.0*hardness*randreal()+1.0)*game.damfac
1065 # Damage for at least time of travel!
1066 game.damage[dev] += game.optime + extradm
1068 prout(_("***Shields are down."))
1069 if game.state.remkl + len(game.state.kcmdr) + game.state.nscrem:
1076 def torpedo(origin, bearing, dispersion, number, nburst):
1077 "Let a photon torpedo fly"
1078 if not damaged(DSRSENS) or game.condition == "docked":
1079 setwnd(srscan_window)
1081 setwnd(message_window)
1082 ac = bearing + 0.25*dispersion # dispersion is a random variable
1083 bullseye = (15.0 - bearing)*0.5235988
1084 track = course(bearing=ac, distance=QUADSIZE, origin=cartesian(origin))
1085 bumpto = Coord(0, 0)
1086 # Loop to move a single torpedo
1087 setwnd(message_window)
1088 for step in range(1, QUADSIZE*2):
1089 if not track.nexttok():
1092 if not w.valid_sector():
1094 iquad = game.quad[w.i][w.j]
1095 tracktorpedo(w, step, number, nburst, iquad)
1099 setwnd(message_window)
1100 if not damaged(DSRSENS) or game.condition == "docked":
1101 skip(1) # start new line after text track
1102 if iquad in ('E', 'F'): # Hit our ship
1104 prout(_("Torpedo hits %s.") % crmshp())
1105 hit = 700.0 + randreal(100) - \
1106 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1107 newcnd() # we're blown out of dock
1108 if game.landed or game.condition == "docked":
1109 return hit # Cheat if on a planet
1110 # In the C/FORTRAN version, dispersion was 2.5 radians, which
1111 # is 143 degrees, which is almost exactly 4.8 clockface units
1112 displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
1113 displacement.nexttok()
1114 bumpto = displacement.sector()
1115 if not bumpto.valid_sector():
1117 if game.quad[bumpto.i][bumpto.j] == ' ':
1120 if game.quad[bumpto.i][bumpto.j] != '.':
1121 # can't move into object
1123 game.sector = bumpto
1125 game.quad[w.i][w.j] = '.'
1126 game.quad[bumpto.i][bumpto.j] = iquad
1127 prout(_(" displaced by blast to Sector %s ") % bumpto)
1128 for enemy in game.enemies:
1129 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1132 elif iquad in ('C', 'S', 'R', 'K'): # Hit a regular enemy
1134 if iquad in ('C', 'S') and withprob(0.05):
1135 prout(crmena(True, iquad, "sector", w) + _(" uses anti-photon device;"))
1136 prout(_(" torpedo neutralized."))
1138 for enemy in game.enemies:
1139 if w == enemy.location:
1140 kp = math.fabs(enemy.power)
1141 h1 = 700.0 + randrange(100) - \
1142 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1150 if enemy.power == 0:
1153 proutn(crmena(True, iquad, "sector", w))
1154 displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
1155 displacement.nexttok()
1156 bumpto = displacement.sector()
1157 if not bumpto.valid_sector():
1158 prout(_(" damaged but not destroyed."))
1160 if game.quad[bumpto.i][bumpto.j] == ' ':
1161 prout(_(" buffeted into black hole."))
1162 deadkl(w, iquad, bumpto)
1163 if game.quad[bumpto.i][bumpto.j] != '.':
1164 prout(_(" damaged but not destroyed."))
1166 prout(_(" damaged-- displaced by blast to Sector %s ")%bumpto)
1167 enemy.location = bumpto
1168 game.quad[w.i][w.j] = '.'
1169 game.quad[bumpto.i][bumpto.j] = iquad
1170 for enemy in game.enemies:
1171 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1175 prout("Internal error, no enemy where expected!")
1178 elif iquad == 'B': # Hit a base
1180 prout(_("***STARBASE DESTROYED.."))
1181 game.state.baseq = [x for x in game.state.baseq if x != game.quadrant]
1182 game.quad[w.i][w.j] = '.'
1183 game.base.invalidate()
1184 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
1185 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = False
1186 game.state.basekl += 1
1189 elif iquad == 'P': # Hit a planet
1190 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1191 game.state.nplankl += 1
1192 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1193 game.iplnet.pclass = "destroyed"
1195 game.plnet.invalidate()
1196 game.quad[w.i][w.j] = '.'
1198 # captain perishes on planet
1201 elif iquad == '@': # Hit an inhabited world -- very bad!
1202 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1203 game.state.nworldkl += 1
1204 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1205 game.iplnet.pclass = "destroyed"
1207 game.plnet.invalidate()
1208 game.quad[w.i][w.j] = '.'
1210 # captain perishes on planet
1212 prout(_("The torpedo destroyed an inhabited planet."))
1214 elif iquad == '*': # Hit a star
1218 prout(crmena(True, '*', "sector", w) + _(" unaffected by photon blast."))
1220 elif iquad == '?': # Hit a thingy
1221 if not (game.options & OPTION_THINGY) or withprob(0.3):
1223 prouts(_("AAAAIIIIEEEEEEEEAAAAAAAAUUUUUGGGGGHHHHHHHHHHHH!!!"))
1225 prouts(_(" HACK! HACK! HACK! *CHOKE!* "))
1227 proutn(_("Mr. Spock-"))
1228 prouts(_(" \"Fascinating!\""))
1232 # Stas Sergeev added the possibility that
1233 # you can shove the Thingy and piss it off.
1234 # It then becomes an enemy and may fire at you.
1237 elif iquad == ' ': # Black hole
1239 prout(crmena(True, ' ', "sector", w) + _(" swallows torpedo."))
1241 elif iquad == '#': # hit the web
1243 prout(_("***Torpedo absorbed by Tholian web."))
1245 elif iquad == 'T': # Hit a Tholian
1246 h1 = 700.0 + randrange(100) - \
1247 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1250 game.quad[w.i][w.j] = '.'
1255 proutn(crmena(True, 'T', "sector", w))
1257 prout(_(" survives photon blast."))
1259 prout(_(" disappears."))
1260 game.tholian.move(None)
1261 game.quad[w.i][w.j] = '#'
1266 proutn("Don't know how to handle torpedo collision with ")
1267 proutn(crmena(True, iquad, "sector", w))
1272 setwnd(message_window)
1273 prout(_("Torpedo missed."))
1277 "Critical-hit resolution."
1278 if hit < (275.0-25.0*game.skill)*randreal(1.0, 1.5):
1280 ncrit = int(1.0 + hit/(500.0+randreal(100)))
1281 proutn(_("***CRITICAL HIT--"))
1282 # Select devices and cause damage
1287 # Cheat to prevent shuttle damage unless on ship
1288 if not (game.damage[j]<0.0 or (j == DSHUTTL and game.iscraft != "onship")):
1291 extradm = (hit*game.damfac)/(ncrit*randreal(75, 100))
1292 game.damage[j] += extradm
1295 for (i, j) in enumerate(cdam):
1297 if skipcount % 3 == 2 and i < len(cdam)-1:
1302 prout(_(" damaged."))
1303 if damaged(DSHIELD) and game.shldup:
1304 prout(_("***Shields knocked down."))
1307 def attack(torps_ok):
1308 # bad guy attacks us
1309 # torps_ok == False forces use of phasers in an attack
1310 # game could be over at this point, check
1320 prout("=== ATTACK!")
1321 # Tholian gets to move before attacking
1324 # if you have just entered the RNZ, you'll get a warning
1325 if game.neutz: # The one chance not to be attacked
1328 # commanders get a chance to tac-move towards you
1329 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:
1330 for (bugout, enemy, old, goto) in moveklings():
1332 # we know about this if either short or long range
1333 # sensors are working
1334 if damaged(DSRSENS) and damaged(DLRSENS) \
1335 and game.condition != "docked":
1336 prout(crmena(True, enemy.type, "sector", old) + \
1337 (_(" escapes to Quadrant %s (and regains strength).") % goto))
1338 else: # Enemy still in-sector
1339 if enemy.move(goto):
1340 if not damaged(DSRSENS) or game.condition == "docked":
1341 proutn(_("*** %s from Sector %s") % (cramen(enemy.type), enemy.location))
1342 if enemy.kdist < old:
1343 proutn(_(" advances to "))
1345 proutn(_(" retreats to "))
1346 prout("Sector %s." % goto)
1348 # if no enemies remain after movement, we're done
1349 if len(game.enemies) == 0 or (len(game.enemies) == 1 and thing.at(game.quadrant) and not thing.angered):
1351 # set up partial hits if attack happens during shield status change
1352 pfac = 1.0/game.inshld
1354 chgfac = 0.25 + randreal(0.5)
1356 # message verbosity control
1357 if game.skill <= SKILL_FAIR:
1359 for enemy in game.enemies:
1361 continue # too weak to attack
1362 # compute hit strength and diminish shield power
1364 # Increase chance of photon torpedos if docked or enemy energy is low
1365 if game.condition == "docked":
1367 if enemy.power < 500:
1369 if enemy.type == 'T' or (enemy.type == '?' and not thing.angered):
1371 # different enemies have different probabilities of throwing a torp
1372 usephasers = not torps_ok or \
1373 (enemy.type == 'K' and r > 0.0005) or \
1374 (enemy.type == 'C' and r > 0.015) or \
1375 (enemy.type == 'R' and r > 0.3) or \
1376 (enemy.type == 'S' and r > 0.07) or \
1377 (enemy.type == '?' and r > 0.05)
1378 if usephasers: # Enemy uses phasers
1379 if game.condition == "docked":
1380 continue # Don't waste the effort!
1381 attempt = True # Attempt to attack
1382 dustfac = randreal(0.8, 0.85)
1383 hit = enemy.power*math.pow(dustfac, enemy.kavgd)
1385 else: # Enemy uses photon torpedo
1386 # We should be able to make the bearing() method work here
1387 pcourse = 1.90985*math.atan2(game.sector.j-enemy.location.j, enemy.location.i-game.sector.i)
1389 proutn(_("***TORPEDO INCOMING"))
1390 if not damaged(DSRSENS):
1391 proutn(_(" From ") + crmena(False, enemy.type, where, enemy.location))
1394 dispersion = (randreal()+randreal())*0.5 - 0.5
1395 dispersion += 0.002*enemy.power*dispersion
1396 hit = torpedo(enemy.location, pcourse, dispersion, number=1, nburst=1)
1397 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
1398 finish(FWON) # Klingons did themselves in!
1399 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.alldone:
1400 return # Supernova or finished
1403 # incoming phaser or torpedo, shields may dissipate it
1404 if game.shldup or game.shldchg or game.condition == "docked":
1405 # shields will take hits
1406 propor = pfac * game.shield
1407 if game.condition == "docked":
1411 hitsh = propor*chgfac*hit+1.0
1413 if absorb > game.shield:
1414 absorb = game.shield
1415 game.shield -= absorb
1417 # taking a hit blasts us out of a starbase dock
1418 if game.condition == "docked":
1420 # but the shields may take care of it
1421 if propor > 0.1 and hit < 0.005*game.energy:
1423 # hit from this opponent got through shields, so take damage
1425 proutn(_("%d unit hit") % int(hit))
1426 if (damaged(DSRSENS) and usephasers) or game.skill<=SKILL_FAIR:
1427 proutn(_(" on the ") + crmshp())
1428 if not damaged(DSRSENS) and usephasers:
1429 prout(_(" from ") + crmena(False, enemy.type, where, enemy.location))
1431 # Decide if hit is critical
1437 if game.energy <= 0:
1438 # Returning home upon your shield, not with it...
1441 if not attempt and game.condition == "docked":
1442 prout(_("***Enemies decide against attacking your ship."))
1443 percent = 100.0*pfac*game.shield+0.5
1445 # Shields fully protect ship
1446 proutn(_("Enemy attack reduces shield strength to "))
1448 # Emit message if starship suffered hit(s)
1450 proutn(_("Energy left %2d shields ") % int(game.energy))
1453 elif not damaged(DSHIELD):
1456 proutn(_("damaged, "))
1457 prout(_("%d%%, torpedoes left %d") % (percent, game.torps))
1458 # Check if anyone was hurt
1459 if hitmax >= 200 or hittot >= 500:
1460 icas = randrange(int(hittot * 0.015))
1463 prout(_("Mc Coy- \"Sickbay to bridge. We suffered %d casualties") % icas)
1464 prout(_(" in that last attack.\""))
1466 game.state.crew -= icas
1467 # After attack, reset average distance to enemies
1468 for enemy in game.enemies:
1469 enemy.kavgd = enemy.kdist
1473 def deadkl(w, etype, mv):
1474 "Kill a Klingon, Tholian, Romulan, or Thingy."
1475 # Added mv to allow enemy to "move" before dying
1476 proutn(crmena(True, etype, "sector", mv))
1477 # Decide what kind of enemy it is and update appropriately
1479 # Chalk up a Romulan
1480 game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans -= 1
1482 game.state.nromrem -= 1
1491 # Killed some type of Klingon
1492 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
1495 game.state.kcmdr.remove(game.quadrant)
1497 if game.state.kcmdr:
1498 schedule(FTBEAM, expran(1.0*game.incom/len(game.state.kcmdr)))
1499 if is_scheduled(FCDBAS) and game.battle == game.quadrant:
1502 game.state.remkl -= 1
1504 game.state.nscrem -= 1
1505 game.state.kscmdr.invalidate()
1510 # For each kind of enemy, finish message to player
1511 prout(_(" destroyed."))
1512 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
1515 # Remove enemy ship from arrays describing local conditions
1516 for e in game.enemies:
1523 "Return None if target is invalid, otherwise return a course angle."
1524 if not w.valid_sector():
1528 # C code this was translated from is wacky -- why the sign reversal?
1529 delta.j = (w.j - game.sector.j)
1530 delta.i = (game.sector.i - w.i)
1531 if delta == Coord(0, 0):
1533 prout(_("Spock- \"Bridge to sickbay. Dr. McCoy,"))
1534 prout(_(" I recommend an immediate review of"))
1535 prout(_(" the Captain's psychological profile.\""))
1538 return delta.bearing()
1541 "Launch photon torpedo salvo."
1544 if damaged(DPHOTON):
1545 prout(_("Photon tubes damaged."))
1549 prout(_("No torpedoes left."))
1552 # First, get torpedo count
1555 if scanner.token == "IHALPHA":
1558 elif scanner.token == "IHEOL" or not scanner.waiting():
1559 prout(_("%d torpedoes left.") % game.torps)
1561 proutn(_("Number of torpedoes to fire- "))
1562 continue # Go back around to get a number
1563 else: # key == "IHREAL"
1565 if n <= 0: # abort command
1570 prout(_("Maximum of %d torpedoes per burst.") % MAXBURST)
1573 scanner.chew() # User requested more torps than available
1574 continue # Go back around
1575 break # All is good, go to next stage
1579 key = scanner.nexttok()
1580 if i == 0 and key == "IHEOL":
1581 break # no coordinate waiting, we will try prompting
1582 if i == 1 and key == "IHEOL":
1583 # direct all torpedoes at one target
1585 target.append(target[0])
1586 tcourse.append(tcourse[0])
1589 scanner.push(scanner.token)
1590 target.append(scanner.getcoord())
1591 if target[-1] == None:
1593 tcourse.append(targetcheck(target[-1]))
1594 if tcourse[-1] == None:
1597 if len(target) == 0:
1598 # prompt for each one
1600 proutn(_("Target sector for torpedo number %d- ") % (i+1))
1602 target.append(scanner.getcoord())
1603 if target[-1] == None:
1605 tcourse.append(targetcheck(target[-1]))
1606 if tcourse[-1] == None:
1609 # Loop for moving <n> torpedoes
1611 if game.condition != "docked":
1613 dispersion = (randreal()+randreal())*0.5 -0.5
1614 if math.fabs(dispersion) >= 0.47:
1616 dispersion *= randreal(1.2, 2.2)
1618 prouts(_("***TORPEDO NUMBER %d MISFIRES") % (i+1))
1620 prouts(_("***TORPEDO MISFIRES."))
1623 prout(_(" Remainder of burst aborted."))
1625 prout(_("***Photon tubes damaged by misfire."))
1626 game.damage[DPHOTON] = game.damfac * randreal(1.0, 3.0)
1628 if game.shldup or game.condition == "docked":
1629 dispersion *= 1.0 + 0.0001*game.shield
1630 torpedo(game.sector, tcourse[i], dispersion, number=i, nburst=n)
1631 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
1633 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)<=0:
1637 "Check for phasers overheating."
1639 checkburn = (rpow-1500.0)*0.00038
1640 if withprob(checkburn):
1641 prout(_("Weapons officer Sulu- \"Phasers overheated, sir.\""))
1642 game.damage[DPHASER] = game.damfac* randreal(1.0, 2.0) * (1.0+checkburn)
1644 def checkshctrl(rpow):
1645 "Check shield control."
1648 prout(_("Shields lowered."))
1650 # Something bad has happened
1651 prouts(_("***RED ALERT! RED ALERT!"))
1653 hit = rpow*game.shield/game.inshld
1654 game.energy -= rpow+hit*0.8
1655 game.shield -= hit*0.2
1656 if game.energy <= 0.0:
1657 prouts(_("Sulu- \"Captain! Shield malf***********************\""))
1662 prouts(_("Sulu- \"Captain! Shield malfunction! Phaser fire contained!\""))
1664 prout(_("Lt. Uhura- \"Sir, all decks reporting damage.\""))
1665 icas = randrange(int(hit*0.012))
1670 prout(_("McCoy to bridge- \"Severe radiation burns, Jim."))
1671 prout(_(" %d casualties so far.\"") % icas)
1673 game.state.crew -= icas
1675 prout(_("Phaser energy dispersed by shields."))
1676 prout(_("Enemy unaffected."))
1681 "Register a phaser hit on Klingons and Romulans."
1688 dustfac = randreal(0.9, 1.0)
1689 hit = wham*math.pow(dustfac, game.enemies[kk].kdist)
1690 kpini = game.enemies[kk].power
1691 kp = math.fabs(kpini)
1692 if PHASEFAC*hit < kp:
1694 if game.enemies[kk].power < 0:
1695 game.enemies[kk].power -= -kp
1697 game.enemies[kk].power -= kp
1698 kpow = game.enemies[kk].power
1699 w = game.enemies[kk].location
1701 if not damaged(DSRSENS):
1703 proutn(_("%d unit hit on ") % int(hit))
1705 proutn(_("Very small hit on "))
1706 ienm = game.quad[w.i][w.j]
1709 proutn(crmena(False, ienm, "sector", w))
1713 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1717 kk -= 1 # don't do the increment
1719 else: # decide whether or not to emasculate klingon
1720 if kpow > 0 and withprob(0.9) and kpow <= randreal(0.4, 0.8)*kpini:
1721 prout(_("***Mr. Spock- \"Captain, the vessel at Sector %s")%w)
1722 prout(_(" has just lost its firepower.\""))
1723 game.enemies[kk].power = -kpow
1728 "Fire phasers at bad guys."
1732 irec = 0 # Cheating inhibitor
1741 # SR sensors and Computer are needed for automode
1742 if damaged(DSRSENS) or damaged(DCOMPTR):
1744 if game.condition == "docked":
1745 prout(_("Phasers can't be fired through base shields."))
1748 if damaged(DPHASER):
1749 prout(_("Phaser control damaged."))
1753 if damaged(DSHCTRL):
1754 prout(_("High speed shield control damaged."))
1757 if game.energy <= 200.0:
1758 prout(_("Insufficient energy to activate high-speed shield control."))
1761 prout(_("Weapons Officer Sulu- \"High-speed shield control enabled, sir.\""))
1763 # Original code so convoluted, I re-did it all
1764 # (That was Tom Almy talking about the C code, I think -- ESR)
1765 while automode == "NOTSET":
1766 key = scanner.nexttok()
1767 if key == "IHALPHA":
1768 if scanner.sees("manual"):
1769 if len(game.enemies)==0:
1770 prout(_("There is no enemy present to select."))
1773 automode = "AUTOMATIC"
1776 key = scanner.nexttok()
1777 elif scanner.sees("automatic"):
1778 if (not itarg) and len(game.enemies) != 0:
1779 automode = "FORCEMAN"
1781 if len(game.enemies)==0:
1782 prout(_("Energy will be expended into space."))
1783 automode = "AUTOMATIC"
1784 key = scanner.nexttok()
1785 elif scanner.sees("no"):
1790 elif key == "IHREAL":
1791 if len(game.enemies)==0:
1792 prout(_("Energy will be expended into space."))
1793 automode = "AUTOMATIC"
1795 automode = "FORCEMAN"
1797 automode = "AUTOMATIC"
1800 if len(game.enemies)==0:
1801 prout(_("Energy will be expended into space."))
1802 automode = "AUTOMATIC"
1804 automode = "FORCEMAN"
1806 proutn(_("Manual or automatic? "))
1811 if automode == "AUTOMATIC":
1812 if key == "IHALPHA" and scanner.sees("no"):
1814 key = scanner.nexttok()
1815 if key != "IHREAL" and len(game.enemies) != 0:
1816 prout(_("Phasers locked on target. Energy available: %.2f")%avail)
1821 for i in range(len(game.enemies)):
1822 irec += math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))*randreal(1.01, 1.06) + 1.0
1824 proutn(_("%d units required. ") % irec)
1826 proutn(_("Units to fire= "))
1827 key = scanner.nexttok()
1832 proutn(_("Energy available= %.2f") % avail)
1835 if not rpow > avail:
1841 key = scanner.nexttok()
1842 if key == "IHALPHA" and scanner.sees("no"):
1845 game.energy -= 200 # Go and do it!
1846 if checkshctrl(rpow):
1851 if len(game.enemies):
1854 for i in range(len(game.enemies)):
1858 hits[i] = math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))
1859 over = randreal(1.01, 1.06) * hits[i]
1861 powrem -= hits[i] + over
1862 if powrem <= 0 and temp < hits[i]:
1871 if extra > 0 and not game.alldone:
1873 proutn(_("*** Tholian web absorbs "))
1874 if len(game.enemies)>0:
1875 proutn(_("excess "))
1876 prout(_("phaser energy."))
1878 prout(_("%d expended on empty space.") % int(extra))
1879 elif automode == "FORCEMAN":
1882 if damaged(DCOMPTR):
1883 prout(_("Battle computer damaged, manual fire only."))
1886 prouts(_("---WORKING---"))
1888 prout(_("Short-range-sensors-damaged"))
1889 prout(_("Insufficient-data-for-automatic-phaser-fire"))
1890 prout(_("Manual-fire-must-be-used"))
1892 elif automode == "MANUAL":
1894 for k in range(len(game.enemies)):
1895 aim = game.enemies[k].location
1896 ienm = game.quad[aim.i][aim.j]
1898 proutn(_("Energy available= %.2f") % (avail-0.006))
1902 if damaged(DSRSENS) and \
1903 not game.sector.distance(aim)<2**0.5 and ienm in ('C', 'S'):
1904 prout(cramen(ienm) + _(" can't be located without short range scan."))
1907 hits[k] = 0 # prevent overflow -- thanks to Alexei Voitenko
1912 if itarg and k > kz:
1913 irec = (abs(game.enemies[k].power)/(PHASEFAC*math.pow(0.9, game.enemies[k].kdist))) * randreal(1.01, 1.06) + 1.0
1916 if not damaged(DCOMPTR):
1921 proutn(_("units to fire at %s- ") % crmena(False, ienm, "sector", aim))
1922 key = scanner.nexttok()
1923 if key == "IHALPHA" and scanner.sees("no"):
1925 key = scanner.nexttok()
1927 if key == "IHALPHA":
1931 if k == 1: # Let me say I'm baffled by this
1934 if scanner.real < 0:
1938 hits[k] = scanner.real
1939 rpow += scanner.real
1940 # If total requested is too much, inform and start over
1942 prout(_("Available energy exceeded -- try again."))
1945 key = scanner.nexttok() # scan for next value
1948 # zero energy -- abort
1951 if key == "IHALPHA" and scanner.sees("no"):
1956 game.energy -= 200.0
1957 if checkshctrl(rpow):
1961 # Say shield raised or malfunction, if necessary
1968 prout(_("Sulu- \"Sir, the high-speed shield control has malfunctioned . . ."))
1969 prouts(_(" CLICK CLICK POP . . ."))
1970 prout(_(" No response, sir!"))
1973 prout(_("Shields raised."))
1978 # Code from events,c begins here.
1980 # This isn't a real event queue a la BSD Trek yet -- you can only have one
1981 # event of each type active at any given time. Mostly these means we can
1982 # only have one FDISTR/FENSLV/FREPRO sequence going at any given time
1983 # BSD Trek, from which we swiped the idea, can have up to 5.
1985 def unschedule(evtype):
1986 "Remove an event from the schedule."
1987 game.future[evtype].date = FOREVER
1988 return game.future[evtype]
1990 def is_scheduled(evtype):
1991 "Is an event of specified type scheduled."
1992 return game.future[evtype].date != FOREVER
1994 def scheduled(evtype):
1995 "When will this event happen?"
1996 return game.future[evtype].date
1998 def schedule(evtype, offset):
1999 "Schedule an event of specified type."
2000 game.future[evtype].date = game.state.date + offset
2001 return game.future[evtype]
2003 def postpone(evtype, offset):
2004 "Postpone a scheduled event."
2005 game.future[evtype].date += offset
2008 "Rest period is interrupted by event."
2011 proutn(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
2013 game.resting = False
2019 "Run through the event queue looking for things to do."
2021 fintim = game.state.date + game.optime
2030 def tractorbeam(yank):
2031 "Tractor-beaming cases merge here."
2033 game.optime = (10.0/(7.5*7.5))*yank # 7.5 is yank rate (warp 7.5)
2035 prout("***" + crmshp() + _(" caught in long range tractor beam--"))
2036 # If Kirk & Co. screwing around on planet, handle
2037 atover(True) # atover(true) is Grab
2040 if game.icraft: # Caught in Galileo?
2043 # Check to see if shuttle is aboard
2044 if game.iscraft == "offship":
2047 prout(_("Galileo, left on the planet surface, is captured"))
2048 prout(_("by aliens and made into a flying McDonald's."))
2049 game.damage[DSHUTTL] = -10
2050 game.iscraft = "removed"
2052 prout(_("Galileo, left on the planet surface, is well hidden."))
2054 game.quadrant = game.state.kscmdr
2056 game.quadrant = game.state.kcmdr[i]
2057 game.sector = randplace(QUADSIZE)
2058 prout(crmshp() + _(" is pulled to Quadrant %s, Sector %s") \
2059 % (game.quadrant, game.sector))
2061 prout(_("(Remainder of rest/repair period cancelled.)"))
2062 game.resting = False
2064 if not damaged(DSHIELD) and game.shield > 0:
2065 doshield(shraise=True) # raise shields
2066 game.shldchg = False
2068 prout(_("(Shields not currently useable.)"))
2070 # Adjust finish time to time of tractor beaming?
2071 # fintim = game.state.date+game.optime
2072 attack(torps_ok=False)
2073 if not game.state.kcmdr:
2076 schedule(FTBEAM, game.optime+expran(1.5*game.intime/len(game.state.kcmdr)))
2079 "Code merges here for any commander destroying a starbase."
2080 # Not perfect, but will have to do
2081 # Handle case where base is in same quadrant as starship
2082 if game.battle == game.quadrant:
2083 game.state.chart[game.battle.i][game.battle.j].starbase = False
2084 game.quad[game.base.i][game.base.j] = '.'
2085 game.base.invalidate()
2088 prout(_("Spock- \"Captain, I believe the starbase has been destroyed.\""))
2089 elif game.state.baseq and communicating():
2090 # Get word via subspace radio
2093 prout(_("Lt. Uhura- \"Captain, Starfleet Command reports that"))
2094 proutn(_(" the starbase in Quadrant %s has been destroyed by") % game.battle)
2096 prout(_("the Klingon Super-Commander"))
2098 prout(_("a Klingon Commander"))
2099 game.state.chart[game.battle.i][game.battle.j].starbase = False
2100 # Remove Starbase from galaxy
2101 game.state.galaxy[game.battle.i][game.battle.j].starbase = False
2102 game.state.baseq = [x for x in game.state.baseq if x != game.battle]
2104 # reinstate a commander's base attack
2108 game.battle.invalidate()
2110 prout("=== EVENTS from %.2f to %.2f:" % (game.state.date, fintim))
2111 for i in range(1, NEVENTS):
2112 if i == FSNOVA: proutn("=== Supernova ")
2113 elif i == FTBEAM: proutn("=== T Beam ")
2114 elif i == FSNAP: proutn("=== Snapshot ")
2115 elif i == FBATTAK: proutn("=== Base Attack ")
2116 elif i == FCDBAS: proutn("=== Base Destroy ")
2117 elif i == FSCMOVE: proutn("=== SC Move ")
2118 elif i == FSCDBAS: proutn("=== SC Base Destroy ")
2119 elif i == FDSPROB: proutn("=== Probe Move ")
2120 elif i == FDISTR: proutn("=== Distress Call ")
2121 elif i == FENSLV: proutn("=== Enslavement ")
2122 elif i == FREPRO: proutn("=== Klingon Build ")
2124 prout("%.2f" % (scheduled(i)))
2127 radio_was_broken = damaged(DRADIO)
2130 # Select earliest extraneous event, evcode==0 if no events
2135 for l in range(1, NEVENTS):
2136 if game.future[l].date < datemin:
2139 prout("== Event %d fires" % evcode)
2140 datemin = game.future[l].date
2141 xtime = datemin-game.state.date
2142 game.state.date = datemin
2143 # Decrement Federation resources and recompute remaining time
2144 game.state.remres -= (game.state.remkl+4*len(game.state.kcmdr))*xtime
2146 if game.state.remtime <= 0:
2149 # Any crew left alive?
2150 if game.state.crew <= 0:
2153 # Is life support adequate?
2154 if damaged(DLIFSUP) and game.condition != "docked":
2155 if game.lsupres < xtime and game.damage[DLIFSUP] > game.lsupres:
2158 game.lsupres -= xtime
2159 if game.damage[DLIFSUP] <= xtime:
2160 game.lsupres = game.inlsr
2163 if game.condition == "docked":
2165 # Don't fix Deathray here
2166 for l in range(NDEVICES):
2167 if game.damage[l] > 0.0 and l != DDRAY:
2168 if game.damage[l]-repair > 0.0:
2169 game.damage[l] -= repair
2171 game.damage[l] = 0.0
2172 # If radio repaired, update star chart and attack reports
2173 if radio_was_broken and not damaged(DRADIO):
2174 prout(_("Lt. Uhura- \"Captain, the sub-space radio is working and"))
2175 prout(_(" surveillance reports are coming in."))
2177 if not game.iseenit:
2181 prout(_(" The star chart is now up to date.\""))
2183 # Cause extraneous event EVCODE to occur
2184 game.optime -= xtime
2185 if evcode == FSNOVA: # Supernova
2188 schedule(FSNOVA, expran(0.5*game.intime))
2189 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2191 elif evcode == FSPY: # Check with spy to see if SC should tractor beam
2192 if game.state.nscrem == 0 or \
2193 ictbeam or istract or \
2194 game.condition == "docked" or game.isatb == 1 or game.iscate:
2196 if game.ientesc or \
2197 (game.energy<2000 and game.torps<4 and game.shield < 1250) or \
2198 (damaged(DPHASER) and (damaged(DPHOTON) or game.torps<4)) or \
2199 (damaged(DSHIELD) and \
2200 (game.energy < 2500 or damaged(DPHASER)) and \
2201 (game.torps < 5 or damaged(DPHOTON))):
2203 istract = ictbeam = True
2204 tractorbeam((game.state.kscmdr-game.quadrant).distance())
2207 elif evcode == FTBEAM: # Tractor beam
2208 if not game.state.kcmdr:
2211 i = randrange(len(game.state.kcmdr))
2212 yank = (game.state.kcmdr[i]-game.quadrant).distance()
2213 if istract or game.condition == "docked" or yank == 0:
2214 # Drats! Have to reschedule
2216 game.optime + expran(1.5*game.intime/len(game.state.kcmdr)))
2220 elif evcode == FSNAP: # Snapshot of the universe (for time warp)
2221 game.snapsht = copy.deepcopy(game.state)
2222 game.state.snap = True
2223 schedule(FSNAP, expran(0.5 * game.intime))
2224 elif evcode == FBATTAK: # Commander attacks starbase
2225 if not game.state.kcmdr or not game.state.baseq:
2231 for ibq in game.state.baseq:
2232 for cmdr in game.state.kcmdr:
2233 if ibq == cmdr and ibq != game.quadrant and ibq != game.state.kscmdr:
2236 # no match found -- try later
2237 schedule(FBATTAK, expran(0.3*game.intime))
2242 # commander + starbase combination found -- launch attack
2244 schedule(FCDBAS, randreal(1.0, 4.0))
2245 if game.isatb: # extra time if SC already attacking
2246 postpone(FCDBAS, scheduled(FSCDBAS)-game.state.date)
2247 game.future[FBATTAK].date = game.future[FCDBAS].date + expran(0.3*game.intime)
2248 game.iseenit = False
2249 if not communicating():
2250 continue # No warning :-(
2254 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") % game.battle)
2255 prout(_(" reports that it is under attack and that it can"))
2256 prout(_(" hold out only until stardate %d.\"") % (int(scheduled(FCDBAS))))
2259 elif evcode == FSCDBAS: # Supercommander destroys base
2262 if not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].starbase:
2263 continue # WAS RETURN!
2265 game.battle = game.state.kscmdr
2267 elif evcode == FCDBAS: # Commander succeeds in destroying base
2268 if evcode == FCDBAS:
2270 if not game.state.baseq() \
2271 or not game.state.galaxy[game.battle.i][game.battle.j].starbase:
2272 game.battle.invalidate()
2274 # find the lucky pair
2275 for cmdr in game.state.kcmdr:
2276 if cmdr == game.battle:
2279 # No action to take after all
2282 elif evcode == FSCMOVE: # Supercommander moves
2283 schedule(FSCMOVE, 0.2777)
2284 if not game.ientesc and not istract and game.isatb != 1 and \
2285 (not game.iscate or not game.justin):
2287 elif evcode == FDSPROB: # Move deep space probe
2288 schedule(FDSPROB, 0.01)
2289 if not game.probe.nexttok():
2290 if not game.probe.quadrant().valid_quadrant() or \
2291 game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j].supernova:
2292 # Left galaxy or ran into supernova
2296 proutn(_("Lt. Uhura- \"The deep space probe "))
2297 if not game.probe.quadrant().valid_quadrant():
2298 prout(_("has left the galaxy.\""))
2300 prout(_("is no longer transmitting.\""))
2306 prout(_("Lt. Uhura- \"The deep space probe is now in Quadrant %s.\"") % game.probe.quadrant())
2307 pquad = game.probe.quadrant()
2308 pdest = game.state.galaxy[pquad.i][pquad.j]
2310 game.state.chart[pquad.i][pquad.j].klingons = pdest.klingons
2311 game.state.chart[pquad.i][pquad.j].starbase = pdest.starbase
2312 game.state.chart[pquad.i][pquad.j].stars = pdest.stars
2313 pdest.charted = True
2314 game.probe.moves -= 1 # One less to travel
2315 if game.probe.arrived() and game.isarmed and pdest.stars:
2316 supernova(game.probe) # fire in the hole!
2318 if game.state.galaxy[pquad.i][pquad.j].supernova:
2320 elif evcode == FDISTR: # inhabited system issues distress call
2322 # try a whole bunch of times to find something suitable
2323 for i in range(100):
2324 # need a quadrant which is not the current one,
2325 # which has some stars which are inhabited and
2326 # not already under attack, which is not
2327 # supernova'ed, and which has some Klingons in it
2328 w = randplace(GALSIZE)
2329 q = game.state.galaxy[w.i][w.j]
2330 if not (game.quadrant == w or q.planet == None or \
2331 not q.planet.inhabited or \
2332 q.supernova or q.status!="secure" or q.klingons<=0):
2335 # can't seem to find one; ignore this call
2337 prout("=== Couldn't find location for distress event.")
2339 # got one!! Schedule its enslavement
2340 ev = schedule(FENSLV, expran(game.intime))
2342 q.status = "distressed"
2343 # tell the captain about it if we can
2345 prout(_("Uhura- Captain, %s in Quadrant %s reports it is under attack") \
2346 % (q.planet, repr(w)))
2347 prout(_("by a Klingon invasion fleet."))
2350 elif evcode == FENSLV: # starsystem is enslaved
2351 ev = unschedule(FENSLV)
2352 # see if current distress call still active
2353 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2357 q.status = "enslaved"
2359 # play stork and schedule the first baby
2360 ev2 = schedule(FREPRO, expran(2.0 * game.intime))
2361 ev2.quadrant = ev.quadrant
2363 # report the disaster if we can
2365 prout(_("Uhura- We've lost contact with starsystem %s") % \
2367 prout(_("in Quadrant %s.\n") % ev.quadrant)
2368 elif evcode == FREPRO: # Klingon reproduces
2369 # If we ever switch to a real event queue, we'll need to
2370 # explicitly retrieve and restore the x and y.
2371 ev = schedule(FREPRO, expran(1.0 * game.intime))
2372 # see if current distress call still active
2373 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2377 if game.state.remkl >= MAXKLGAME:
2378 continue # full right now
2379 # reproduce one Klingon
2382 if game.klhere >= MAXKLQUAD:
2384 # this quadrant not ok, pick an adjacent one
2385 for m.i in range(w.i - 1, w.i + 2):
2386 for m.j in range(w.j - 1, w.j + 2):
2387 if not m.valid_quadrant():
2389 q = game.state.galaxy[m.i][m.j]
2390 # check for this quad ok (not full & no snova)
2391 if q.klingons >= MAXKLQUAD or q.supernova:
2395 continue # search for eligible quadrant failed
2399 game.state.remkl += 1
2401 if game.quadrant == w:
2403 game.enemies.append(newkling())
2404 # recompute time left
2407 if game.quadrant == w:
2408 prout(_("Spock- sensors indicate the Klingons have"))
2409 prout(_("launched a warship from %s.") % q.planet)
2411 prout(_("Uhura- Starfleet reports increased Klingon activity"))
2412 if q.planet != None:
2413 proutn(_("near %s ") % q.planet)
2414 prout(_("in Quadrant %s.") % w)
2420 key = scanner.nexttok()
2423 proutn(_("How long? "))
2428 origTime = delay = scanner.real
2431 if delay >= game.state.remtime or len(game.enemies) != 0:
2432 proutn(_("Are you sure? "))
2435 # Alternate resting periods (events) with attacks
2439 game.resting = False
2440 if not game.resting:
2441 prout(_("%d stardates left.") % int(game.state.remtime))
2443 temp = game.optime = delay
2444 if len(game.enemies):
2445 rtime = randreal(1.0, 2.0)
2449 if game.optime < delay:
2450 attack(torps_ok=False)
2458 # Repair Deathray if long rest at starbase
2459 if origTime-delay >= 9.99 and game.condition == "docked":
2460 game.damage[DDRAY] = 0.0
2461 # leave if quadrant supernovas
2462 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2464 game.resting = False
2469 ncourse = (0.0, 10.5, 12.0, 1.5, 9.0, 0.0, 3.0, 7.5, 6.0, 4.5)
2470 newc = Coord(); neighbor = Coord(); bump = Coord(0, 0)
2472 # Wow! We've supernova'ed
2473 supernova(game.quadrant)
2475 # handle initial nova
2476 game.quad[nov.i][nov.j] = '.'
2477 prout(crmena(False, '*', "sector", nov) + _(" novas."))
2478 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2479 game.state.starkl += 1
2480 # Set up queue to recursively trigger adjacent stars
2486 for offset.i in range(-1, 1+1):
2487 for offset.j in range(-1, 1+1):
2488 if offset.j == 0 and offset.i == 0:
2490 neighbor = start + offset
2491 if not neighbor.valid_sector():
2493 iquad = game.quad[neighbor.i][neighbor.j]
2494 # Empty space ends reaction
2495 if iquad in ('.', '?', ' ', 'T', '#'):
2497 elif iquad == '*': # Affect another star
2499 # This star supernovas
2500 supernova(game.quadrant)
2503 hits.append(neighbor)
2504 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2505 game.state.starkl += 1
2506 proutn(crmena(True, '*', "sector", neighbor))
2508 game.quad[neighbor.i][neighbor.j] = '.'
2510 elif iquad in ('P', '@'): # Destroy planet
2511 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
2513 game.state.nplankl += 1
2515 game.state.nworldkl += 1
2516 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2517 game.iplnet.pclass = "destroyed"
2519 game.plnet.invalidate()
2523 game.quad[neighbor.i][neighbor.j] = '.'
2524 elif iquad == 'B': # Destroy base
2525 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
2526 game.state.baseq = [x for x in game.state.baseq if x!= game.quadrant]
2527 game.base.invalidate()
2528 game.state.basekl += 1
2530 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2531 game.quad[neighbor.i][neighbor.j] = '.'
2532 elif iquad in ('E', 'F'): # Buffet ship
2533 prout(_("***Starship buffeted by nova."))
2535 if game.shield >= 2000.0:
2536 game.shield -= 2000.0
2538 diff = 2000.0 - game.shield
2542 prout(_("***Shields knocked out."))
2543 game.damage[DSHIELD] += 0.005*game.damfac*randreal()*diff
2545 game.energy -= 2000.0
2546 if game.energy <= 0:
2549 # add in course nova contributes to kicking starship
2550 bump += (game.sector-hits[-1]).sgn()
2551 elif iquad == 'K': # kill klingon
2552 deadkl(neighbor, iquad, neighbor)
2553 elif iquad in ('C','S','R'): # Damage/destroy big enemies
2554 for ll in range(len(game.enemies)):
2555 if game.enemies[ll].location == neighbor:
2557 game.enemies[ll].power -= 800.0 # If firepower is lost, die
2558 if game.enemies[ll].power <= 0.0:
2559 deadkl(neighbor, iquad, neighbor)
2561 newc = neighbor + neighbor - hits[-1]
2562 proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged"))
2563 if not newc.valid_sector():
2564 # can't leave quadrant
2567 iquad1 = game.quad[newc.i][newc.j]
2569 proutn(_(", blasted into ") + crmena(False, ' ', "sector", newc))
2571 deadkl(neighbor, iquad, newc)
2574 # can't move into something else
2577 proutn(_(", buffeted to Sector %s") % newc)
2578 game.quad[neighbor.i][neighbor.j] = '.'
2579 game.quad[newc.i][newc.j] = iquad
2580 game.enemies[ll].move(newc)
2581 # Starship affected by nova -- kick it away.
2583 direc = ncourse[3*(bump.i+1)+bump.j+2]
2588 scourse = course(bearing=direc, distance=dist)
2589 game.optime = scourse.time(warp=4)
2591 prout(_("Force of nova displaces starship."))
2592 imove(scourse, noattack=True)
2593 game.optime = scourse.time(warp=4)
2597 "Star goes supernova."
2602 # Scheduled supernova -- select star at random.
2605 for nq.i in range(GALSIZE):
2606 for nq.j in range(GALSIZE):
2607 stars += game.state.galaxy[nq.i][nq.j].stars
2609 return # nothing to supernova exists
2610 num = randrange(stars) + 1
2611 for nq.i in range(GALSIZE):
2612 for nq.j in range(GALSIZE):
2613 num -= game.state.galaxy[nq.i][nq.j].stars
2619 proutn("=== Super nova here?")
2622 if not nq == game.quadrant or game.justin:
2623 # it isn't here, or we just entered (treat as enroute)
2626 prout(_("Message from Starfleet Command Stardate %.2f") % game.state.date)
2627 prout(_(" Supernova in Quadrant %s; caution advised.") % nq)
2630 # we are in the quadrant!
2631 num = randrange(game.state.galaxy[nq.i][nq.j].stars) + 1
2632 for ns.i in range(QUADSIZE):
2633 for ns.j in range(QUADSIZE):
2634 if game.quad[ns.i][ns.j]=='*':
2641 prouts(_("***RED ALERT! RED ALERT!"))
2643 prout(_("***Incipient supernova detected at Sector %s") % ns)
2644 if (ns.i-game.sector.i)**2 + (ns.j-game.sector.j)**2 <= 2.1:
2645 proutn(_("Emergency override attempts t"))
2646 prouts("***************")
2650 # destroy any Klingons in supernovaed quadrant
2651 kldead = game.state.galaxy[nq.i][nq.j].klingons
2652 game.state.galaxy[nq.i][nq.j].klingons = 0
2653 if nq == game.state.kscmdr:
2654 # did in the Supercommander!
2655 game.state.nscrem = game.state.kscmdr.i = game.state.kscmdr.j = game.isatb = 0
2659 survivors = filter(lambda w: w != nq, game.state.kcmdr)
2660 comkills = len(game.state.kcmdr) - len(survivors)
2661 game.state.kcmdr = survivors
2663 if not game.state.kcmdr:
2665 game.state.remkl -= kldead
2666 # destroy Romulans and planets in supernovaed quadrant
2667 nrmdead = game.state.galaxy[nq.i][nq.j].romulans
2668 game.state.galaxy[nq.i][nq.j].romulans = 0
2669 game.state.nromrem -= nrmdead
2671 for loop in range(game.inplan):
2672 if game.state.planets[loop].quadrant == nq:
2673 game.state.planets[loop].pclass = "destroyed"
2675 # Destroy any base in supernovaed quadrant
2676 game.state.baseq = [x for x in game.state.baseq if x != nq]
2677 # If starship caused supernova, tally up destruction
2679 game.state.starkl += game.state.galaxy[nq.i][nq.j].stars
2680 game.state.basekl += game.state.galaxy[nq.i][nq.j].starbase
2681 game.state.nplankl += npdead
2682 # mark supernova in galaxy and in star chart
2683 if game.quadrant == nq or communicating():
2684 game.state.galaxy[nq.i][nq.j].supernova = True
2685 # If supernova destroys last Klingons give special message
2686 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0 and not nq == game.quadrant:
2689 prout(_("Lucky you!"))
2690 proutn(_("A supernova in %s has just destroyed the last Klingons.") % nq)
2693 # if some Klingons remain, continue or die in supernova
2698 # Code from finish.c ends here.
2701 "Self-destruct maneuver. Finish with a BANG!"
2703 if damaged(DCOMPTR):
2704 prout(_("Computer damaged; cannot execute destruct sequence."))
2706 prouts(_("---WORKING---")); skip(1)
2707 prouts(_("SELF-DESTRUCT-SEQUENCE-ACTIVATED")); skip(1)
2708 prouts(" 10"); skip(1)
2709 prouts(" 9"); skip(1)
2710 prouts(" 8"); skip(1)
2711 prouts(" 7"); skip(1)
2712 prouts(" 6"); skip(1)
2714 prout(_("ENTER-CORRECT-PASSWORD-TO-CONTINUE-"))
2716 prout(_("SELF-DESTRUCT-SEQUENCE-OTHERWISE-"))
2718 prout(_("SELF-DESTRUCT-SEQUENCE-WILL-BE-ABORTED"))
2721 if game.passwd != scanner.token:
2722 prouts(_("PASSWORD-REJECTED;"))
2724 prouts(_("CONTINUITY-EFFECTED"))
2727 prouts(_("PASSWORD-ACCEPTED")); skip(1)
2728 prouts(" 5"); skip(1)
2729 prouts(" 4"); skip(1)
2730 prouts(" 3"); skip(1)
2731 prouts(" 2"); skip(1)
2732 prouts(" 1"); skip(1)
2734 prouts(_("GOODBYE-CRUEL-WORLD"))
2742 prouts(_("********* Entropy of %s maximized *********") % crmshp())
2746 if len(game.enemies) != 0:
2747 whammo = 25.0 * game.energy
2748 for l in range(len(game.enemies)):
2749 if game.enemies[l].power*game.enemies[l].kdist <= whammo:
2750 deadkl(game.enemies[l].location, game.quad[game.enemies[l].location.i][game.enemies[l].location.j], game.enemies[l].location)
2754 "Compute our rate of kils over time."
2755 elapsed = game.state.date - game.indate
2756 if elapsed == 0: # Avoid divide-by-zero error if calculated on turn 0
2759 starting = (game.inkling + game.incom + game.inscom)
2760 remaining = (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)
2761 return (starting - remaining)/elapsed
2765 badpt = 5.0*game.state.starkl + \
2767 10.0*game.state.nplankl + \
2768 300*game.state.nworldkl + \
2770 100.0*game.state.basekl +\
2772 if game.ship == 'F':
2774 elif game.ship == None:
2779 # end the game, with appropriate notfications
2783 prout(_("It is stardate %.1f.") % game.state.date)
2785 if ifin == FWON: # Game has been won
2786 if game.state.nromrem != 0:
2787 prout(_("The remaining %d Romulans surrender to Starfleet Command.") %
2790 prout(_("You have smashed the Klingon invasion fleet and saved"))
2791 prout(_("the Federation."))
2796 badpt = 0.0 # Close enough!
2797 # killsPerDate >= RateMax
2798 if game.state.date-game.indate < 5.0 or \
2799 killrate() >= 0.1*game.skill*(game.skill+1.0) + 0.1 + 0.008*badpt:
2801 prout(_("In fact, you have done so well that Starfleet Command"))
2802 if game.skill == SKILL_NOVICE:
2803 prout(_("promotes you one step in rank from \"Novice\" to \"Fair\"."))
2804 elif game.skill == SKILL_FAIR:
2805 prout(_("promotes you one step in rank from \"Fair\" to \"Good\"."))
2806 elif game.skill == SKILL_GOOD:
2807 prout(_("promotes you one step in rank from \"Good\" to \"Expert\"."))
2808 elif game.skill == SKILL_EXPERT:
2809 prout(_("promotes you to Commodore Emeritus."))
2811 prout(_("Now that you think you're really good, try playing"))
2812 prout(_("the \"Emeritus\" game. It will splatter your ego."))
2813 elif game.skill == SKILL_EMERITUS:
2815 proutn(_("Computer- "))
2816 prouts(_("ERROR-ERROR-ERROR-ERROR"))
2818 prouts(_(" YOUR-SKILL-HAS-EXCEEDED-THE-CAPACITY-OF-THIS-PROGRAM"))
2820 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2822 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2824 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2826 prouts(_(" THIS-PROGRAM-MUST?- MUST ? - SUR? ? -? VI"))
2828 prout(_("Now you can retire and write your own Star Trek game!"))
2830 elif game.skill >= SKILL_EXPERT:
2831 if game.thawed and not game.idebug:
2832 prout(_("You cannot get a citation, so..."))
2834 proutn(_("Do you want your Commodore Emeritus Citation printed? "))
2838 # Only grant long life if alive (original didn't!)
2840 prout(_("LIVE LONG AND PROSPER."))
2845 elif ifin == FDEPLETE: # Federation Resources Depleted
2846 prout(_("Your time has run out and the Federation has been"))
2847 prout(_("conquered. Your starship is now Klingon property,"))
2848 prout(_("and you are put on trial as a war criminal. On the"))
2849 proutn(_("basis of your record, you are "))
2850 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)*3.0 > (game.inkling + game.incom + game.inscom):
2851 prout(_("acquitted."))
2853 prout(_("LIVE LONG AND PROSPER."))
2855 prout(_("found guilty and"))
2856 prout(_("sentenced to death by slow torture."))
2860 elif ifin == FLIFESUP:
2861 prout(_("Your life support reserves have run out, and"))
2862 prout(_("you die of thirst, starvation, and asphyxiation."))
2863 prout(_("Your starship is a derelict in space."))
2865 prout(_("Your energy supply is exhausted."))
2867 prout(_("Your starship is a derelict in space."))
2868 elif ifin == FBATTLE:
2869 prout(_("The %s has been destroyed in battle.") % crmshp())
2871 prout(_("Dulce et decorum est pro patria mori."))
2873 prout(_("You have made three attempts to cross the negative energy"))
2874 prout(_("barrier which surrounds the galaxy."))
2876 prout(_("Your navigation is abominable."))
2879 prout(_("Your starship has been destroyed by a nova."))
2880 prout(_("That was a great shot."))
2882 elif ifin == FSNOVAED:
2883 prout(_("The %s has been fried by a supernova.") % crmshp())
2884 prout(_("...Not even cinders remain..."))
2885 elif ifin == FABANDN:
2886 prout(_("You have been captured by the Klingons. If you still"))
2887 prout(_("had a starbase to be returned to, you would have been"))
2888 prout(_("repatriated and given another chance. Since you have"))
2889 prout(_("no starbases, you will be mercilessly tortured to death."))
2890 elif ifin == FDILITHIUM:
2891 prout(_("Your starship is now an expanding cloud of subatomic particles"))
2892 elif ifin == FMATERIALIZE:
2893 prout(_("Starbase was unable to re-materialize your starship."))
2894 prout(_("Sic transit gloria mundi"))
2895 elif ifin == FPHASER:
2896 prout(_("The %s has been cremated by its own phasers.") % crmshp())
2898 prout(_("You and your landing party have been"))
2899 prout(_("converted to energy, disipating through space."))
2900 elif ifin == FMINING:
2901 prout(_("You are left with your landing party on"))
2902 prout(_("a wild jungle planet inhabited by primitive cannibals."))
2904 prout(_("They are very fond of \"Captain Kirk\" soup."))
2906 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
2907 elif ifin == FDPLANET:
2908 prout(_("You and your mining party perish."))
2910 prout(_("That was a great shot."))
2913 prout(_("The Galileo is instantly annihilated by the supernova."))
2914 prout(_("You and your mining party are atomized."))
2916 prout(_("Mr. Spock takes command of the %s and") % crmshp())
2917 prout(_("joins the Romulans, wreaking terror on the Federation."))
2918 elif ifin == FPNOVA:
2919 prout(_("You and your mining party are atomized."))
2921 prout(_("Mr. Spock takes command of the %s and") % crmshp())
2922 prout(_("joins the Romulans, wreaking terror on the Federation."))
2923 elif ifin == FSTRACTOR:
2924 prout(_("The shuttle craft Galileo is also caught,"))
2925 prout(_("and breaks up under the strain."))
2927 prout(_("Your debris is scattered for millions of miles."))
2928 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
2930 prout(_("The mutants attack and kill Spock."))
2931 prout(_("Your ship is captured by Klingons, and"))
2932 prout(_("your crew is put on display in a Klingon zoo."))
2933 elif ifin == FTRIBBLE:
2934 prout(_("Tribbles consume all remaining water,"))
2935 prout(_("food, and oxygen on your ship."))
2937 prout(_("You die of thirst, starvation, and asphyxiation."))
2938 prout(_("Your starship is a derelict in space."))
2940 prout(_("Your ship is drawn to the center of the black hole."))
2941 prout(_("You are crushed into extremely dense matter."))
2943 prout(_("Your last crew member has died."))
2944 if game.ship == 'F':
2946 elif game.ship == 'E':
2949 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0:
2950 goodies = game.state.remres/game.inresor
2951 baddies = (game.state.remkl + 2.0*len(game.state.kcmdr))/(game.inkling+2.0*game.incom)
2952 if goodies/baddies >= randreal(1.0, 1.5):
2953 prout(_("As a result of your actions, a treaty with the Klingon"))
2954 prout(_("Empire has been signed. The terms of the treaty are"))
2955 if goodies/baddies >= randreal(3.0):
2956 prout(_("favorable to the Federation."))
2958 prout(_("Congratulations!"))
2960 prout(_("highly unfavorable to the Federation."))
2962 prout(_("The Federation will be destroyed."))
2964 prout(_("Since you took the last Klingon with you, you are a"))
2965 prout(_("martyr and a hero. Someday maybe they'll erect a"))
2966 prout(_("statue in your memory. Rest in peace, and try not"))
2967 prout(_("to think about pigeons."))
2972 "Compute player's score."
2973 timused = game.state.date - game.indate
2974 if (timused == 0 or (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0) and timused < 5.0:
2976 game.perdate = killrate()
2977 ithperd = 500*game.perdate + 0.5
2980 iwon = 100*game.skill
2981 if game.ship == 'E':
2983 elif game.ship == 'F':
2987 game.score = 10*(game.inkling - game.state.remkl) \
2988 + 50*(game.incom - len(game.state.kcmdr)) \
2990 + 20*(game.inrom - game.state.nromrem) \
2991 + 200*(game.inscom - game.state.nscrem) \
2992 - game.state.nromrem \
2997 prout(_("Your score --"))
2998 if game.inrom - game.state.nromrem:
2999 prout(_("%6d Romulans destroyed %5d") %
3000 (game.inrom - game.state.nromrem, 20*(game.inrom - game.state.nromrem)))
3001 if game.state.nromrem and game.gamewon:
3002 prout(_("%6d Romulans captured %5d") %
3003 (game.state.nromrem, game.state.nromrem))
3004 if game.inkling - game.state.remkl:
3005 prout(_("%6d ordinary Klingons destroyed %5d") %
3006 (game.inkling - game.state.remkl, 10*(game.inkling - game.state.remkl)))
3007 if game.incom - len(game.state.kcmdr):
3008 prout(_("%6d Klingon commanders destroyed %5d") %
3009 (game.incom - len(game.state.kcmdr), 50*(game.incom - len(game.state.kcmdr))))
3010 if game.inscom - game.state.nscrem:
3011 prout(_("%6d Super-Commander destroyed %5d") %
3012 (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem)))
3014 prout(_("%6.2f Klingons per stardate %5d") %
3015 (game.perdate, ithperd))
3016 if game.state.starkl:
3017 prout(_("%6d stars destroyed by your action %5d") %
3018 (game.state.starkl, -5*game.state.starkl))
3019 if game.state.nplankl:
3020 prout(_("%6d planets destroyed by your action %5d") %
3021 (game.state.nplankl, -10*game.state.nplankl))
3022 if (game.options & OPTION_WORLDS) and game.state.nworldkl:
3023 prout(_("%6d inhabited planets destroyed by your action %5d") %
3024 (game.state.nworldkl, -300*game.state.nworldkl))
3025 if game.state.basekl:
3026 prout(_("%6d bases destroyed by your action %5d") %
3027 (game.state.basekl, -100*game.state.basekl))
3029 prout(_("%6d calls for help from starbase %5d") %
3030 (game.nhelp, -45*game.nhelp))
3032 prout(_("%6d casualties incurred %5d") %
3033 (game.casual, -game.casual))
3035 prout(_("%6d crew abandoned in space %5d") %
3036 (game.abandoned, -3*game.abandoned))
3038 prout(_("%6d ship(s) lost or destroyed %5d") %
3039 (klship, -100*klship))
3041 prout(_("Penalty for getting yourself killed -200"))
3043 proutn(_("Bonus for winning "))
3044 if game.skill == SKILL_NOVICE: proutn(_("Novice game "))
3045 elif game.skill == SKILL_FAIR: proutn(_("Fair game "))
3046 elif game.skill == SKILL_GOOD: proutn(_("Good game "))
3047 elif game.skill == SKILL_EXPERT: proutn(_("Expert game "))
3048 elif game.skill == SKILL_EMERITUS: proutn(_("Emeritus game"))
3049 prout(" %5d" % iwon)
3051 prout(_("TOTAL SCORE %5d") % game.score)
3054 "Emit winner's commemmorative plaque."
3057 proutn(_("File or device name for your plaque: "))
3060 fp = open(winner, "w")
3063 prout(_("Invalid name."))
3065 proutn(_("Enter name to go on plaque (up to 30 characters): "))
3067 # The 38 below must be 64 for 132-column paper
3068 nskip = 38 - len(winner)/2
3069 fp.write("\n\n\n\n")
3070 # --------DRAW ENTERPRISE PICTURE.
3071 fp.write(" EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n" )
3072 fp.write(" EEE E : : : E\n" )
3073 fp.write(" EE EEE E : : NCC-1701 : E\n")
3074 fp.write("EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEE : : : E\n")
3075 fp.write(" E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n")
3076 fp.write(" EEEEEEEEE EEEEEEEEEEEEE E E\n")
3077 fp.write(" EEEEEEE EEEEE E E E E\n")
3078 fp.write(" EEE E E E E\n")
3079 fp.write(" E E E E\n")
3080 fp.write(" EEEEEEEEEEEEE E E\n")
3081 fp.write(" EEE : EEEEEEE EEEEEEEE\n")
3082 fp.write(" :E : EEEE E\n")
3083 fp.write(" .-E -:----- E\n")
3084 fp.write(" :E : E\n")
3085 fp.write(" EE : EEEEEEEE\n")
3086 fp.write(" EEEEEEEEEEEEEEEEEEEEEEE\n")
3088 fp.write(_(" U. S. S. ENTERPRISE\n"))
3089 fp.write("\n\n\n\n")
3090 fp.write(_(" For demonstrating outstanding ability as a starship captain\n"))
3092 fp.write(_(" Starfleet Command bestows to you\n"))
3094 fp.write("%*s%s\n\n" % (nskip, "", winner))
3095 fp.write(_(" the rank of\n\n"))
3096 fp.write(_(" \"Commodore Emeritus\"\n\n"))
3098 if game.skill == SKILL_EXPERT:
3099 fp.write(_(" Expert level\n\n"))
3100 elif game.skill == SKILL_EMERITUS:
3101 fp.write(_("Emeritus level\n\n"))
3103 fp.write(_(" Cheat level\n\n"))
3104 timestring = time.ctime()
3105 fp.write(_(" This day of %.6s %.4s, %.8s\n\n") %
3106 (timestring+4, timestring+20, timestring+11))
3107 fp.write(_(" Your score: %d\n\n") % game.score)
3108 fp.write(_(" Klingons per stardate: %.2f\n") % game.perdate)
3111 # Code from io.c begins here
3113 rows = linecount = 0 # for paging
3116 fullscreen_window = None
3117 srscan_window = None # Short range scan
3118 report_window = None # Report legends for status window
3119 status_window = None # The status window itself
3120 lrscan_window = None # Long range scan
3121 message_window = None # Main window for scrolling text
3122 prompt_window = None # Prompt window at bottom of display
3127 "for some recent versions of python2, the following enables UTF8"
3128 "for the older ones we probably need to set C locale, and the python3"
3129 "has no problems at all"
3130 if sys.version_info[0] < 3:
3132 locale.setlocale(locale.LC_ALL, "")
3133 gettext.bindtextdomain("sst", "/usr/local/share/locale")
3134 gettext.textdomain("sst")
3135 if not (game.options & OPTION_CURSES):
3136 ln_env = os.getenv("LINES")
3142 stdscr = curses.initscr()
3146 if game.options & OPTION_COLOR:
3147 curses.start_color()
3148 curses.use_default_colors()
3149 curses.init_pair(curses.COLOR_BLACK, curses.COLOR_BLACK, -1)
3150 curses.init_pair(curses.COLOR_GREEN, curses.COLOR_GREEN, -1)
3151 curses.init_pair(curses.COLOR_RED, curses.COLOR_RED, -1)
3152 curses.init_pair(curses.COLOR_CYAN, curses.COLOR_CYAN, -1)
3153 curses.init_pair(curses.COLOR_WHITE, curses.COLOR_WHITE, -1)
3154 curses.init_pair(curses.COLOR_MAGENTA, curses.COLOR_MAGENTA, -1)
3155 curses.init_pair(curses.COLOR_BLUE, curses.COLOR_BLUE, -1)
3156 curses.init_pair(curses.COLOR_YELLOW, curses.COLOR_YELLOW, -1)
3157 global fullscreen_window, srscan_window, report_window, status_window
3158 global lrscan_window, message_window, prompt_window
3159 (rows, columns) = stdscr.getmaxyx()
3160 fullscreen_window = stdscr
3161 srscan_window = curses.newwin(12, 25, 0, 0)
3162 report_window = curses.newwin(11, 0, 1, 25)
3163 status_window = curses.newwin(10, 0, 1, 39)
3164 lrscan_window = curses.newwin(5, 0, 0, 64)
3165 message_window = curses.newwin(0, 0, 12, 0)
3166 prompt_window = curses.newwin(1, 0, rows-2, 0)
3167 message_window.scrollok(True)
3168 setwnd(fullscreen_window)
3172 if game.options & OPTION_CURSES:
3173 stdscr.keypad(False)
3179 "Wait for user action -- OK to do nothing if on a TTY"
3180 if game.options & OPTION_CURSES:
3185 prouts(_("[ANNOUNCEMENT ARRIVING...]"))
3189 if game.skill > SKILL_FAIR:
3190 prompt = _("[CONTINUE?]")
3192 prompt = _("[PRESS ENTER TO CONTINUE]")
3194 if game.options & OPTION_CURSES:
3196 setwnd(prompt_window)
3197 prompt_window.clear()
3198 prompt_window.addstr(prompt)
3199 prompt_window.getstr()
3200 prompt_window.clear()
3201 prompt_window.refresh()
3202 setwnd(message_window)
3205 sys.stdout.write('\n')
3209 sys.stdout.write('\n' * rows)
3213 "Skip i lines. Pause game if this would cause a scrolling event."
3214 for dummy in range(i):
3215 if game.options & OPTION_CURSES:
3216 (y, x) = curwnd.getyx()
3219 except curses.error:
3224 if rows and linecount >= rows:
3227 sys.stdout.write('\n')
3230 "Utter a line with no following line feed."
3231 if game.options & OPTION_CURSES:
3232 (y, x) = curwnd.getyx()
3233 (my, mx) = curwnd.getmaxyx()
3234 if curwnd == message_window and y >= my - 2:
3237 # Uncomment this to debug curses problems
3239 logfp.write("#curses: at %s proutn(%s)\n" % ((y, x), repr(line)))
3243 sys.stdout.write(line)
3253 if not replayfp or replayfp.closed: # Don't slow down replays
3256 if game.options & OPTION_CURSES:
3260 if not replayfp or replayfp.closed:
3264 "Get a line of input."
3265 if game.options & OPTION_CURSES:
3266 line = curwnd.getstr() + "\n"
3269 if replayfp and not replayfp.closed:
3271 line = replayfp.readline()
3274 prout("*** Replay finished")
3277 elif line[0] != "#":
3280 line = eval(input()) + "\n"
3286 "Change windows -- OK for this to be a no-op in tty mode."
3288 if game.options & OPTION_CURSES:
3289 # Uncomment this to debug curses problems
3291 if wnd == fullscreen_window:
3292 legend = "fullscreen"
3293 elif wnd == srscan_window:
3295 elif wnd == report_window:
3297 elif wnd == status_window:
3299 elif wnd == lrscan_window:
3301 elif wnd == message_window:
3303 elif wnd == prompt_window:
3307 logfp.write("#curses: setwnd(%s)\n" % legend)
3309 # Some curses implementations get confused when you try this.
3311 curses.curs_set(wnd in (fullscreen_window, message_window, prompt_window))
3312 except curses.error:
3316 "Clear to end of line -- can be a no-op in tty mode"
3317 if game.options & OPTION_CURSES:
3322 "Clear screen -- can be a no-op in tty mode."
3324 if game.options & OPTION_CURSES:
3330 def textcolor(color=DEFAULT):
3331 if game.options & OPTION_COLOR:
3332 if color == DEFAULT:
3334 elif color == BLACK:
3335 curwnd.attron(curses.color_pair(curses.COLOR_BLACK))
3337 curwnd.attron(curses.color_pair(curses.COLOR_BLUE))
3338 elif color == GREEN:
3339 curwnd.attron(curses.color_pair(curses.COLOR_GREEN))
3341 curwnd.attron(curses.color_pair(curses.COLOR_CYAN))
3343 curwnd.attron(curses.color_pair(curses.COLOR_RED))
3344 elif color == MAGENTA:
3345 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA))
3346 elif color == BROWN:
3347 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW))
3348 elif color == LIGHTGRAY:
3349 curwnd.attron(curses.color_pair(curses.COLOR_WHITE))
3350 elif color == DARKGRAY:
3351 curwnd.attron(curses.color_pair(curses.COLOR_BLACK) | curses.A_BOLD)
3352 elif color == LIGHTBLUE:
3353 curwnd.attron(curses.color_pair(curses.COLOR_BLUE) | curses.A_BOLD)
3354 elif color == LIGHTGREEN:
3355 curwnd.attron(curses.color_pair(curses.COLOR_GREEN) | curses.A_BOLD)
3356 elif color == LIGHTCYAN:
3357 curwnd.attron(curses.color_pair(curses.COLOR_CYAN) | curses.A_BOLD)
3358 elif color == LIGHTRED:
3359 curwnd.attron(curses.color_pair(curses.COLOR_RED) | curses.A_BOLD)
3360 elif color == LIGHTMAGENTA:
3361 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA) | curses.A_BOLD)
3362 elif color == YELLOW:
3363 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW) | curses.A_BOLD)
3364 elif color == WHITE:
3365 curwnd.attron(curses.color_pair(curses.COLOR_WHITE) | curses.A_BOLD)
3368 if game.options & OPTION_COLOR:
3369 curwnd.attron(curses.A_REVERSE)
3372 # Things past this point have policy implications.
3376 "Hook to be called after moving to redraw maps."
3377 if game.options & OPTION_CURSES:
3380 setwnd(srscan_window)
3384 setwnd(status_window)
3385 status_window.clear()
3386 status_window.move(0, 0)
3387 setwnd(report_window)
3388 report_window.clear()
3389 report_window.move(0, 0)
3391 setwnd(lrscan_window)
3392 lrscan_window.clear()
3393 lrscan_window.move(0, 0)
3394 lrscan(silent=False)
3396 def put_srscan_sym(w, sym):
3397 "Emit symbol for short-range scan."
3398 srscan_window.move(w.i+1, w.j*2+2)
3399 srscan_window.addch(sym)
3400 srscan_window.refresh()
3403 "Enemy fall down, go boom."
3404 if game.options & OPTION_CURSES:
3406 setwnd(srscan_window)
3407 srscan_window.attron(curses.A_REVERSE)
3408 put_srscan_sym(w, game.quad[w.i][w.j])
3412 srscan_window.attroff(curses.A_REVERSE)
3413 put_srscan_sym(w, game.quad[w.i][w.j])
3414 curses.delay_output(500)
3415 setwnd(message_window)
3418 "Sound and visual effects for teleportation."
3419 if game.options & OPTION_CURSES:
3421 setwnd(message_window)
3423 prouts(" . . . . . ")
3424 if game.options & OPTION_CURSES:
3425 #curses.delay_output(1000)
3429 def tracktorpedo(w, step, i, n, iquad):
3430 "Torpedo-track animation."
3431 if not game.options & OPTION_CURSES:
3435 proutn(_("Track for torpedo number %d- ") % (i+1))
3438 proutn(_("Torpedo track- "))
3439 elif step==4 or step==9:
3443 if not damaged(DSRSENS) or game.condition=="docked":
3444 if i != 0 and step == 1:
3447 if (iquad=='.') or (iquad==' '):
3448 put_srscan_sym(w, '+')
3452 put_srscan_sym(w, iquad)
3454 curwnd.attron(curses.A_REVERSE)
3455 put_srscan_sym(w, iquad)
3459 curwnd.attroff(curses.A_REVERSE)
3460 put_srscan_sym(w, iquad)
3465 "Display the current galaxy chart."
3466 if game.options & OPTION_CURSES:
3467 setwnd(message_window)
3468 message_window.clear()
3470 if game.options & OPTION_TTY:
3475 def prstat(txt, data):
3477 if game.options & OPTION_CURSES:
3479 setwnd(status_window)
3481 proutn(" " * (NSYM - len(txt)))
3484 if game.options & OPTION_CURSES:
3485 setwnd(report_window)
3487 # Code from moving.c begins here
3489 def imove(icourse=None, noattack=False):
3490 "Movement execution for warp, impulse, supernova, and tractor-beam events."
3493 def newquadrant(noattack):
3494 # Leaving quadrant -- allow final enemy attack
3495 # Don't do it if being pushed by Nova
3496 if len(game.enemies) != 0 and not noattack:
3498 for enemy in game.enemies:
3499 finald = (w - enemy.location).distance()
3500 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3501 # Stas Sergeev added the condition
3502 # that attacks only happen if Klingons
3503 # are present and your skill is good.
3504 if game.skill > SKILL_GOOD and game.klhere > 0 and not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3505 attack(torps_ok=False)
3508 # check for edge of galaxy
3512 if icourse.final.i < 0:
3513 icourse.final.i = -icourse.final.i
3515 if icourse.final.j < 0:
3516 icourse.final.j = -icourse.final.j
3518 if icourse.final.i >= GALSIZE*QUADSIZE:
3519 icourse.final.i = (GALSIZE*QUADSIZE*2) - icourse.final.i
3521 if icourse.final.j >= GALSIZE*QUADSIZE:
3522 icourse.final.j = (GALSIZE*QUADSIZE*2) - icourse.final.j
3530 if game.nkinks == 3:
3531 # Three strikes -- you're out!
3535 prout(_("YOU HAVE ATTEMPTED TO CROSS THE NEGATIVE ENERGY BARRIER"))
3536 prout(_("AT THE EDGE OF THE GALAXY. THE THIRD TIME YOU TRY THIS,"))
3537 prout(_("YOU WILL BE DESTROYED."))
3538 # Compute final position in new quadrant
3539 if trbeam: # Don't bother if we are to be beamed
3541 game.quadrant = icourse.final.quadrant()
3542 game.sector = icourse.final.sector()
3544 prout(_("Entering Quadrant %s.") % game.quadrant)
3545 game.quad[game.sector.i][game.sector.j] = game.ship
3547 if game.skill>SKILL_NOVICE:
3548 attack(torps_ok=False)
3550 def check_collision(h):
3551 iquad = game.quad[h.i][h.j]
3553 # object encountered in flight path
3554 stopegy = 50.0*icourse.distance/game.optime
3555 if iquad in ('T', 'K', 'C', 'S', 'R', '?'):
3556 for enemy in game.enemies:
3557 if enemy.location == game.sector:
3559 collision(rammed=False, enemy=enemy)
3563 prouts(_("***RED ALERT! RED ALERT!"))
3565 proutn("***" + crmshp())
3566 proutn(_(" pulled into black hole at Sector %s") % h)
3567 # Getting pulled into a black hole was certain
3568 # death in Almy's original. Stas Sergeev added a
3569 # possibility that you'll get timewarped instead.
3571 for m in range(NDEVICES):
3572 if game.damage[m]>0:
3574 probf=math.pow(1.4,(game.energy+game.shield)/5000.0-1.0)*math.pow(1.3,1.0/(n+1)-1.0)
3575 if (game.options & OPTION_BLKHOLE) and withprob(1-probf):
3585 prout(_(" encounters Tholian web at %s;") % h)
3587 prout(_(" blocked by object at %s;") % h)
3588 proutn(_("Emergency stop required "))
3589 prout(_("%2d units of energy.") % int(stopegy))
3590 game.energy -= stopegy
3591 if game.energy <= 0:
3598 prout(_("Helmsman Sulu- \"Leaving standard orbit.\""))
3599 game.inorbit = False
3600 # If tractor beam is to occur, don't move full distance
3601 if game.state.date+game.optime >= scheduled(FTBEAM):
3603 game.condition = "red"
3604 icourse.distance = icourse.distance*(scheduled(FTBEAM)-game.state.date)/game.optime + 0.1
3605 game.optime = scheduled(FTBEAM) - game.state.date + 1e-5
3607 game.quad[game.sector.i][game.sector.j] = '.'
3608 for m in range(icourse.moves):
3610 w = icourse.sector()
3611 if icourse.origin.quadrant() != icourse.location.quadrant():
3612 newquadrant(noattack)
3614 elif check_collision(w):
3615 print("Collision detected")
3619 # We're in destination quadrant -- compute new average enemy distances
3620 game.quad[game.sector.i][game.sector.j] = game.ship
3622 for enemy in game.enemies:
3623 finald = (w-enemy.location).distance()
3624 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3625 enemy.kdist = finald
3627 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3628 attack(torps_ok=False)
3629 for enemy in game.enemies:
3630 enemy.kavgd = enemy.kdist
3633 setwnd(message_window)
3637 "Dock our ship at a starbase."
3639 if game.condition == "docked" and verbose:
3640 prout(_("Already docked."))
3643 prout(_("You must first leave standard orbit."))
3645 if not game.base.is_valid() or abs(game.sector.i-game.base.i) > 1 or abs(game.sector.j-game.base.j) > 1:
3646 prout(crmshp() + _(" not adjacent to base."))
3648 game.condition = "docked"
3652 if game.energy < game.inenrg:
3653 game.energy = game.inenrg
3654 game.shield = game.inshld
3655 game.torps = game.intorps
3656 game.lsupres = game.inlsr
3657 game.state.crew = FULLCREW
3658 if not damaged(DRADIO) and \
3659 ((is_scheduled(FCDBAS) or game.isatb == 1) and not game.iseenit):
3660 # get attack report from base
3661 prout(_("Lt. Uhura- \"Captain, an important message from the starbase:\""))
3665 def cartesian(loc1=None, loc2=None):
3667 return game.quadrant * QUADSIZE + game.sector
3669 return game.quadrant * QUADSIZE + loc1
3671 return loc1 * QUADSIZE + loc2
3673 def getcourse(isprobe):
3674 "Get a course and distance from the user."
3676 dquad = copy.copy(game.quadrant)
3677 navmode = "unspecified"
3681 if game.landed and not isprobe:
3682 prout(_("Dummy! You can't leave standard orbit until you"))
3683 proutn(_("are back aboard the ship."))
3686 while navmode == "unspecified":
3687 if damaged(DNAVSYS):
3689 prout(_("Computer damaged; manual navigation only"))
3691 prout(_("Computer damaged; manual movement only"))
3696 key = scanner.nexttok()
3698 proutn(_("Manual or automatic- "))
3701 elif key == "IHALPHA":
3702 if scanner.sees("manual"):
3704 key = scanner.nexttok()
3706 elif scanner.sees("automatic"):
3707 navmode = "automatic"
3708 key = scanner.nexttok()
3716 prout(_("(Manual navigation assumed.)"))
3718 prout(_("(Manual movement assumed.)"))
3722 if navmode == "automatic":
3723 while key == "IHEOL":
3725 proutn(_("Target quadrant or quadrant§or- "))
3727 proutn(_("Destination sector or quadrant§or- "))
3730 key = scanner.nexttok()
3734 xi = int(round(scanner.real))-1
3735 key = scanner.nexttok()
3739 xj = int(round(scanner.real))-1
3740 key = scanner.nexttok()
3742 # both quadrant and sector specified
3743 xk = int(round(scanner.real))-1
3744 key = scanner.nexttok()
3748 xl = int(round(scanner.real))-1
3754 # only one pair of numbers was specified
3756 # only quadrant specified -- go to center of dest quad
3759 dsect.j = dsect.i = 4 # preserves 1-origin behavior
3761 # only sector specified
3765 if not dquad.valid_quadrant() or not dsect.valid_sector():
3772 prout(_("Helmsman Sulu- \"Course locked in for Sector %s.\"") % dsect)
3774 prout(_("Ensign Chekov- \"Course laid in, Captain.\""))
3775 # the actual deltas get computed here
3776 delta.j = dquad.j-game.quadrant.j + (dsect.j-game.sector.j)/(QUADSIZE*1.0)
3777 delta.i = game.quadrant.i-dquad.i + (game.sector.i-dsect.i)/(QUADSIZE*1.0)
3779 while key == "IHEOL":
3780 proutn(_("X and Y displacements- "))
3783 key = scanner.nexttok()
3788 delta.j = scanner.real
3789 key = scanner.nexttok()
3793 delta.i = scanner.real
3794 # Check for zero movement
3795 if delta.i == 0 and delta.j == 0:
3798 if itemp == "verbose" and not isprobe:
3800 prout(_("Helmsman Sulu- \"Aye, Sir.\""))
3802 return course(bearing=delta.bearing(), distance=delta.distance())
3805 def __init__(self, bearing, distance, origin=None):
3806 self.distance = distance
3807 self.bearing = bearing
3809 self.origin = cartesian(game.quadrant, game.sector)
3811 self.origin = origin
3812 # The bearing() code we inherited from FORTRAN is actually computing
3813 # clockface directions!
3814 if self.bearing < 0.0:
3815 self.bearing += 12.0
3816 self.angle = ((15.0 - self.bearing) * 0.5235988)
3818 self.origin = cartesian(game.quadrant, game.sector)
3820 self.origin = cartesian(game.quadrant, origin)
3821 self.increment = Coord(-math.sin(self.angle), math.cos(self.angle))
3822 bigger = max(abs(self.increment.i), abs(self.increment.j))
3823 self.increment /= bigger
3824 self.moves = int(round(10*self.distance*bigger))
3826 self.final = (self.location + self.moves*self.increment).roundtogrid()
3828 self.location = self.origin
3831 return self.location.roundtogrid() == self.final
3833 "Next step on course."
3835 self.nextlocation = self.location + self.increment
3836 samequad = (self.location.quadrant() == self.nextlocation.quadrant())
3837 self.location = self.nextlocation
3840 return self.location.quadrant()
3842 return self.location.sector()
3843 def power(self, warp):
3844 return self.distance*(warp**3)*(game.shldup+1)
3845 def time(self, warp):
3846 return 10.0*self.distance/warp**2
3849 "Move under impulse power."
3851 if damaged(DIMPULS):
3854 prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
3856 if game.energy > 30.0:
3858 course = getcourse(isprobe=False)
3861 power = 20.0 + 100.0*course.distance
3864 if power >= game.energy:
3865 # Insufficient power for trip
3867 prout(_("First Officer Spock- \"Captain, the impulse engines"))
3868 prout(_("require 20.0 units to engage, plus 100.0 units per"))
3869 if game.energy > 30:
3870 proutn(_("quadrant. We can go, therefore, a maximum of %d") %
3871 int(0.01 * (game.energy-20.0)-0.05))
3872 prout(_(" quadrants.\""))
3874 prout(_("quadrant. They are, therefore, useless.\""))
3877 # Make sure enough time is left for the trip
3878 game.optime = course.distance/0.095
3879 if game.optime >= game.state.remtime:
3880 prout(_("First Officer Spock- \"Captain, our speed under impulse"))
3881 prout(_("power is only 0.95 sectors per stardate. Are you sure"))
3882 proutn(_("we dare spend the time?\" "))
3885 # Activate impulse engines and pay the cost
3886 imove(course, noattack=False)
3890 power = 20.0 + 100.0*course.distance
3891 game.energy -= power
3892 game.optime = course.distance/0.095
3893 if game.energy <= 0:
3897 def warp(wcourse, involuntary):
3898 "ove under warp drive."
3899 blooey = False; twarp = False
3900 if not involuntary: # Not WARPX entry
3902 if game.damage[DWARPEN] > 10.0:
3905 prout(_("Engineer Scott- \"The warp engines are damaged, Sir.\""))
3907 if damaged(DWARPEN) and game.warpfac > 4.0:
3910 prout(_("Engineer Scott- \"Sorry, Captain. Until this damage"))
3911 prout(_(" is repaired, I can only give you warp 4.\""))
3913 # Read in course and distance
3916 wcourse = getcourse(isprobe=False)
3919 # Make sure starship has enough energy for the trip
3920 # Note: this formula is slightly different from the C version,
3921 # and lets you skate a bit closer to the edge.
3922 if wcourse.power(game.warpfac) >= game.energy:
3923 # Insufficient power for trip
3926 prout(_("Engineering to bridge--"))
3927 if not game.shldup or 0.5*wcourse.power(game.warpfac) > game.energy:
3928 iwarp = (game.energy/(wcourse.distance+0.05)) ** 0.333333333
3930 prout(_("We can't do it, Captain. We don't have enough energy."))
3932 proutn(_("We don't have enough energy, but we could do it at warp %d") % iwarp)
3935 prout(_("if you'll lower the shields."))
3939 prout(_("We haven't the energy to go that far with the shields up."))
3941 # Make sure enough time is left for the trip
3942 game.optime = wcourse.time(game.warpfac)
3943 if game.optime >= 0.8*game.state.remtime:
3945 prout(_("First Officer Spock- \"Captain, I compute that such"))
3946 proutn(_(" a trip would require approximately %2.0f") %
3947 (100.0*game.optime/game.state.remtime))
3948 prout(_(" percent of our"))
3949 proutn(_(" remaining time. Are you sure this is wise?\" "))
3955 if game.warpfac > 6.0:
3956 # Decide if engine damage will occur
3957 # ESR: Seems wrong. Probability of damage goes *down* with distance?
3958 prob = wcourse.distance*(6.0-game.warpfac)**2/66.666666666
3959 if prob > randreal():
3961 wcourse.distance = randreal(wcourse.distance)
3962 # Decide if time warp will occur
3963 if 0.5*wcourse.distance*math.pow(7.0,game.warpfac-10.0) > randreal():
3965 if game.idebug and game.warpfac==10 and not twarp:
3967 proutn("=== Force time warp? ")
3971 # If time warp or engine damage, check path
3972 # If it is obstructed, don't do warp or damage
3973 look = wcourse.moves
3977 w = wcourse.sector()
3978 if not w.valid_sector():
3980 if game.quad[w.i][w.j] != '.':
3984 # Activate Warp Engines and pay the cost
3985 imove(wcourse, noattack=False)
3988 game.energy -= wcourse.power(game.warpfac)
3989 if game.energy <= 0:
3991 game.optime = wcourse.time(game.warpfac)
3995 game.damage[DWARPEN] = game.damfac * randreal(1.0, 4.0)
3997 prout(_("Engineering to bridge--"))
3998 prout(_(" Scott here. The warp engines are damaged."))
3999 prout(_(" We'll have to reduce speed to warp 4."))
4004 "Change the warp factor."
4006 key=scanner.nexttok()
4010 proutn(_("Warp factor- "))
4014 if game.damage[DWARPEN] > 10.0:
4015 prout(_("Warp engines inoperative."))
4017 if damaged(DWARPEN) and scanner.real > 4.0:
4018 prout(_("Engineer Scott- \"I'm doing my best, Captain,"))
4019 prout(_(" but right now we can only go warp 4.\""))
4021 if scanner.real > 10.0:
4022 prout(_("Helmsman Sulu- \"Our top speed is warp 10, Captain.\""))
4024 if scanner.real < 1.0:
4025 prout(_("Helmsman Sulu- \"We can't go below warp 1, Captain.\""))
4027 oldfac = game.warpfac
4028 game.warpfac = scanner.real
4029 if game.warpfac <= oldfac or game.warpfac <= 6.0:
4030 prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\"") %
4033 if game.warpfac < 8.00:
4034 prout(_("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\""))
4036 if game.warpfac == 10.0:
4037 prout(_("Engineer Scott- \"Aye, Captain, we'll try it.\""))
4039 prout(_("Engineer Scott- \"Aye, Captain, but our engines may not take it.\""))
4043 "Cope with being tossed out of quadrant by supernova or yanked by beam."
4045 # is captain on planet?
4047 if damaged(DTRANSP):
4050 prout(_("Scotty rushes to the transporter controls."))
4052 prout(_("But with the shields up it's hopeless."))
4054 prouts(_("His desperate attempt to rescue you . . ."))
4059 prout(_("SUCCEEDS!"))
4062 proutn(_("The crystals mined were "))
4070 # Check to see if captain in shuttle craft
4075 # Inform captain of attempt to reach safety
4079 prouts(_("***RED ALERT! RED ALERT!"))
4081 proutn(_("The %s has stopped in a quadrant containing") % crmshp())
4082 prouts(_(" a supernova."))
4084 prout(_("***Emergency automatic override attempts to hurl ")+crmshp())
4085 prout(_("safely out of quadrant."))
4086 if not damaged(DRADIO):
4087 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
4088 # Try to use warp engines
4089 if damaged(DWARPEN):
4091 prout(_("Warp engines damaged."))
4094 game.warpfac = randreal(6.0, 8.0)
4095 prout(_("Warp factor set to %d") % int(game.warpfac))
4096 power = 0.75*game.energy
4097 dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1))
4098 dist = max(dist, randreal(math.sqrt(2)))
4099 bugout = course(bearing=randreal(12), distance=dist) # How dumb!
4100 game.optime = bugout.time(game.warpfac)
4102 game.inorbit = False
4103 warp(bugout, involuntary=True)
4105 # This is bad news, we didn't leave quadrant.
4109 prout(_("Insufficient energy to leave quadrant."))
4112 # Repeat if another snova
4113 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
4115 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
4116 finish(FWON) # Snova killed remaining enemy.
4119 "Let's do the time warp again."
4120 prout(_("***TIME WARP ENTERED."))
4121 if game.state.snap and withprob(0.5):
4123 prout(_("You are traveling backwards in time %d stardates.") %
4124 int(game.state.date-game.snapsht.date))
4125 game.state = game.snapsht
4126 game.state.snap = False
4127 if len(game.state.kcmdr):
4128 schedule(FTBEAM, expran(game.intime/len(game.state.kcmdr)))
4129 schedule(FBATTAK, expran(0.3*game.intime))
4130 schedule(FSNOVA, expran(0.5*game.intime))
4131 # next snapshot will be sooner
4132 schedule(FSNAP, expran(0.25*game.state.remtime))
4134 if game.state.nscrem:
4135 schedule(FSCMOVE, 0.2777)
4139 game.battle.invalidate()
4140 # Make sure Galileo is consistant -- Snapshot may have been taken
4141 # when on planet, which would give us two Galileos!
4143 for l in range(game.inplan):
4144 if game.state.planets[l].known == "shuttle_down":
4146 if game.iscraft == "onship" and game.ship=='E':
4147 prout(_("Chekov- \"Security reports the Galileo has disappeared, Sir!"))
4148 game.iscraft = "offship"
4149 # Likewise, if in the original time the Galileo was abandoned, but
4150 # was on ship earlier, it would have vanished -- let's restore it.
4151 if game.iscraft == "offship" and not gotit and game.damage[DSHUTTL] >= 0.0:
4152 prout(_("Chekov- \"Security reports the Galileo has reappeared in the dock!\""))
4153 game.iscraft = "onship"
4154 # There used to be code to do the actual reconstrction here,
4155 # but the starchart is now part of the snapshotted galaxy state.
4156 prout(_("Spock has reconstructed a correct star chart from memory"))
4158 # Go forward in time
4159 game.optime = expran(0.5*game.intime)
4160 prout(_("You are traveling forward in time %d stardates.") % int(game.optime))
4161 # cheat to make sure no tractor beams occur during time warp
4162 postpone(FTBEAM, game.optime)
4163 game.damage[DRADIO] += game.optime
4165 events() # Stas Sergeev added this -- do pending events
4168 "Launch deep-space probe."
4169 # New code to launch a deep space probe
4170 if game.nprobes == 0:
4173 if game.ship == 'E':
4174 prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\""))
4176 prout(_("Ye Faerie Queene has no deep space probes."))
4181 prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\""))
4183 if is_scheduled(FDSPROB):
4186 if damaged(DRADIO) and game.condition != "docked":
4187 prout(_("Spock- \"Records show the previous probe has not yet"))
4188 prout(_(" reached its destination.\""))
4190 prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""))
4192 key = scanner.nexttok()
4194 if game.nprobes == 1:
4195 prout(_("1 probe left."))
4197 prout(_("%d probes left") % game.nprobes)
4198 proutn(_("Are you sure you want to fire a probe? "))
4201 game.isarmed = False
4202 if key == "IHALPHA" and scanner.token == "armed":
4204 key = scanner.nexttok()
4205 elif key == "IHEOL":
4206 proutn(_("Arm NOVAMAX warhead? "))
4208 elif key == "IHREAL": # first element of course
4209 scanner.push(scanner.token)
4211 game.probe = getcourse(isprobe=True)
4215 schedule(FDSPROB, 0.01) # Time to move one sector
4216 prout(_("Ensign Chekov- \"The deep space probe is launched, Captain.\""))
4221 "Yell for help from nearest starbase."
4222 # There's more than one way to move in this game!
4224 # Test for conditions which prevent calling for help
4225 if game.condition == "docked":
4226 prout(_("Lt. Uhura- \"But Captain, we're already docked.\""))
4229 prout(_("Subspace radio damaged."))
4231 if not game.state.baseq:
4232 prout(_("Lt. Uhura- \"Captain, I'm not getting any response from Starbase.\""))
4235 prout(_("You must be aboard the %s.") % crmshp())
4237 # OK -- call for help from nearest starbase
4240 # There's one in this quadrant
4241 ddist = (game.base - game.sector).distance()
4244 for ibq in game.state.baseq:
4245 xdist = QUADSIZE * (ibq - game.quadrant).distance()
4248 # Since starbase not in quadrant, set up new quadrant
4251 # dematerialize starship
4252 game.quad[game.sector.i][game.sector.j]='.'
4253 proutn(_("Starbase in Quadrant %s responds--%s dematerializes") \
4254 % (game.quadrant, crmshp()))
4255 game.sector.invalidate()
4256 for m in range(1, 5+1):
4257 w = game.base.scatter()
4258 if w.valid_sector() and game.quad[w.i][w.j]=='.':
4259 # found one -- finish up
4262 if not game.sector.is_valid():
4263 prout(_("You have been lost in space..."))
4264 finish(FMATERIALIZE)
4266 # Give starbase three chances to rematerialize starship
4267 probf = math.pow((1.0 - math.pow(0.98,ddist)), 0.33333333)
4268 for m in range(1, 3+1):
4269 if m == 1: proutn(_("1st"))
4270 elif m == 2: proutn(_("2nd"))
4271 elif m == 3: proutn(_("3rd"))
4272 proutn(_(" attempt to re-materialize ") + crmshp())
4273 game.quad[game.sector.i][game.sector.j]=('-','o','O')[m-1]
4276 if randreal() > probf:
4280 curses.delay_output(500)
4282 game.quad[game.sector.i][game.sector.j]='?'
4285 setwnd(message_window)
4286 finish(FMATERIALIZE)
4288 game.quad[game.sector.i][game.sector.j]=game.ship
4290 prout(_("succeeds."))
4294 prout(_("Lt. Uhura- \"Captain, we made it!\""))
4299 if game.condition=="docked":
4301 prout(_("You cannot abandon Ye Faerie Queene."))
4304 # Must take shuttle craft to exit
4305 if game.damage[DSHUTTL]==-1:
4306 prout(_("Ye Faerie Queene has no shuttle craft."))
4308 if game.damage[DSHUTTL]<0:
4309 prout(_("Shuttle craft now serving Big Macs."))
4311 if game.damage[DSHUTTL]>0:
4312 prout(_("Shuttle craft damaged."))
4315 prout(_("You must be aboard the ship."))
4317 if game.iscraft != "onship":
4318 prout(_("Shuttle craft not currently available."))
4320 # Emit abandon ship messages
4322 prouts(_("***ABANDON SHIP! ABANDON SHIP!"))
4324 prouts(_("***ALL HANDS ABANDON SHIP!"))
4326 prout(_("Captain and crew escape in shuttle craft."))
4327 if not game.state.baseq:
4328 # Oops! no place to go...
4331 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
4333 if not (game.options & OPTION_WORLDS) and not damaged(DTRANSP):
4334 prout(_("Remainder of ship's complement beam down"))
4335 prout(_("to nearest habitable planet."))
4336 elif q.planet != None and not damaged(DTRANSP):
4337 prout(_("Remainder of ship's complement beam down to %s.") %
4340 prout(_("Entire crew of %d left to die in outer space.") %
4342 game.casual += game.state.crew
4343 game.abandoned += game.state.crew
4344 # If at least one base left, give 'em the Faerie Queene
4346 game.icrystl = False # crystals are lost
4347 game.nprobes = 0 # No probes
4348 prout(_("You are captured by Klingons and released to"))
4349 prout(_("the Federation in a prisoner-of-war exchange."))
4350 nb = randrange(len(game.state.baseq))
4351 # Set up quadrant and position FQ adjacient to base
4352 if not game.quadrant == game.state.baseq[nb]:
4353 game.quadrant = game.state.baseq[nb]
4354 game.sector.i = game.sector.j = 5
4357 # position next to base by trial and error
4358 game.quad[game.sector.i][game.sector.j] = '.'
4359 for l in range(QUADSIZE):
4360 game.sector = game.base.scatter()
4361 if game.sector.valid_sector() and \
4362 game.quad[game.sector.i][game.sector.j] == '.':
4365 break # found a spot
4366 game.sector.i=QUADSIZE/2
4367 game.sector.j=QUADSIZE/2
4369 # Get new commission
4370 game.quad[game.sector.i][game.sector.j] = game.ship = 'F'
4371 game.state.crew = FULLCREW
4372 prout(_("Starfleet puts you in command of another ship,"))
4373 prout(_("the Faerie Queene, which is antiquated but,"))
4374 prout(_("still useable."))
4376 prout(_("The dilithium crystals have been moved."))
4378 game.iscraft = "offship" # Galileo disappears
4380 game.condition="docked"
4381 for l in range(NDEVICES):
4382 game.damage[l] = 0.0
4383 game.damage[DSHUTTL] = -1
4384 game.energy = game.inenrg = 3000.0
4385 game.shield = game.inshld = 1250.0
4386 game.torps = game.intorps = 6
4387 game.lsupres=game.inlsr=3.0
4392 # Code from planets.c begins here.
4395 "Abort a lengthy operation if an event interrupts it."
4398 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.justin:
4403 "Report on (uninhabited) planets in the galaxy."
4407 prout(_("Spock- \"Planet report follows, Captain.\""))
4409 for i in range(game.inplan):
4410 if game.state.planets[i].pclass == "destroyed":
4412 if (game.state.planets[i].known != "unknown" \
4413 and not game.state.planets[i].inhabited) \
4416 if game.idebug and game.state.planets[i].known=="unknown":
4417 proutn("(Unknown) ")
4418 proutn(_("Quadrant %s") % game.state.planets[i].quadrant)
4419 proutn(_(" class "))
4420 proutn(game.state.planets[i].pclass)
4422 if game.state.planets[i].crystals != "present":
4424 prout(_("dilithium crystals present."))
4425 if game.state.planets[i].known=="shuttle_down":
4426 prout(_(" Shuttle Craft Galileo on surface."))
4428 prout(_("No information available."))
4431 "Enter standard orbit."
4435 prout(_("Already in standard orbit."))
4437 if damaged(DWARPEN) and damaged(DIMPULS):
4438 prout(_("Both warp and impulse engines damaged."))
4440 if not game.plnet.is_valid():
4441 prout("There is no planet in this sector.")
4443 if abs(game.sector.i-game.plnet.i)>1 or abs(game.sector.j-game.plnet.j)>1:
4444 prout(crmshp() + _(" not adjacent to planet."))
4447 game.optime = randreal(0.02, 0.05)
4448 prout(_("Helmsman Sulu- \"Entering standard orbit, Sir.\""))
4452 game.height = randreal(1400, 8600)
4453 prout(_("Sulu- \"Entered orbit at altitude %.2f kilometers.\"") % game.height)
4458 "Examine planets in this quadrant."
4459 if damaged(DSRSENS):
4460 if game.options & OPTION_TTY:
4461 prout(_("Short range sensors damaged."))
4463 if game.iplnet == None:
4464 if game.options & OPTION_TTY:
4465 prout(_("Spock- \"No planet in this quadrant, Captain.\""))
4467 if game.iplnet.known == "unknown":
4468 prout(_("Spock- \"Sensor scan for Quadrant %s-") % game.quadrant)
4470 prout(_(" Planet at Sector %s is of class %s.") %
4471 (game.plnet, game.iplnet.pclass))
4472 if game.iplnet.known=="shuttle_down":
4473 prout(_(" Sensors show Galileo still on surface."))
4474 proutn(_(" Readings indicate"))
4475 if game.iplnet.crystals != "present":
4477 prout(_(" dilithium crystals present.\""))
4478 if game.iplnet.known == "unknown":
4479 game.iplnet.known = "known"
4480 elif game.iplnet.inhabited:
4481 prout(_("Spock- \"The inhabited planet %s ") % game.iplnet.name)
4482 prout(_(" is located at Sector %s, Captain.\"") % game.plnet)
4485 "Use the transporter."
4489 if damaged(DTRANSP):
4490 prout(_("Transporter damaged."))
4491 if not damaged(DSHUTTL) and (game.iplnet.known=="shuttle_down" or game.iscraft == "onship"):
4493 proutn(_("Spock- \"May I suggest the shuttle craft, Sir?\" "))
4497 if not game.inorbit:
4498 prout(crmshp() + _(" not in standard orbit."))
4501 prout(_("Impossible to transport through shields."))
4503 if game.iplnet.known=="unknown":
4504 prout(_("Spock- \"Captain, we have no information on this planet"))
4505 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4506 prout(_(" you may not go down.\""))
4508 if not game.landed and game.iplnet.crystals=="absent":
4509 prout(_("Spock- \"Captain, I fail to see the logic in"))
4510 prout(_(" exploring a planet with no dilithium crystals."))
4511 proutn(_(" Are you sure this is wise?\" "))
4515 if not (game.options & OPTION_PLAIN):
4516 nrgneed = 50 * game.skill + game.height / 100.0
4517 if nrgneed > game.energy:
4518 prout(_("Engineering to bridge--"))
4519 prout(_(" Captain, we don't have enough energy for transportation."))
4521 if not game.landed and nrgneed * 2 > game.energy:
4522 prout(_("Engineering to bridge--"))
4523 prout(_(" Captain, we have enough energy only to transport you down to"))
4524 prout(_(" the planet, but there wouldn't be an energy for the trip back."))
4525 if game.iplnet.known == "shuttle_down":
4526 prout(_(" Although the Galileo shuttle craft may still be on a surface."))
4527 proutn(_(" Are you sure this is wise?\" "))
4532 # Coming from planet
4533 if game.iplnet.known=="shuttle_down":
4534 proutn(_("Spock- \"Wouldn't you rather take the Galileo?\" "))
4538 prout(_("Your crew hides the Galileo to prevent capture by aliens."))
4539 prout(_("Landing party assembled, ready to beam up."))
4541 prout(_("Kirk whips out communicator..."))
4542 prouts(_("BEEP BEEP BEEP"))
4544 prout(_("\"Kirk to enterprise- Lock on coordinates...energize.\""))
4547 prout(_("Scotty- \"Transporter room ready, Sir.\""))
4549 prout(_("Kirk and landing party prepare to beam down to planet surface."))
4551 prout(_("Kirk- \"Energize.\""))
4554 prouts("WWHOOOIIIIIRRRRREEEE.E.E. . . . . . .")
4556 if not withprob(0.98):
4557 prouts("BOOOIIIOOOIIOOOOIIIOIING . . .")
4559 prout(_("Scotty- \"Oh my God! I've lost them.\""))
4562 prouts(". . . . . . .E.E.EEEERRRRRIIIIIOOOHWW")
4563 game.landed = not game.landed
4564 game.energy -= nrgneed
4566 prout(_("Transport complete."))
4567 if game.landed and game.iplnet.known=="shuttle_down":
4568 prout(_("The shuttle craft Galileo is here!"))
4569 if not game.landed and game.imine:
4576 "Strip-mine a world for dilithium."
4580 prout(_("Mining party not on planet."))
4582 if game.iplnet.crystals == "mined":
4583 prout(_("This planet has already been strip-mined for dilithium."))
4585 elif game.iplnet.crystals == "absent":
4586 prout(_("No dilithium crystals on this planet."))
4589 prout(_("You've already mined enough crystals for this trip."))
4591 if game.icrystl and game.cryprob == 0.05:
4592 prout(_("With all those fresh crystals aboard the ") + crmshp())
4593 prout(_("there's no reason to mine more at this time."))
4595 game.optime = randreal(0.1, 0.3)*(ord(game.iplnet.pclass)-ord("L"))
4598 prout(_("Mining operation complete."))
4599 game.iplnet.crystals = "mined"
4600 game.imine = game.ididit = True
4603 "Use dilithium crystals."
4607 if not game.icrystl:
4608 prout(_("No dilithium crystals available."))
4610 if game.energy >= 1000:
4611 prout(_("Spock- \"Captain, Starfleet Regulations prohibit such an operation"))
4612 prout(_(" except when Condition Yellow exists."))
4614 prout(_("Spock- \"Captain, I must warn you that loading"))
4615 prout(_(" raw dilithium crystals into the ship's power"))
4616 prout(_(" system may risk a severe explosion."))
4617 proutn(_(" Are you sure this is wise?\" "))
4622 prout(_("Engineering Officer Scott- \"(GULP) Aye Sir."))
4623 prout(_(" Mr. Spock and I will try it.\""))
4625 prout(_("Spock- \"Crystals in place, Sir."))
4626 prout(_(" Ready to activate circuit.\""))
4628 prouts(_("Scotty- \"Keep your fingers crossed, Sir!\""))
4630 if withprob(game.cryprob):
4631 prouts(_(" \"Activating now! - - No good! It's***"))
4633 prouts(_("***RED ALERT! RED A*L********************************"))
4636 prouts(_("****************** KA-BOOM!!!! *******************"))
4640 game.energy += randreal(5000.0, 5500.0)
4641 prouts(_(" \"Activating now! - - "))
4642 prout(_("The instruments"))
4643 prout(_(" are going crazy, but I think it's"))
4644 prout(_(" going to work!! Congratulations, Sir!\""))
4649 "Use shuttlecraft for planetary jaunt."
4652 if damaged(DSHUTTL):
4653 if game.damage[DSHUTTL] == -1.0:
4654 if game.inorbit and game.iplnet.known == "shuttle_down":
4655 prout(_("Ye Faerie Queene has no shuttle craft bay to dock it at."))
4657 prout(_("Ye Faerie Queene had no shuttle craft."))
4658 elif game.damage[DSHUTTL] > 0:
4659 prout(_("The Galileo is damaged."))
4660 else: # game.damage[DSHUTTL] < 0
4661 prout(_("Shuttle craft is now serving Big Macs."))
4663 if not game.inorbit:
4664 prout(crmshp() + _(" not in standard orbit."))
4666 if (game.iplnet.known != "shuttle_down") and game.iscraft != "onship":
4667 prout(_("Shuttle craft not currently available."))
4669 if not game.landed and game.iplnet.known=="shuttle_down":
4670 prout(_("You will have to beam down to retrieve the shuttle craft."))
4672 if game.shldup or game.condition == "docked":
4673 prout(_("Shuttle craft cannot pass through shields."))
4675 if game.iplnet.known=="unknown":
4676 prout(_("Spock- \"Captain, we have no information on this planet"))
4677 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4678 prout(_(" you may not fly down.\""))
4680 game.optime = 3.0e-5*game.height
4681 if game.optime >= 0.8*game.state.remtime:
4682 prout(_("First Officer Spock- \"Captain, I compute that such"))
4683 proutn(_(" a maneuver would require approximately %2d%% of our") % \
4684 int(100*game.optime/game.state.remtime))
4685 prout(_("remaining time."))
4686 proutn(_("Are you sure this is wise?\" "))
4692 if game.iscraft == "onship":
4694 if not damaged(DTRANSP):
4695 proutn(_("Spock- \"Would you rather use the transporter?\" "))
4699 proutn(_("Shuttle crew"))
4701 proutn(_("Rescue party"))
4702 prout(_(" boards Galileo and swoops toward planet surface."))
4703 game.iscraft = "offship"
4707 game.iplnet.known="shuttle_down"
4708 prout(_("Trip complete."))
4711 # Ready to go back to ship
4712 prout(_("You and your mining party board the"))
4713 prout(_("shuttle craft for the trip back to the Enterprise."))
4715 prouts(_("The short hop begins . . ."))
4717 game.iplnet.known="known"
4723 game.iscraft = "onship"
4729 prout(_("Trip complete."))
4732 # Kirk on ship and so is Galileo
4733 prout(_("Mining party assembles in the hangar deck,"))
4734 prout(_("ready to board the shuttle craft \"Galileo\"."))
4736 prouts(_("The hangar doors open; the trip begins."))
4739 game.iscraft = "offship"
4742 game.iplnet.known = "shuttle_down"
4745 prout(_("Trip complete."))
4749 "Use the big zapper."
4753 if game.ship != 'E':
4754 prout(_("Ye Faerie Queene has no death ray."))
4756 if len(game.enemies)==0:
4757 prout(_("Sulu- \"But Sir, there are no enemies in this quadrant.\""))
4760 prout(_("Death Ray is damaged."))
4762 prout(_("Spock- \"Captain, the 'Experimental Death Ray'"))
4763 prout(_(" is highly unpredictible. Considering the alternatives,"))
4764 proutn(_(" are you sure this is wise?\" "))
4767 prout(_("Spock- \"Acknowledged.\""))
4770 prouts(_("WHOOEE ... WHOOEE ... WHOOEE ... WHOOEE"))
4772 prout(_("Crew scrambles in emergency preparation."))
4773 prout(_("Spock and Scotty ready the death ray and"))
4774 prout(_("prepare to channel all ship's power to the device."))
4776 prout(_("Spock- \"Preparations complete, sir.\""))
4777 prout(_("Kirk- \"Engage!\""))
4779 prouts(_("WHIRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"))
4782 if game.options & OPTION_PLAIN:
4786 prouts(_("Sulu- \"Captain! It's working!\""))
4788 while len(game.enemies) > 0:
4789 deadkl(game.enemies[1].location, game.quad[game.enemies[1].location.i][game.enemies[1].location.j],game.enemies[1].location)
4790 prout(_("Ensign Chekov- \"Congratulations, Captain!\""))
4791 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
4793 if (game.options & OPTION_PLAIN) == 0:
4794 prout(_("Spock- \"Captain, I believe the `Experimental Death Ray'"))
4796 prout(_(" is still operational.\""))
4798 prout(_(" has been rendered nonfunctional.\""))
4799 game.damage[DDRAY] = 39.95
4801 r = randreal() # Pick failure method
4803 prouts(_("Sulu- \"Captain! It's working!\""))
4805 prouts(_("***RED ALERT! RED ALERT!"))
4807 prout(_("***MATTER-ANTIMATTER IMPLOSION IMMINENT!"))
4809 prouts(_("***RED ALERT! RED A*L********************************"))
4812 prouts(_("****************** KA-BOOM!!!! *******************"))
4817 prouts(_("Sulu- \"Captain! Yagabandaghangrapl, brachriigringlanbla!\""))
4819 prout(_("Lt. Uhura- \"Graaeek! Graaeek!\""))
4821 prout(_("Spock- \"Fascinating! . . . All humans aboard"))
4822 prout(_(" have apparently been transformed into strange mutations."))
4823 prout(_(" Vulcans do not seem to be affected."))
4825 prout(_("Kirk- \"Raauch! Raauch!\""))
4829 prouts(_("Sulu- \"Captain! It's --WHAT?!?!\""))
4831 proutn(_("Spock- \"I believe the word is"))
4832 prouts(_(" *ASTONISHING*"))
4833 prout(_(" Mr. Sulu."))
4834 for i in range(QUADSIZE):
4835 for j in range(QUADSIZE):
4836 if game.quad[i][j] == '.':
4837 game.quad[i][j] = '?'
4838 prout(_(" Captain, our quadrant is now infested with"))
4839 prouts(_(" - - - - - - *THINGS*."))
4841 prout(_(" I have no logical explanation.\""))
4843 prouts(_("Sulu- \"Captain! The Death Ray is creating tribbles!\""))
4845 prout(_("Scotty- \"There are so many tribbles down here"))
4846 prout(_(" in Engineering, we can't move for 'em, Captain.\""))
4850 # Code from reports.c begins here
4852 def attackreport(curt):
4853 "eport status of bases under attack."
4855 if is_scheduled(FCDBAS):
4856 prout(_("Starbase in Quadrant %s is currently under Commander attack.") % game.battle)
4857 prout(_("It can hold out until Stardate %d.") % int(scheduled(FCDBAS)))
4858 elif game.isatb == 1:
4859 prout(_("Starbase in Quadrant %s is under Super-commander attack.") % game.state.kscmdr)
4860 prout(_("It can hold out until Stardate %d.") % int(scheduled(FSCDBAS)))
4862 prout(_("No Starbase is currently under attack."))
4864 if is_scheduled(FCDBAS):
4865 proutn(_("Base in %s attacked by C. Alive until %.1f") % (game.battle, scheduled(FCDBAS)))
4867 proutn(_("Base in %s attacked by S. Alive until %.1f") % (game.state.kscmdr, scheduled(FSCDBAS)))
4871 # report on general game status
4873 s1 = (game.thawed and _("thawed ")) or ""
4874 s2 = {1:"short", 2:"medium", 4:"long"}[game.length]
4875 s3 = (None, _("novice"), _("fair"),
4876 _("good"), _("expert"), _("emeritus"))[game.skill]
4877 prout(_("You %s a %s%s %s game.") % ((_("were playing"), _("are playing"))[game.alldone], s1, s2, s3))
4878 if game.skill>SKILL_GOOD and game.thawed and not game.alldone:
4879 prout(_("No plaque is allowed."))
4881 prout(_("This is tournament game %d.") % game.tourn)
4882 prout(_("Your secret password is \"%s\"") % game.passwd)
4883 proutn(_("%d of %d Klingons have been killed") % (((game.inkling + game.incom + game.inscom) - (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)),
4884 (game.inkling + game.incom + game.inscom)))
4885 if game.incom - len(game.state.kcmdr):
4886 prout(_(", including %d Commander%s.") % (game.incom - len(game.state.kcmdr), (_("s"), "")[(game.incom - len(game.state.kcmdr))==1]))
4887 elif game.inkling - game.state.remkl + (game.inscom - game.state.nscrem) > 0:
4888 prout(_(", but no Commanders."))
4891 if game.skill > SKILL_FAIR:
4892 prout(_("The Super Commander has %sbeen destroyed.") % ("", _("not "))[game.state.nscrem])
4893 if len(game.state.baseq) != game.inbase:
4895 if game.inbase-len(game.state.baseq)==1:
4896 proutn(_("has been 1 base"))
4898 proutn(_("have been %d bases") % (game.inbase-len(game.state.baseq)))
4899 prout(_(" destroyed, %d remaining.") % len(game.state.baseq))
4901 prout(_("There are %d bases.") % game.inbase)
4902 if communicating() or game.iseenit:
4903 # Don't report this if not seen and
4904 # either the radio is dead or not at base!
4908 prout(_("%d casualt%s suffered so far.") % (game.casual, ("y", "ies")[game.casual!=1]))
4910 prout(_("There were %d call%s for help.") % (game.nhelp, ("" , _("s"))[game.nhelp!=1]))
4911 if game.ship == 'E':
4912 proutn(_("You have "))
4914 proutn("%d" % (game.nprobes))
4917 proutn(_(" deep space probe"))
4921 if communicating() and is_scheduled(FDSPROB):
4923 proutn(_("An armed deep space probe is in "))
4925 proutn(_("A deep space probe is in "))
4926 prout("Quadrant %s." % game.probec)
4928 if game.cryprob <= .05:
4929 prout(_("Dilithium crystals aboard ship... not yet used."))
4933 while game.cryprob > ai:
4936 prout(_("Dilithium crystals have been used %d time%s.") % \
4937 (i, (_("s"), "")[i==1]))
4941 "Long-range sensor scan."
4942 if damaged(DLRSENS):
4943 # Now allow base's sensors if docked
4944 if game.condition != "docked":
4946 prout(_("LONG-RANGE SENSORS DAMAGED."))
4949 prout(_("Starbase's long-range scan"))
4951 prout(_("Long-range scan"))
4952 for x in range(game.quadrant.i-1, game.quadrant.i+2):
4955 for y in range(game.quadrant.j-1, game.quadrant.j+2):
4956 if not Coord(x, y).valid_quadrant():
4960 if not damaged(DRADIO):
4961 game.state.galaxy[x][y].charted = True
4962 game.state.chart[x][y].klingons = game.state.galaxy[x][y].klingons
4963 game.state.chart[x][y].starbase = game.state.galaxy[x][y].starbase
4964 game.state.chart[x][y].stars = game.state.galaxy[x][y].stars
4965 if not silent and game.state.galaxy[x][y].supernova:
4968 proutn(" %3d" % (game.state.chart[x][y].klingons*100 + game.state.chart[x][y].starbase * 10 + game.state.chart[x][y].stars))
4976 for i in range(NDEVICES):
4979 prout(_("\tDEVICE\t\t\t-REPAIR TIMES-"))
4980 prout(_("\t\t\tIN FLIGHT\t\tDOCKED"))
4982 prout(" %-26s\t%8.2f\t\t%8.2f" % (device[i],
4983 game.damage[i]+0.05,
4984 DOCKFAC*game.damage[i]+0.005))
4986 prout(_("All devices functional."))
4989 "Update the chart in the Enterprise's computer from galaxy data."
4990 game.lastchart = game.state.date
4991 for i in range(GALSIZE):
4992 for j in range(GALSIZE):
4993 if game.state.galaxy[i][j].charted:
4994 game.state.chart[i][j].klingons = game.state.galaxy[i][j].klingons
4995 game.state.chart[i][j].starbase = game.state.galaxy[i][j].starbase
4996 game.state.chart[i][j].stars = game.state.galaxy[i][j].stars
4999 "Display the star chart."
5001 if (game.options & OPTION_AUTOSCAN):
5003 if not damaged(DRADIO):
5005 if game.lastchart < game.state.date and game.condition == "docked":
5006 prout(_("Spock- \"I revised the Star Chart from the starbase's records.\""))
5008 prout(_(" STAR CHART FOR THE KNOWN GALAXY"))
5009 if game.state.date > game.lastchart:
5010 prout(_("(Last surveillance update %d stardates ago).") % ((int)(game.state.date-game.lastchart)))
5011 prout(" 1 2 3 4 5 6 7 8")
5012 for i in range(GALSIZE):
5013 proutn("%d |" % (i+1))
5014 for j in range(GALSIZE):
5015 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5019 if game.state.galaxy[i][j].supernova:
5021 elif not game.state.galaxy[i][j].charted and game.state.galaxy[i][j].starbase:
5023 elif game.state.galaxy[i][j].charted:
5024 show = "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars)
5028 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5036 def sectscan(goodScan, i, j):
5037 "Light up an individual dot in a sector."
5038 if goodScan or (abs(i-game.sector.i)<= 1 and abs(j-game.sector.j) <= 1):
5039 textcolor({"green":GREEN,
5043 "dead":BROWN}[game.condition])
5044 if game.quad[i][j] != game.ship:
5046 proutn("%c " % game.quad[i][j])
5052 "Emit status report lines"
5053 if not req or req == 1:
5054 prstat(_("Stardate"), _("%.1f, Time Left %.2f") \
5055 % (game.state.date, game.state.remtime))
5056 if not req or req == 2:
5057 if game.condition != "docked":
5059 prstat(_("Condition"), _("%s, %i DAMAGES") % \
5060 (game.condition.upper(), sum([x > 0 for x in game.damage])))
5061 if not req or req == 3:
5062 prstat(_("Position"), "%s , %s" % (game.quadrant, game.sector))
5063 if not req or req == 4:
5064 if damaged(DLIFSUP):
5065 if game.condition == "docked":
5066 s = _("DAMAGED, Base provides")
5068 s = _("DAMAGED, reserves=%4.2f") % game.lsupres
5071 prstat(_("Life Support"), s)
5072 if not req or req == 5:
5073 prstat(_("Warp Factor"), "%.1f" % game.warpfac)
5074 if not req or req == 6:
5076 if game.icrystl and (game.options & OPTION_SHOWME):
5077 extra = _(" (have crystals)")
5078 prstat(_("Energy"), "%.2f%s" % (game.energy, extra))
5079 if not req or req == 7:
5080 prstat(_("Torpedoes"), "%d" % (game.torps))
5081 if not req or req == 8:
5082 if damaged(DSHIELD):
5088 data = _(" %d%% %.1f units") \
5089 % (int((100.0*game.shield)/game.inshld + 0.5), game.shield)
5090 prstat(_("Shields"), s+data)
5091 if not req or req == 9:
5092 prstat(_("Klingons Left"), "%d" \
5093 % (game.state.remkl+len(game.state.kcmdr)+game.state.nscrem))
5094 if not req or req == 10:
5095 if game.options & OPTION_WORLDS:
5096 plnet = game.state.galaxy[game.quadrant.i][game.quadrant.j].planet
5097 if plnet and plnet.inhabited:
5098 prstat(_("Major system"), plnet.name)
5100 prout(_("Sector is uninhabited"))
5101 elif not req or req == 11:
5102 attackreport(not req)
5105 "Request specified status data, a historical relic from slow TTYs."
5106 requests = ("da","co","po","ls","wa","en","to","sh","kl","sy", "ti")
5107 while scanner.nexttok() == "IHEOL":
5108 proutn(_("Information desired? "))
5110 if scanner.token in requests:
5111 status(requests.index(scanner.token))
5113 prout(_("UNRECOGNIZED REQUEST. Legal requests are:"))
5114 prout((" date, condition, position, lsupport, warpfactor,"))
5115 prout((" energy, torpedoes, shields, klingons, system, time."))
5120 if damaged(DSRSENS):
5121 # Allow base's sensors if docked
5122 if game.condition != "docked":
5123 prout(_(" S.R. SENSORS DAMAGED!"))
5126 prout(_(" [Using Base's sensors]"))
5128 prout(_(" Short-range scan"))
5129 if goodScan and not damaged(DRADIO):
5130 game.state.chart[game.quadrant.i][game.quadrant.j].klingons = game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons
5131 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase
5132 game.state.chart[game.quadrant.i][game.quadrant.j].stars = game.state.galaxy[game.quadrant.i][game.quadrant.j].stars
5133 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
5134 prout(" 1 2 3 4 5 6 7 8 9 10")
5135 if game.condition != "docked":
5137 for i in range(QUADSIZE):
5138 proutn("%2d " % (i+1))
5139 for j in range(QUADSIZE):
5140 sectscan(goodScan, i, j)
5144 "Use computer to get estimated time of arrival for a warp jump."
5145 w1 = Coord(); w2 = Coord()
5147 if damaged(DCOMPTR):
5148 prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR."))
5151 if scanner.nexttok() != "IHREAL":
5154 proutn(_("Destination quadrant and/or sector? "))
5155 if scanner.nexttok()!="IHREAL":
5158 w1.j = int(scanner.real-0.5)
5159 if scanner.nexttok() != "IHREAL":
5162 w1.i = int(scanner.real-0.5)
5163 if scanner.nexttok() == "IHREAL":
5164 w2.j = int(scanner.real-0.5)
5165 if scanner.nexttok() != "IHREAL":
5168 w2.i = int(scanner.real-0.5)
5170 if game.quadrant.j>w1.i:
5174 if game.quadrant.i>w1.j:
5178 if not w1.valid_quadrant() or not w2.valid_sector():
5181 dist = math.sqrt((w1.j-game.quadrant.j+(w2.j-game.sector.j)/(QUADSIZE*1.0))**2+
5182 (w1.i-game.quadrant.i+(w2.i-game.sector.i)/(QUADSIZE*1.0))**2)
5185 prout(_("Answer \"no\" if you don't know the value:"))
5188 proutn(_("Time or arrival date? "))
5189 if scanner.nexttok()=="IHREAL":
5190 ttime = scanner.real
5191 if ttime > game.state.date:
5192 ttime -= game.state.date # Actually a star date
5193 twarp=(math.floor(math.sqrt((10.0*dist)/ttime)*10.0)+1.0)/10.0
5194 if ttime <= 1e-10 or twarp > 10:
5195 prout(_("We'll never make it, sir."))
5202 proutn(_("Warp factor? "))
5203 if scanner.nexttok()== "IHREAL":
5205 twarp = scanner.real
5206 if twarp<1.0 or twarp > 10.0:
5210 prout(_("Captain, certainly you can give me one of these."))
5213 ttime = (10.0*dist)/twarp**2
5214 tpower = dist*twarp*twarp*twarp*(game.shldup+1)
5215 if tpower >= game.energy:
5216 prout(_("Insufficient energy, sir."))
5217 if not game.shldup or tpower > game.energy*2.0:
5220 proutn(_("New warp factor to try? "))
5221 if scanner.nexttok() == "IHREAL":
5223 twarp = scanner.real
5224 if twarp<1.0 or twarp > 10.0:
5232 prout(_("But if you lower your shields,"))
5233 proutn(_("remaining"))
5236 proutn(_("Remaining"))
5237 prout(_(" energy will be %.2f.") % (game.energy-tpower))
5239 prout(_("And we will arrive at stardate %.2f.") % (game.state.date+ttime))
5241 prout(_("Any warp speed is adequate."))
5243 prout(_("Minimum warp needed is %.2f,") % (twarp))
5244 prout(_("and we will arrive at stardate %.2f.") % (game.state.date+ttime))
5245 if game.state.remtime < ttime:
5246 prout(_("Unfortunately, the Federation will be destroyed by then."))
5248 prout(_("You'll be taking risks at that speed, Captain"))
5249 if (game.isatb==1 and game.state.kscmdr == w1 and \
5250 scheduled(FSCDBAS)< ttime+game.state.date) or \
5251 (scheduled(FCDBAS)<ttime+game.state.date and game.battle == w1):
5252 prout(_("The starbase there will be destroyed by then."))
5253 proutn(_("New warp factor to try? "))
5254 if scanner.nexttok() == "IHREAL":
5256 twarp = scanner.real
5257 if twarp<1.0 or twarp > 10.0:
5265 # Code from setup.c begins here
5268 "Issue a historically correct banner."
5270 prout(_("-SUPER- STAR TREK"))
5272 # From the FORTRAN original
5273 # prout(_("Latest update-21 Sept 78"))
5279 scanner.push("emsave.trk")
5280 key = scanner.nexttok()
5282 proutn(_("File name: "))
5283 key = scanner.nexttok()
5284 if key != "IHALPHA":
5287 if '.' not in scanner.token:
5288 scanner.token += ".trk"
5290 fp = open(scanner.token, "wb")
5292 prout(_("Can't freeze game as file %s") % scanner.token)
5294 pickle.dump(game, fp)
5299 "Retrieve saved game."
5302 key = scanner.nexttok()
5304 proutn(_("File name: "))
5305 key = scanner.nexttok()
5306 if key != "IHALPHA":
5309 if '.' not in scanner.token:
5310 scanner.token += ".trk"
5312 fp = open(scanner.token, "rb")
5314 prout(_("Can't thaw game in %s") % scanner.token)
5316 game = pickle.load(fp)
5321 # I used <http://www.memory-alpha.org> to find planets
5322 # with references in ST:TOS. Earth and the Alpha Centauri
5323 # Colony have been omitted.
5325 # Some planets marked Class G and P here will be displayed as class M
5326 # because of the way planets are generated. This is a known bug.
5329 _("Andoria (Fesoan)"), # several episodes
5330 _("Tellar Prime (Miracht)"), # TOS: "Journey to Babel"
5331 _("Vulcan (T'Khasi)"), # many episodes
5332 _("Medusa"), # TOS: "Is There in Truth No Beauty?"
5333 _("Argelius II (Nelphia)"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5334 _("Ardana"), # TOS: "The Cloud Minders"
5335 _("Catulla (Cendo-Prae)"), # TOS: "The Way to Eden"
5336 _("Gideon"), # TOS: "The Mark of Gideon"
5337 _("Aldebaran III"), # TOS: "The Deadly Years"
5338 _("Alpha Majoris I"), # TOS: "Wolf in the Fold"
5339 _("Altair IV"), # TOS: "Amok Time
5340 _("Ariannus"), # TOS: "Let That Be Your Last Battlefield"
5341 _("Benecia"), # TOS: "The Conscience of the King"
5342 _("Beta Niobe I (Sarpeidon)"), # TOS: "All Our Yesterdays"
5343 _("Alpha Carinae II"), # TOS: "The Ultimate Computer"
5344 _("Capella IV (Kohath)"), # TOS: "Friday's Child" (Class G)
5345 _("Daran V"), # TOS: "For the World is Hollow and I Have Touched the Sky"
5346 _("Deneb II"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5347 _("Eminiar VII"), # TOS: "A Taste of Armageddon"
5348 _("Gamma Canaris IV"), # TOS: "Metamorphosis"
5349 _("Gamma Tranguli VI (Vaalel)"), # TOS: "The Apple"
5350 _("Ingraham B"), # TOS: "Operation: Annihilate"
5351 _("Janus IV"), # TOS: "The Devil in the Dark"
5352 _("Makus III"), # TOS: "The Galileo Seven"
5353 _("Marcos XII"), # TOS: "And the Children Shall Lead",
5354 _("Omega IV"), # TOS: "The Omega Glory"
5355 _("Regulus V"), # TOS: "Amok Time
5356 _("Deneva"), # TOS: "Operation -- Annihilate!"
5357 # Worlds from BSD Trek
5358 _("Rigel II"), # TOS: "Shore Leave" ("III" in BSD)
5359 _("Beta III"), # TOS: "The Return of the Archons"
5360 _("Triacus"), # TOS: "And the Children Shall Lead",
5361 _("Exo III"), # TOS: "What Are Little Girls Made Of?" (Class P)
5363 # _("Hansen's Planet"), # TOS: "The Galileo Seven"
5364 # _("Taurus IV"), # TOS: "The Galileo Seven" (class G)
5365 # _("Antos IV (Doraphane)"), # TOS: "Whom Gods Destroy", "Who Mourns for Adonais?"
5366 # _("Izar"), # TOS: "Whom Gods Destroy"
5367 # _("Tiburon"), # TOS: "The Way to Eden"
5368 # _("Merak II"), # TOS: "The Cloud Minders"
5369 # _("Coridan (Desotriana)"), # TOS: "Journey to Babel"
5370 # _("Iotia"), # TOS: "A Piece of the Action"
5374 _("S. R. Sensors"), \
5375 _("L. R. Sensors"), \
5377 _("Photon Tubes"), \
5378 _("Life Support"), \
5379 _("Warp Engines"), \
5380 _("Impulse Engines"), \
5382 _("Subspace Radio"), \
5383 _("Shuttle Craft"), \
5385 _("Navigation System"), \
5387 _("Shield Control"), \
5393 "Prepare to play, set up cosmos."
5395 # Decide how many of everything
5397 return # frozen game
5398 # Prepare the Enterprise
5399 game.alldone = game.gamewon = game.shldchg = game.shldup = False
5401 game.state.crew = FULLCREW
5402 game.energy = game.inenrg = 5000.0
5403 game.shield = game.inshld = 2500.0
5406 game.quadrant = randplace(GALSIZE)
5407 game.sector = randplace(QUADSIZE)
5408 game.torps = game.intorps = 10
5409 game.nprobes = randrange(2, 5)
5411 for i in range(NDEVICES):
5412 game.damage[i] = 0.0
5413 # Set up assorted game parameters
5414 game.battle = Coord()
5415 game.state.date = game.indate = 100.0 * randreal(20, 51)
5416 game.nkinks = game.nhelp = game.casual = game.abandoned = 0
5417 game.iscate = game.resting = game.imine = game.icrystl = game.icraft = False
5418 game.isatb = game.state.nplankl = 0
5419 game.state.starkl = game.state.basekl = game.state.nworldkl = 0
5420 game.iscraft = "onship"
5425 game.state.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
5427 game.state.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
5429 game.state.planets = [] # Planet information
5430 game.state.baseq = [] # Base quadrant coordinates
5431 game.state.kcmdr = [] # Commander quadrant coordinates
5432 game.statekscmdr = Coord() # Supercommander quadrant coordinates
5434 # Starchart is functional but we've never seen it
5435 game.lastchart = FOREVER
5436 # Put stars in the galaxy
5438 for i in range(GALSIZE):
5439 for j in range(GALSIZE):
5440 # Can't have more stars per quadrant than fit in one decimal digit,
5441 # if we do the chart representation will break.
5442 k = randrange(1, min(10, QUADSIZE**2/10))
5444 game.state.galaxy[i][j].stars = k
5445 # Locate star bases in galaxy
5447 prout("=== Allocating %d bases" % game.inbase)
5448 for i in range(game.inbase):
5451 w = randplace(GALSIZE)
5452 if not game.state.galaxy[w.i][w.j].starbase:
5455 # C version: for (j = i-1; j > 0; j--)
5456 # so it did them in the opposite order.
5457 for j in range(1, i):
5458 # Improved placement algorithm to spread out bases
5459 distq = (w - game.state.baseq[j]).distance()
5460 if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75):
5463 prout("=== Abandoning base #%d at %s" % (i, w))
5465 elif distq < 6.0 * (BASEMAX+1-game.inbase):
5467 prout("=== Saving base #%d, close to #%d" % (i, j))
5471 prout("=== Placing base #%d in quadrant %s" % (i, w))
5472 game.state.baseq.append(w)
5473 game.state.galaxy[w.i][w.j].starbase = game.state.chart[w.i][w.j].starbase = True
5474 # Position ordinary Klingon Battle Cruisers
5476 klumper = 0.25*game.skill*(9.0-game.length)+1.0
5477 if klumper > MAXKLQUAD:
5481 klump = (1.0 - r*r)*klumper
5486 w = randplace(GALSIZE)
5487 if not game.state.galaxy[w.i][w.j].supernova and \
5488 game.state.galaxy[w.i][w.j].klingons + klump <= MAXKLQUAD:
5490 game.state.galaxy[w.i][w.j].klingons += int(klump)
5493 # Position Klingon Commander Ships
5494 for i in range(game.incom):
5496 w = randplace(GALSIZE)
5497 if not welcoming(w) or w in game.state.kcmdr:
5499 if (game.state.galaxy[w.i][w.j].klingons or withprob(0.25)):
5501 game.state.galaxy[w.i][w.j].klingons += 1
5502 game.state.kcmdr.append(w)
5503 # Locate planets in galaxy
5504 for i in range(game.inplan):
5506 w = randplace(GALSIZE)
5507 if game.state.galaxy[w.i][w.j].planet == None:
5511 new.crystals = "absent"
5512 if (game.options & OPTION_WORLDS) and i < NINHAB:
5513 new.pclass = "M" # All inhabited planets are class M
5514 new.crystals = "absent"
5516 new.name = systnames[i]
5517 new.inhabited = True
5519 new.pclass = ("M", "N", "O")[randrange(0, 3)]
5521 new.crystals = "present"
5522 new.known = "unknown"
5523 new.inhabited = False
5524 game.state.galaxy[w.i][w.j].planet = new
5525 game.state.planets.append(new)
5527 for i in range(game.state.nromrem):
5528 w = randplace(GALSIZE)
5529 game.state.galaxy[w.i][w.j].romulans += 1
5530 # Place the Super-Commander if needed
5531 if game.state.nscrem > 0:
5533 w = randplace(GALSIZE)
5536 game.state.kscmdr = w
5537 game.state.galaxy[w.i][w.j].klingons += 1
5538 # Initialize times for extraneous events
5539 schedule(FSNOVA, expran(0.5 * game.intime))
5540 schedule(FTBEAM, expran(1.5 * (game.intime / len(game.state.kcmdr))))
5541 schedule(FSNAP, randreal(1.0, 2.0)) # Force an early snapshot
5542 schedule(FBATTAK, expran(0.3*game.intime))
5544 if game.state.nscrem:
5545 schedule(FSCMOVE, 0.2777)
5550 if (game.options & OPTION_WORLDS) and game.skill >= SKILL_GOOD:
5551 schedule(FDISTR, expran(1.0 + game.intime))
5556 # Place thing (in tournament game, we don't want one!)
5557 # New in SST2K: never place the Thing near a starbase.
5558 # This makes sense and avoids a special case in the old code.
5560 if game.tourn is None:
5562 thing = randplace(GALSIZE)
5563 if thing not in game.state.baseq:
5566 game.state.snap = False
5567 if game.skill == SKILL_NOVICE:
5568 prout(_("It is stardate %d. The Federation is being attacked by") % int(game.state.date))
5569 prout(_("a deadly Klingon invasion force. As captain of the United"))
5570 prout(_("Starship U.S.S. Enterprise, it is your mission to seek out"))
5571 prout(_("and destroy this invasion force of %d battle cruisers.") % ((game.inkling + game.incom + game.inscom)))
5572 prout(_("You have an initial allotment of %d stardates to complete") % int(game.intime))
5573 prout(_("your mission. As you proceed you may be given more time."))
5575 prout(_("You will have %d supporting starbases.") % (game.inbase))
5576 proutn(_("Starbase locations- "))
5578 prout(_("Stardate %d.") % int(game.state.date))
5580 prout(_("%d Klingons.") % (game.inkling + game.incom + game.inscom))
5581 prout(_("An unknown number of Romulans."))
5582 if game.state.nscrem:
5583 prout(_("And one (GULP) Super-Commander."))
5584 prout(_("%d stardates.") % int(game.intime))
5585 proutn(_("%d starbases in ") % game.inbase)
5586 for i in range(game.inbase):
5587 proutn(repr(game.state.baseq[i]))
5590 proutn(_("The Enterprise is currently in Quadrant %s") % game.quadrant)
5591 proutn(_(" Sector %s") % game.sector)
5593 prout(_("Good Luck!"))
5594 if game.state.nscrem:
5595 prout(_(" YOU'LL NEED IT."))
5598 setwnd(message_window)
5600 if len(game.enemies) - (thing == game.quadrant) - (game.tholian != None):
5602 if game.neutz: # bad luck to start in a Romulan Neutral Zone
5603 attack(torps_ok=False)
5606 "Choose your game type."
5608 game.tourn = game.length = 0
5610 game.skill = SKILL_NONE
5612 # if not scanner.inqueue: # Can start with command line options
5613 proutn(_("Would you like a regular, tournament, or saved game? "))
5615 if scanner.sees("tournament"):
5616 while scanner.nexttok() == "IHEOL":
5617 proutn(_("Type in tournament number-"))
5618 if scanner.real == 0:
5620 continue # We don't want a blank entry
5621 game.tourn = int(round(scanner.real))
5622 random.seed(scanner.real)
5624 logfp.write("# random.seed(%d)\n" % scanner.real)
5626 if scanner.sees("saved") or scanner.sees("frozen"):
5630 if game.passwd == None:
5632 if not game.alldone:
5633 game.thawed = True # No plaque if not finished
5637 if scanner.sees("regular"):
5639 proutn(_("What is \"%s\"? ") % scanner.token)
5641 while game.length==0 or game.skill==SKILL_NONE:
5642 if scanner.nexttok() == "IHALPHA":
5643 if scanner.sees("short"):
5645 elif scanner.sees("medium"):
5647 elif scanner.sees("long"):
5649 elif scanner.sees("novice"):
5650 game.skill = SKILL_NOVICE
5651 elif scanner.sees("fair"):
5652 game.skill = SKILL_FAIR
5653 elif scanner.sees("good"):
5654 game.skill = SKILL_GOOD
5655 elif scanner.sees("expert"):
5656 game.skill = SKILL_EXPERT
5657 elif scanner.sees("emeritus"):
5658 game.skill = SKILL_EMERITUS
5660 proutn(_("What is \""))
5661 proutn(scanner.token)
5666 proutn(_("Would you like a Short, Medium, or Long game? "))
5667 elif game.skill == SKILL_NONE:
5668 proutn(_("Are you a Novice, Fair, Good, Expert, or Emeritus player? "))
5669 # Choose game options -- added by ESR for SST2K
5670 if scanner.nexttok() != "IHALPHA":
5672 proutn(_("Choose your game style (plain, almy, fancy or just press enter): "))
5674 if scanner.sees("plain"):
5675 # Approximates the UT FORTRAN version.
5676 game.options &=~ (OPTION_THOLIAN | OPTION_PLANETS | OPTION_THINGY | OPTION_PROBE | OPTION_RAMMING | OPTION_MVBADDY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
5677 game.options |= OPTION_PLAIN
5678 elif scanner.sees("almy"):
5679 # Approximates Tom Almy's version.
5680 game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
5681 game.options |= OPTION_ALMY
5682 elif scanner.sees("fancy") or scanner.sees("\n"):
5684 elif len(scanner.token):
5685 proutn(_("What is \"%s\"?") % scanner.token)
5686 game.options &=~ OPTION_COLOR
5688 if game.passwd == "debug":
5690 prout("=== Debug mode enabled.")
5691 # Use parameters to generate initial values of things
5692 game.damfac = 0.5 * game.skill
5693 game.inbase = randrange(BASEMIN, BASEMAX+1)
5695 if game.options & OPTION_PLANETS:
5696 game.inplan += randrange(MAXUNINHAB/2, MAXUNINHAB+1)
5697 if game.options & OPTION_WORLDS:
5698 game.inplan += int(NINHAB)
5699 game.state.nromrem = game.inrom = randrange(2 *game.skill)
5700 game.state.nscrem = game.inscom = (game.skill > SKILL_FAIR)
5701 game.state.remtime = 7.0 * game.length
5702 game.intime = game.state.remtime
5703 game.state.remkl = game.inkling = 2.0*game.intime*((game.skill+1 - 2*randreal())*game.skill*0.1+.15)
5704 game.incom = min(MINCMDR, int(game.skill + 0.0625*game.inkling*randreal()))
5705 game.state.remres = (game.inkling+4*game.incom)*game.intime
5706 game.inresor = game.state.remres
5707 if game.inkling > 50:
5708 game.state.inbase += 1
5711 def dropin(iquad=None):
5712 "Drop a feature on a random dot in the current quadrant."
5714 w = randplace(QUADSIZE)
5715 if game.quad[w.i][w.j] == '.':
5717 if iquad is not None:
5718 game.quad[w.i][w.j] = iquad
5722 "Update our alert status."
5723 game.condition = "green"
5724 if game.energy < 1000.0:
5725 game.condition = "yellow"
5726 if game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons or game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans:
5727 game.condition = "red"
5729 game.condition="dead"
5732 "Drop new Klingon into current quadrant."
5733 return Enemy('K', loc=dropin(), power=randreal(300,450)+25.0*game.skill)
5736 "Sort enemies by distance so 'nearest' is meaningful."
5737 game.enemies.sort(key=lambda x: x.kdist)
5740 "Set up a new state of quadrant, for when we enter or re-enter it."
5743 game.neutz = game.inorbit = game.landed = False
5744 game.ientesc = game.iseenit = False
5745 # Create a blank quadrant
5746 game.quad = fill2d(QUADSIZE, lambda i, j: '.')
5748 # Attempt to escape Super-commander, so tbeam back!
5751 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
5752 # cope with supernova
5755 game.klhere = q.klingons
5756 game.irhere = q.romulans
5758 game.quad[game.sector.i][game.sector.j] = game.ship
5761 # Position ordinary Klingons
5762 for i in range(game.klhere):
5764 # If we need a commander, promote a Klingon
5765 for cmdr in game.state.kcmdr:
5766 if cmdr == game.quadrant:
5767 e = game.enemies[game.klhere-1]
5768 game.quad[e.location.i][e.location.j] = 'C'
5769 e.power = randreal(950,1350) + 50.0*game.skill
5771 # If we need a super-commander, promote a Klingon
5772 if game.quadrant == game.state.kscmdr:
5774 game.quad[e.location.i][e.location.j] = 'S'
5775 e.power = randreal(1175.0, 1575.0) + 125.0*game.skill
5776 game.iscate = (game.state.remkl > 1)
5777 # Put in Romulans if needed
5778 for i in range(q.romulans):
5779 Enemy('R', loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill)
5780 # If quadrant needs a starbase, put it in
5782 game.base = dropin('B')
5783 # If quadrant needs a planet, put it in
5785 game.iplnet = q.planet
5786 if not q.planet.inhabited:
5787 game.plnet = dropin('P')
5789 game.plnet = dropin('@')
5790 # Check for condition
5793 if game.irhere > 0 and game.klhere == 0:
5795 if not damaged(DRADIO):
5797 prout(_("LT. Uhura- \"Captain, an urgent message."))
5798 prout(_(" I'll put it on audio.\" CLICK"))
5800 prout(_("INTRUDER! YOU HAVE VIOLATED THE ROMULAN NEUTRAL ZONE."))
5801 prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!"))
5802 # Put in THING if needed
5803 if thing == game.quadrant:
5804 Enemy(etype='?', loc=dropin(),
5805 power=randreal(6000,6500.0)+250.0*game.skill)
5806 if not damaged(DSRSENS):
5808 prout(_("Mr. Spock- \"Captain, this is most unusual."))
5809 prout(_(" Please examine your short-range scan.\""))
5810 # Decide if quadrant needs a Tholian; lighten up if skill is low
5811 if game.options & OPTION_THOLIAN:
5812 if (game.skill < SKILL_GOOD and withprob(0.02)) or \
5813 (game.skill == SKILL_GOOD and withprob(0.05)) or \
5814 (game.skill > SKILL_GOOD and withprob(0.08)):
5817 w.i = withprob(0.5) * (QUADSIZE-1)
5818 w.j = withprob(0.5) * (QUADSIZE-1)
5819 if game.quad[w.i][w.j] == '.':
5821 game.tholian = Enemy(etype='T', loc=w,
5822 power=randrange(100, 500) + 25.0*game.skill)
5823 # Reserve unoccupied corners
5824 if game.quad[0][0]=='.':
5825 game.quad[0][0] = 'X'
5826 if game.quad[0][QUADSIZE-1]=='.':
5827 game.quad[0][QUADSIZE-1] = 'X'
5828 if game.quad[QUADSIZE-1][0]=='.':
5829 game.quad[QUADSIZE-1][0] = 'X'
5830 if game.quad[QUADSIZE-1][QUADSIZE-1]=='.':
5831 game.quad[QUADSIZE-1][QUADSIZE-1] = 'X'
5833 # And finally the stars
5834 for i in range(q.stars):
5836 # Put in a few black holes
5837 for i in range(1, 3+1):
5840 # Take out X's in corners if Tholian present
5842 if game.quad[0][0]=='X':
5843 game.quad[0][0] = '.'
5844 if game.quad[0][QUADSIZE-1]=='X':
5845 game.quad[0][QUADSIZE-1] = '.'
5846 if game.quad[QUADSIZE-1][0]=='X':
5847 game.quad[QUADSIZE-1][0] = '.'
5848 if game.quad[QUADSIZE-1][QUADSIZE-1]=='X':
5849 game.quad[QUADSIZE-1][QUADSIZE-1] = '.'
5852 "Set the self-destruct password."
5853 if game.options & OPTION_PLAIN:
5856 proutn(_("Please type in a secret password- "))
5858 game.passwd = scanner.token
5859 if game.passwd != None:
5863 game.passwd += chr(ord('a')+randrange(26))
5864 game.passwd += chr(ord('a')+randrange(26))
5865 game.passwd += chr(ord('a')+randrange(26))
5867 # Code from sst.c begins here
5870 ("SRSCAN", OPTION_TTY),
5871 ("STATUS", OPTION_TTY),
5872 ("REQUEST", OPTION_TTY),
5873 ("LRSCAN", OPTION_TTY),
5886 ("SENSORS", OPTION_PLANETS),
5887 ("ORBIT", OPTION_PLANETS),
5888 ("TRANSPORT", OPTION_PLANETS),
5889 ("MINE", OPTION_PLANETS),
5890 ("CRYSTALS", OPTION_PLANETS),
5891 ("SHUTTLE", OPTION_PLANETS),
5892 ("PLANETS", OPTION_PLANETS),
5897 ("PROBE", OPTION_PROBE),
5899 ("FREEZE", 0), # Synonym for SAVE
5905 ("SOS", 0), # Synonym for MAYDAY
5906 ("CALL", 0), # Synonym for MAYDAY
5913 "Generate a list of legal commands."
5914 prout(_("LEGAL COMMANDS ARE:"))
5916 for (key, opt) in commands:
5917 if not opt or (opt & game.options):
5918 proutn("%-12s " % key)
5920 if emitted % 5 == 4:
5925 "Browse on-line help."
5926 key = scanner.nexttok()
5929 setwnd(prompt_window)
5930 proutn(_("Help on what command? "))
5931 key = scanner.nexttok()
5932 setwnd(message_window)
5935 cmds = [x[0] for x in commands]
5936 if scanner.token.upper() in cmds or scanner.token.upper() == "ABBREV":
5943 cmd = scanner.token.upper()
5944 for directory in docpath:
5946 fp = open(os.path.join(directory, "sst.doc"), "r")
5951 prout(_("Spock- \"Captain, that information is missing from the"))
5952 prout(_(" computer. You need to find sst.doc and put it somewhere"))
5953 proutn(_(" in these directories: %s") % ":".join(docpath))
5955 # This used to continue: "You need to find SST.DOC and put
5956 # it in the current directory."
5959 linebuf = fp.readline()
5961 prout(_("Spock- \"Captain, there is no information on that command.\""))
5964 if linebuf[0] == '%' and linebuf[1] == '%' and linebuf[2] == ' ':
5965 linebuf = linebuf[3:].strip()
5966 if cmd.upper() == linebuf:
5969 prout(_("Spock- \"Captain, I've found the following information:\""))
5972 linebuf = fp.readline()
5973 if "******" in linebuf:
5979 "Command-interpretation loop."
5980 while True: # command loop
5982 while True: # get a command
5984 game.optime = game.justin = False
5986 setwnd(prompt_window)
5989 if scanner.nexttok() == "IHEOL":
5990 if game.options & OPTION_CURSES:
5993 elif scanner.token == "":
5997 setwnd(message_window)
5999 abandon_passed = False
6000 for (cmd, opt) in commands:
6001 # commands after ABANDON cannot be abbreviated
6002 if cmd == "ABANDON":
6003 abandon_passed = True
6004 if cmd == scanner.token.upper() or (not abandon_passed \
6005 and cmd.startswith(scanner.token.upper())):
6010 elif opt and not (opt & game.options):
6014 if cmd == "SRSCAN": # srscan
6016 elif cmd == "STATUS": # status
6018 elif cmd == "REQUEST": # status request
6020 elif cmd == "LRSCAN": # long range scan
6021 lrscan(silent=False)
6022 elif cmd == "PHASERS": # phasers
6026 elif cmd in ("TORPEDO", "PHOTONS"): # photon torpedos
6030 elif cmd == "MOVE": # move under warp
6031 warp(wcourse=None, involuntary=False)
6032 elif cmd == "SHIELDS": # shields
6033 doshield(shraise=False)
6036 game.shldchg = False
6037 elif cmd == "DOCK": # dock at starbase
6040 attack(torps_ok=False)
6041 elif cmd == "DAMAGES": # damage reports
6043 elif cmd == "CHART": # chart
6045 elif cmd == "IMPULSE": # impulse
6047 elif cmd == "REST": # rest
6051 elif cmd == "WARP": # warp
6053 elif cmd == "SCORE": # score
6055 elif cmd == "SENSORS": # sensors
6057 elif cmd == "ORBIT": # orbit
6061 elif cmd == "TRANSPORT": # transport "beam"
6063 elif cmd == "MINE": # mine
6067 elif cmd == "CRYSTALS": # crystals
6071 elif cmd == "SHUTTLE": # shuttle
6075 elif cmd == "PLANETS": # Planet list
6077 elif cmd == "REPORT": # Game Report
6079 elif cmd == "COMPUTER": # use COMPUTER!
6081 elif cmd == "COMMANDS":
6083 elif cmd == "EMEXIT": # Emergency exit
6084 clrscr() # Hide screen
6085 freeze(True) # forced save
6086 raise SystemExit(1) # And quick exit
6087 elif cmd == "PROBE":
6088 probe() # Launch probe
6091 elif cmd == "ABANDON": # Abandon Ship
6093 elif cmd == "DESTRUCT": # Self Destruct
6095 elif cmd == "SAVE": # Save Game
6098 if game.skill > SKILL_GOOD:
6099 prout(_("WARNING--Saved games produce no plaques!"))
6100 elif cmd == "DEATHRAY": # Try a desparation measure
6104 elif cmd == "DEBUGCMD": # What do we want for debug???
6106 elif cmd == "MAYDAY": # Call for help
6111 game.alldone = True # quit the game
6116 break # Game has ended
6117 if game.optime != 0.0:
6120 break # Events did us in
6121 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6124 if hitme and not game.justin:
6125 attack(torps_ok=True)
6128 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6139 "Emit the name of an enemy or feature."
6140 if type == 'R': s = _("Romulan")
6141 elif type == 'K': s = _("Klingon")
6142 elif type == 'C': s = _("Commander")
6143 elif type == 'S': s = _("Super-commander")
6144 elif type == '*': s = _("Star")
6145 elif type == 'P': s = _("Planet")
6146 elif type == 'B': s = _("Starbase")
6147 elif type == ' ': s = _("Black hole")
6148 elif type == 'T': s = _("Tholian")
6149 elif type == '#': s = _("Tholian web")
6150 elif type == '?': s = _("Stranger")
6151 elif type == '@': s = _("Inhabited World")
6152 else: s = "Unknown??"
6155 def crmena(stars, enemy, loctype, w):
6156 "Emit the name of an enemy and his location."
6160 buf += cramen(enemy) + _(" at ")
6161 if loctype == "quadrant":
6162 buf += _("Quadrant ")
6163 elif loctype == "sector":
6165 return buf + repr(w)
6168 "Emit our ship name."
6169 return{'E':_("Enterprise"),'F':_("Faerie Queene")}.get(game.ship,"Ship???")
6172 "Emit a line of stars"
6173 prouts("******************************************************")
6177 return -avrage*math.log(1e-7 + randreal())
6179 def randplace(size):
6180 "Choose a random location."
6182 w.i = randrange(size)
6183 w.j = randrange(size)
6193 # Get a token from the user
6196 # Fill the token quue if nothing here
6197 while not self.inqueue:
6199 if curwnd==prompt_window:
6201 setwnd(message_window)
6208 self.inqueue = line.lstrip().split() + ["\n"]
6209 # From here on in it's all looking at the queue
6210 self.token = self.inqueue.pop(0)
6211 if self.token == "\n":
6215 self.real = float(self.token)
6216 self.type = "IHREAL"
6221 self.token = self.token.lower()
6222 self.type = "IHALPHA"
6225 def append(self, tok):
6226 self.inqueue.append(tok)
6227 def push(self, tok):
6228 self.inqueue.insert(0, tok)
6232 # Demand input for next scan
6234 self.real = self.token = None
6236 # compares s to item and returns true if it matches to the length of s
6237 return s.startswith(self.token)
6239 # Round token value to nearest integer
6240 return int(round(scanner.real))
6244 if scanner.type != "IHREAL":
6247 s.i = scanner.int()-1
6249 if scanner.type != "IHREAL":
6252 s.j = scanner.int()-1
6255 return "<sstcanner: token=%s, type=%s, queue=%s>" % (scanner.token, scanner.type, scanner.inqueue)
6258 "Yes-or-no confirmation."
6262 if scanner.token == 'y':
6264 if scanner.token == 'n':
6267 proutn(_("Please answer with \"y\" or \"n\": "))
6270 "Complain about unparseable input."
6273 prout(_("Beg your pardon, Captain?"))
6276 "Access to the internals for debugging."
6277 proutn("Reset levels? ")
6279 if game.energy < game.inenrg:
6280 game.energy = game.inenrg
6281 game.shield = game.inshld
6282 game.torps = game.intorps
6283 game.lsupres = game.inlsr
6284 proutn("Reset damage? ")
6286 for i in range(NDEVICES):
6287 if game.damage[i] > 0.0:
6288 game.damage[i] = 0.0
6289 proutn("Toggle debug flag? ")
6291 game.idebug = not game.idebug
6293 prout("Debug output ON")
6295 prout("Debug output OFF")
6296 proutn("Cause selective damage? ")
6298 for i in range(NDEVICES):
6299 proutn("Kill %s?" % device[i])
6301 key = scanner.nexttok()
6302 if key == "IHALPHA" and scanner.sees("y"):
6303 game.damage[i] = 10.0
6304 proutn("Examine/change events? ")
6309 FSNOVA: "Supernova ",
6312 FBATTAK: "Base Attack ",
6313 FCDBAS: "Base Destroy ",
6314 FSCMOVE: "SC Move ",
6315 FSCDBAS: "SC Base Destroy ",
6316 FDSPROB: "Probe Move ",
6317 FDISTR: "Distress Call ",
6318 FENSLV: "Enslavement ",
6319 FREPRO: "Klingon Build ",
6321 for i in range(1, NEVENTS):
6324 proutn("%.2f" % (scheduled(i)-game.state.date))
6325 if i == FENSLV or i == FREPRO:
6327 proutn(" in %s" % ev.quadrant)
6332 key = scanner.nexttok()
6336 elif key == "IHREAL":
6337 ev = schedule(i, scanner.real)
6338 if i == FENSLV or i == FREPRO:
6340 proutn("In quadrant- ")
6341 key = scanner.nexttok()
6342 # "IHEOL" says to leave coordinates as they are
6345 prout("Event %d canceled, no x coordinate." % (i))
6348 w.i = int(round(scanner.real))
6349 key = scanner.nexttok()
6351 prout("Event %d canceled, no y coordinate." % (i))
6354 w.j = int(round(scanner.real))
6357 proutn("Induce supernova here? ")
6359 game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova = True
6362 if __name__ == '__main__':
6363 import getopt, socket
6365 global line, thing, game
6369 game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY)
6370 if os.getenv("TERM"):
6371 game.options |= OPTION_CURSES
6373 game.options |= OPTION_TTY
6374 seed = int(time.time())
6375 (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:txV")
6377 for (switch, val) in options:
6380 replayfp = open(val, "r")
6382 sys.stderr.write("sst: can't open replay file %s\n" % val)
6385 line = replayfp.readline().strip()
6386 (leader, __, seed) = line.split()
6388 sys.stderr.write("sst2k: seed set to %s\n" % seed)
6389 line = replayfp.readline().strip()
6390 arguments += line.split()[2:]
6393 sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
6395 game.options |= OPTION_TTY
6396 game.options &=~ OPTION_CURSES
6397 elif switch == '-s':
6399 elif switch == '-t':
6400 game.options |= OPTION_TTY
6401 game.options &=~ OPTION_CURSES
6402 elif switch == '-x':
6404 elif switch == '-V':
6405 print("SST2K", version)
6408 sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n")
6410 # where to save the input in case of bugs
6411 if "TMPDIR" in os.environ:
6412 tmpdir = os.environ['TMPDIR']
6416 logfp = open(os.path.join(tmpdir, "sst-input.log"), "w")
6418 sys.stderr.write("sst: warning, can't open logfile\n")
6421 logfp.write("# seed %s\n" % seed)
6422 logfp.write("# options %s\n" % " ".join(arguments))
6423 logfp.write("# SST2K version %s\n" % version)
6424 logfp.write("# recorded by %s@%s on %s\n" % \
6425 (getpass.getuser(),socket.gethostname(),time.ctime()))
6427 scanner = sstscanner()
6428 for arg in arguments:
6432 while True: # Play a game
6433 setwnd(fullscreen_window)
6439 game.alldone = False
6447 if game.tourn and game.alldone:
6448 proutn(_("Do you want your score recorded?"))
6454 proutn(_("Do you want to play again? "))
6458 prout(_("May the Great Bird of the Galaxy roost upon your home planet."))
6462 except KeyboardInterrupt: