3 sst.py -- Super Star Trek 2K
5 SST2K is a Python translation of a C translation of a FORTRAN
6 original dating back to 1973. Beautiful Python it is not, but it
7 works. Translation by Eric S. Raymond; original game by David Matuszek
8 and Paul Reynolds, with modifications by Don Smith, Tom Almy,
9 Stas Sergeev, and Eric S. Raymond.
11 See the doc/HACKING file in the distribution for designers notes and advice
12 on how to modify (and how not to modify!) this code.
14 import os, sys, math, curses, time, pickle, random, copy, gettext, getpass
15 import getopt, socket, locale
17 # This import only works on Unixes. The intention is to enable
18 # Ctrl-P, Ctrl-N, and friends in Cmd.
26 docpath = (".", "../doc", "/usr/share/doc/sst")
29 return gettext.gettext(st)
31 GALSIZE = 8 # Galaxy size in quadrants
32 NINHAB = (GALSIZE * GALSIZE // 2) # Number of inhabited worlds
33 MAXUNINHAB = 10 # Maximum uninhabited worlds
34 QUADSIZE = 10 # Quadrant size in sectors
35 BASEMIN = 2 # Minimum starbases
36 BASEMAX = (GALSIZE * GALSIZE // 12) # Maximum starbases
37 MAXKLGAME = 127 # Maximum Klingons per game
38 MAXKLQUAD = 9 # Maximum Klingons per quadrant
39 FULLCREW = 428 # Crew size. BSD Trek was 387, that's wrong
40 FOREVER = 1e30 # Time for the indefinite future
41 MAXBURST = 3 # Max # of torps you can launch in one turn
42 MINCMDR = 10 # Minimum number of Klingon commanders
43 DOCKFAC = 0.25 # Repair faster when docked
44 PHASEFAC = 2.0 # Unclear what this is, it was in the C version
64 class TrekError(Exception):
67 class JumpOut(Exception):
71 def __init__(self, x=None, y=None):
74 def valid_quadrant(self):
75 return self.i >= 0 and self.i < GALSIZE and self.j >= 0 and self.j < GALSIZE
76 def valid_sector(self):
77 return self.i >= 0 and self.i < QUADSIZE and self.j >= 0 and self.j < QUADSIZE
79 self.i = self.j = None
81 return self.i != None and self.j != None
82 def __eq__(self, other):
83 return other != None and self.i == other.i and self.j == other.j
84 def __ne__(self, other):
85 return other is None or self.i != other.i or self.j != other.j
86 def __add__(self, other):
87 return Coord(self.i+other.i, self.j+other.j)
88 def __sub__(self, other):
89 return Coord(self.i-other.i, self.j-other.j)
90 def __mul__(self, other):
91 return Coord(self.i*other, self.j*other)
92 def __rmul__(self, other):
93 return Coord(self.i*other, self.j*other)
94 def __div__(self, other):
95 return Coord(self.i/other, self.j/other)
96 def __mod__(self, other):
97 return Coord(self.i % other, self.j % other)
98 def __rdiv__(self, other):
99 return Coord(self.i/other, self.j/other)
100 def roundtogrid(self):
101 return Coord(int(round(self.i)), int(round(self.j)))
102 def distance(self, other=None):
105 return math.sqrt((self.i - other.i)**2 + (self.j - other.j)**2)
107 return 1.90985*math.atan2(self.j, self.i)
113 s.i = self.i / abs(self.i)
117 s.j = self.j / abs(self.j)
120 #print "Location %s -> %s" % (self, (self / QUADSIZE).roundtogrid())
121 return self.roundtogrid() / QUADSIZE
123 return self.roundtogrid() % QUADSIZE
126 s.i = self.i + randrange(-1, 2)
127 s.j = self.j + randrange(-1, 2)
130 if self.i is None or self.j is None:
132 return "%s - %s" % (self.i+1, self.j+1)
136 "Do not anger the Space Thingy!"
143 return (q.i, q.j) == (self.i, self.j)
147 self.name = None # string-valued if inhabited
148 self.quadrant = Coord() # quadrant located
149 self.pclass = None # could be ""M", "N", "O", or "destroyed"
150 self.crystals = "absent"# could be "mined", "present", "absent"
151 self.known = "unknown" # could be "unknown", "known", "shuttle_down"
152 self.inhabited = False # is it inhabited?
160 self.starbase = False
163 self.supernova = False
165 self.status = "secure" # Could be "secure", "distressed", "enslaved"
170 self.starbase = False
173 return "<%s,%s,%s>" % (self.klingons, self.starbase, self.stars)
175 def fill2d(size, fillfun):
176 "Fill an empty list in 2D."
178 for i in range(size):
180 for j in range(size):
181 lst[i].append(fillfun(i, j))
186 self.snap = False # snapshot taken
187 self.crew = 0 # crew complement
188 self.remkl = 0 # remaining klingons
189 self.nscrem = 0 # remaining super commanders
190 self.starkl = 0 # destroyed stars
191 self.basekl = 0 # destroyed bases
192 self.nromrem = 0 # Romulans remaining
193 self.nplankl = 0 # destroyed uninhabited planets
194 self.nworldkl = 0 # destroyed inhabited planets
195 self.planets = [] # Planet information
196 self.date = 0.0 # stardate
197 self.remres = 0 # remaining resources
198 self.remtime = 0 # remaining time
199 self.baseq = [] # Base quadrant coordinates
200 self.kcmdr = [] # Commander quadrant coordinates
201 self.kscmdr = Coord() # Supercommander quadrant coordinates
203 self.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
205 self.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
209 self.date = None # A real number
210 self.quadrant = None # A coord structure
213 OPTION_ALL = 0xffffffff
214 OPTION_TTY = 0x00000001 # old interface
215 OPTION_CURSES = 0x00000002 # new interface
216 OPTION_IOMODES = 0x00000003 # cover both interfaces
217 OPTION_PLANETS = 0x00000004 # planets and mining
218 OPTION_THOLIAN = 0x00000008 # Tholians and their webs (UT 1979 version)
219 OPTION_THINGY = 0x00000010 # Space Thingy can shoot back (Stas, 2005)
220 OPTION_PROBE = 0x00000020 # deep-space probes (DECUS version, 1980)
221 OPTION_SHOWME = 0x00000040 # bracket Enterprise in chart
222 OPTION_RAMMING = 0x00000080 # enemies may ram Enterprise (Almy)
223 OPTION_MVBADDY = 0x00000100 # more enemies can move (Almy)
224 OPTION_BLKHOLE = 0x00000200 # black hole may timewarp you (Stas, 2005)
225 OPTION_BASE = 0x00000400 # bases have good shields (Stas, 2005)
226 OPTION_WORLDS = 0x00000800 # logic for inhabited worlds (ESR, 2006)
227 OPTION_AUTOSCAN = 0x00001000 # automatic LRSCAN before CHART (ESR, 2006)
228 OPTION_PLAIN = 0x01000000 # user chose plain game
229 OPTION_ALMY = 0x02000000 # user chose Almy variant
230 OPTION_COLOR = 0x04000000 # enable color display (experimental, ESR, 2010)
249 NDEVICES = 16 # Number of devices
259 return (game.damage[dev] != 0.0)
261 return not damaged(DRADIO) or game.condition=="docked"
263 # Define future events
264 FSPY = 0 # Spy event happens always (no future[] entry)
265 # can cause SC to tractor beam Enterprise
266 FSNOVA = 1 # Supernova
267 FTBEAM = 2 # Commander tractor beams Enterprise
268 FSNAP = 3 # Snapshot for time warp
269 FBATTAK = 4 # Commander attacks base
270 FCDBAS = 5 # Commander destroys base
271 FSCMOVE = 6 # Supercommander moves (might attack base)
272 FSCDBAS = 7 # Supercommander destroys base
273 FDSPROB = 8 # Move deep space probe
274 FDISTR = 9 # Emit distress call from an inhabited world
275 FENSLV = 10 # Inhabited word is enslaved */
276 FREPRO = 11 # Klingons build a ship in an enslaved system
279 # Abstract out the event handling -- underlying data structures will change
280 # when we implement stateful events
281 def findevent(evtype):
282 return game.future[evtype]
285 def __init__(self, etype=None, loc=None, power=None):
287 self.location = Coord()
292 self.power = power # enemy energy level
293 game.enemies.append(self)
295 motion = (loc != self.location)
296 if self.location.i is not None and self.location.j is not None:
299 game.quad[self.location.i][self.location.j] = '#'
301 game.quad[self.location.i][self.location.j] = '.'
303 self.location = copy.copy(loc)
304 game.quad[self.location.i][self.location.j] = self.type
305 self.kdist = self.kavgd = (game.sector - loc).distance()
307 self.location = Coord()
308 self.kdist = self.kavgd = None
309 game.enemies.remove(self)
312 return "<%s,%s.%f>" % (self.type, self.location, self.power) # For debugging
316 self.options = None # Game options
317 self.state = Snapshot() # A snapshot structure
318 self.snapsht = Snapshot() # Last snapshot taken for time-travel purposes
319 self.quad = None # contents of our quadrant
320 self.damage = [0.0] * NDEVICES # damage encountered
321 self.future = [] # future events
325 self.future.append(Event())
326 self.passwd = None # Self Destruct password
328 self.quadrant = None # where we are in the large
329 self.sector = None # where we are in the small
330 self.tholian = None # Tholian enemy object
331 self.base = None # position of base in current quadrant
332 self.battle = None # base coordinates being attacked
333 self.plnet = None # location of planet in quadrant
334 self.gamewon = False # Finished!
335 self.ididit = False # action taken -- allows enemy to attack
336 self.alive = False # we are alive (not killed)
337 self.justin = False # just entered quadrant
338 self.shldup = False # shields are up
339 self.shldchg = False # shield is changing (affects efficiency)
340 self.iscate = False # super commander is here
341 self.ientesc = False # attempted escape from supercommander
342 self.resting = False # rest time
343 self.icraft = False # Kirk in Galileo
344 self.landed = False # party on planet (true), on ship (false)
345 self.alldone = False # game is now finished
346 self.neutz = False # Romulan Neutral Zone
347 self.isarmed = False # probe is armed
348 self.inorbit = False # orbiting a planet
349 self.imine = False # mining
350 self.icrystl = False # dilithium crystals aboard
351 self.iseenit = False # seen base attack report
352 self.thawed = False # thawed game
353 self.condition = None # "green", "yellow", "red", "docked", "dead"
354 self.iscraft = None # "onship", "offship", "removed"
355 self.skill = None # Player skill level
356 self.inkling = 0 # initial number of klingons
357 self.inbase = 0 # initial number of bases
358 self.incom = 0 # initial number of commanders
359 self.inscom = 0 # initial number of commanders
360 self.inrom = 0 # initial number of commanders
361 self.instar = 0 # initial stars
362 self.intorps = 0 # initial/max torpedoes
363 self.torps = 0 # number of torpedoes
364 self.ship = 0 # ship type -- 'E' is Enterprise
365 self.abandoned = 0 # count of crew abandoned in space
366 self.length = 0 # length of game
367 self.klhere = 0 # klingons here
368 self.casual = 0 # causalties
369 self.nhelp = 0 # calls for help
370 self.nkinks = 0 # count of energy-barrier crossings
371 self.iplnet = None # planet # in quadrant
372 self.inplan = 0 # initial planets
373 self.irhere = 0 # Romulans in quadrant
374 self.isatb = 0 # =2 if super commander is attacking base
375 self.tourn = None # tournament number
376 self.nprobes = 0 # number of probes available
377 self.inresor = 0.0 # initial resources
378 self.intime = 0.0 # initial time
379 self.inenrg = 0.0 # initial/max energy
380 self.inshld = 0.0 # initial/max shield
381 self.inlsr = 0.0 # initial life support resources
382 self.indate = 0.0 # initial date
383 self.energy = 0.0 # energy level
384 self.shield = 0.0 # shield level
385 self.warpfac = 0.0 # warp speed
386 self.lsupres = 0.0 # life support reserves
387 self.optime = 0.0 # time taken by current operation
388 self.damfac = 0.0 # damage factor
389 self.lastchart = 0.0 # time star chart was last updated
390 self.cryprob = 0.0 # probability that crystal will work
391 self.probe = None # object holding probe course info
392 self.height = 0.0 # height of orbit around planet
393 self.score = 0.0 # overall score
394 self.perdate = 0.0 # rate of kills
395 self.idebug = False # Debugging instrumentation enabled?
396 self.statekscmdr = None # No SuperCommander coordinates yet.
398 # Stas thinks this should be (C expression):
399 # game.state.remkl + len(game.state.kcmdr) > 0 ?
400 # game.state.remres/(game.state.remkl + 4*len(game.state.kcmdr)) : 99
401 # He says the existing expression is prone to divide-by-zero errors
402 # after killing the last klingon when score is shown -- perhaps also
403 # if the only remaining klingon is SCOM.
404 self.state.remtime = self.state.remres/(self.state.remkl + 4*len(self.state.kcmdr))
430 return random.random() < p
432 def randrange(*args):
433 return random.randrange(*args)
438 v *= args[0] # from [0, args[0])
440 v = args[0] + v*(args[1]-args[0]) # from [args[0], args[1])
443 # Code from ai.c begins here
446 "Would this quadrant welcome another Klingon?"
447 return iq.valid_quadrant() and \
448 not game.state.galaxy[iq.i][iq.j].supernova and \
449 game.state.galaxy[iq.i][iq.j].klingons < MAXKLQUAD
451 def tryexit(enemy, look, irun):
452 "A bad guy attempts to bug out."
454 iq.i = game.quadrant.i+(look.i+(QUADSIZE-1))/QUADSIZE - 1
455 iq.j = game.quadrant.j+(look.j+(QUADSIZE-1))/QUADSIZE - 1
456 if not welcoming(iq):
458 if enemy.type == 'R':
459 return False # Romulans cannot escape!
461 # avoid intruding on another commander's territory
462 if enemy.type == 'C':
463 if iq in game.state.kcmdr:
465 # refuse to leave if currently attacking starbase
466 if game.battle == game.quadrant:
468 # don't leave if over 1000 units of energy
469 if enemy.power > 1000.0:
471 oldloc = copy.copy(enemy.location)
472 # handle local matters related to escape
475 if game.condition != "docked":
477 # Handle global matters related to escape
478 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
479 game.state.galaxy[iq.i][iq.j].klingons += 1
480 if enemy.type == 'S':
484 schedule(FSCMOVE, 0.2777)
486 game.state.kscmdr = iq
488 for cmdr in game.state.kcmdr:
489 if cmdr == game.quadrant:
490 game.state.kcmdr.append(iq)
492 # report move out of quadrant.
493 return [(True, enemy, oldloc, iq)]
495 # The bad-guy movement algorithm:
497 # 1. Enterprise has "force" based on condition of phaser and photon torpedoes.
498 # If both are operating full strength, force is 1000. If both are damaged,
499 # force is -1000. Having shields down subtracts an additional 1000.
501 # 2. Enemy has forces equal to the energy of the attacker plus
502 # 100*(K+R) + 500*(C+S) - 400 for novice through good levels OR
503 # 346*K + 400*R + 500*(C+S) - 400 for expert and emeritus.
505 # Attacker Initial energy levels (nominal):
506 # Klingon Romulan Commander Super-Commander
507 # Novice 400 700 1200
509 # Good 450 800 1300 1750
510 # Expert 475 850 1350 1875
511 # Emeritus 500 900 1400 2000
512 # VARIANCE 75 200 200 200
514 # Enemy vessels only move prior to their attack. In Novice - Good games
515 # only commanders move. In Expert games, all enemy vessels move if there
516 # is a commander present. In Emeritus games all enemy vessels move.
518 # 3. If Enterprise is not docked, an aggressive action is taken if enemy
519 # forces are 1000 greater than Enterprise.
521 # Agressive action on average cuts the distance between the ship and
522 # the enemy to 1/4 the original.
524 # 4. At lower energy advantage, movement units are proportional to the
525 # advantage with a 650 advantage being to hold ground, 800 to move forward
526 # 1, 950 for two, 150 for back 4, etc. Variance of 100.
528 # If docked, is reduced by roughly 1.75*game.skill, generally forcing a
529 # retreat, especially at high skill levels.
531 # 5. Motion is limited to skill level, except for SC hi-tailing it out.
533 def movebaddy(enemy):
534 "Tactical movement for the bad guys."
538 # This should probably be just (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
539 if game.skill >= SKILL_EXPERT:
540 nbaddys = (((game.quadrant in game.state.kcmdr)*2 + (game.state.kscmdr==game.quadrant)*2+game.klhere*1.23+game.irhere*1.5)/2.0)
542 nbaddys = (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
543 old_dist = enemy.kdist
544 mdist = int(old_dist + 0.5) # Nearest integer distance
545 # If SC, check with spy to see if should hi-tail it
546 if enemy.type == 'S' and \
547 (enemy.power <= 500.0 or (game.condition=="docked" and not damaged(DPHOTON))):
551 # decide whether to advance, retreat, or hold position
552 forces = enemy.power+100.0*len(game.enemies)+400*(nbaddys-1)
554 forces += 1000 # Good for enemy if shield is down!
555 if not damaged(DPHASER) or not damaged(DPHOTON):
556 if damaged(DPHASER): # phasers damaged
559 forces -= 0.2*(game.energy - 2500.0)
560 if damaged(DPHOTON): # photon torpedoes damaged
563 forces -= 50.0*game.torps
565 # phasers and photon tubes both out!
568 if forces <= 1000.0 and game.condition != "docked": # Typical situation
569 motion = ((forces + randreal(200))/150.0) - 5.0
571 if forces > 1000.0: # Very strong -- move in for kill
572 motion = (1.0 - randreal())**2 * old_dist + 1.0
573 if game.condition == "docked" and (game.options & OPTION_BASE): # protected by base -- back off !
574 motion -= game.skill*(2.0-randreal()**2)
576 proutn("=== MOTION = %d, FORCES = %1.2f, " % (motion, forces))
577 # don't move if no motion
580 # Limit motion according to skill
581 if abs(motion) > game.skill:
586 # calculate preferred number of steps
587 nsteps = abs(int(motion))
588 if motion > 0 and nsteps > mdist:
589 nsteps = mdist # don't overshoot
590 if nsteps > QUADSIZE:
591 nsteps = QUADSIZE # This shouldn't be necessary
593 nsteps = 1 # This shouldn't be necessary
595 proutn("NSTEPS = %d:" % nsteps)
596 # Compute preferred values of delta X and Y
597 m = game.sector - enemy.location
598 if 2.0 * abs(m.i) < abs(m.j):
600 if 2.0 * abs(m.j) < abs(game.sector.i-enemy.location.i):
602 m = (motion * m).sgn()
603 goto = enemy.location
605 for ll in range(nsteps):
607 proutn(" %d" % (ll+1))
608 # Check if preferred position available
619 attempts = 0 # Settle mysterious hang problem
620 while attempts < 20 and not success:
622 if look.i < 0 or look.i >= QUADSIZE:
624 return tryexit(enemy, look, irun)
625 if krawli == m.i or m.j == 0:
627 look.i = goto.i + krawli
629 elif look.j < 0 or look.j >= QUADSIZE:
631 return tryexit(enemy, look, irun)
632 if krawlj == m.j or m.i == 0:
634 look.j = goto.j + krawlj
636 elif (game.options & OPTION_RAMMING) and game.quad[look.i][look.j] != '.':
637 # See if enemy should ram ship
638 if game.quad[look.i][look.j] == game.ship and \
639 (enemy.type == 'C' or enemy.type == 'S'):
640 collision(rammed=True, enemy=enemy)
642 if krawli != m.i and m.j != 0:
643 look.i = goto.i + krawli
645 elif krawlj != m.j and m.i != 0:
646 look.j = goto.j + krawlj
649 break # we have failed
660 # Enemy moved, but is still in sector
661 return [(False, enemy, old_dist, goto)]
664 "Sequence Klingon tactical movement."
667 # Figure out which Klingon is the commander (or Supercommander)
670 if game.quadrant in game.state.kcmdr:
671 for enemy in game.enemies:
672 if enemy.type == 'C':
673 tacmoves += movebaddy(enemy)
674 if game.state.kscmdr == game.quadrant:
675 for enemy in game.enemies:
676 if enemy.type == 'S':
677 tacmoves += movebaddy(enemy)
679 # If skill level is high, move other Klingons and Romulans too!
680 # Move these last so they can base their actions on what the
682 if game.skill >= SKILL_EXPERT and (game.options & OPTION_MVBADDY):
683 for enemy in game.enemies:
684 if enemy.type in ('K', 'R'):
685 tacmoves += movebaddy(enemy)
688 def movescom(iq, avoid):
689 "Commander movement helper."
690 # Avoid quadrants with bases if we want to avoid Enterprise
691 if not welcoming(iq) or (avoid and iq in game.state.baseq):
693 if game.justin and not game.iscate:
696 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons -= 1
697 game.state.kscmdr = iq
698 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons += 1
699 if game.state.kscmdr == game.quadrant:
700 # SC has scooted, remove him from current quadrant
705 for enemy in game.enemies:
706 if enemy.type == 'S':
709 if game.condition != "docked":
712 # check for a helpful planet
713 for i in range(game.inplan):
714 if game.state.planets[i].quadrant == game.state.kscmdr and \
715 game.state.planets[i].crystals == "present":
717 game.state.planets[i].pclass = "destroyed"
718 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].planet = None
721 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
722 proutn(_(" a planet in Quadrant %s has been destroyed") % game.state.kscmdr)
723 prout(_(" by the Super-commander.\""))
725 return True # looks good!
727 def supercommander():
728 "Move the Super Commander."
735 prout("== SUPERCOMMANDER")
736 # Decide on being active or passive
737 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 \
738 (game.state.date-game.indate) < 3.0)
739 if not game.iscate and avoid:
740 # compute move away from Enterprise
741 idelta = game.state.kscmdr-game.quadrant
742 if idelta.distance() > 2.0:
744 idelta.i = game.state.kscmdr.j-game.quadrant.j
745 idelta.j = game.quadrant.i-game.state.kscmdr.i
747 # compute distances to starbases
748 if not game.state.baseq:
752 sc = game.state.kscmdr
753 for (i, base) in enumerate(game.state.baseq):
754 basetbl.append((i, (base - sc).distance()))
755 if game.state.baseq > 1:
756 basetbl.sort(key=lambda x: x[1])
757 # look for nearest base without a commander, no Enterprise, and
758 # without too many Klingons, and not already under attack.
759 ifindit = iwhichb = 0
760 for (i2, base) in enumerate(game.state.baseq):
761 i = basetbl[i2][0] # bug in original had it not finding nearest
762 if base == game.quadrant or base == game.battle or not welcoming(base):
764 # if there is a commander, and no other base is appropriate,
765 # we will take the one with the commander
766 for cmdr in game.state.kcmdr:
767 if base == cmdr and ifindit != 2:
771 else: # no commander -- use this one
776 return # Nothing suitable -- wait until next time
777 ibq = game.state.baseq[iwhichb]
778 # decide how to move toward base
779 idelta = ibq - game.state.kscmdr
780 # Maximum movement is 1 quadrant in either or both axes
781 idelta = idelta.sgn()
782 # try moving in both x and y directions
783 # there was what looked like a bug in the Almy C code here,
784 # but it might be this translation is just wrong.
785 iq = game.state.kscmdr + idelta
786 if not movescom(iq, avoid):
787 # failed -- try some other maneuvers
788 if idelta.i == 0 or idelta.j == 0:
791 iq.j = game.state.kscmdr.j + 1
792 if not movescom(iq, avoid):
793 iq.j = game.state.kscmdr.j - 1
796 iq.i = game.state.kscmdr.i + 1
797 if not movescom(iq, avoid):
798 iq.i = game.state.kscmdr.i - 1
801 # try moving just in x or y
802 iq.j = game.state.kscmdr.j
803 if not movescom(iq, avoid):
804 iq.j = game.state.kscmdr.j + idelta.j
805 iq.i = game.state.kscmdr.i
808 if len(game.state.baseq) == 0:
811 for ibq in game.state.baseq:
812 if ibq == game.state.kscmdr and game.state.kscmdr == game.battle:
815 return # no, don't attack base!
818 schedule(FSCDBAS, randreal(1.0, 3.0))
819 if is_scheduled(FCDBAS):
820 postpone(FSCDBAS, scheduled(FCDBAS)-game.state.date)
821 if not communicating():
825 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") \
827 prout(_(" reports that it is under attack from the Klingon Super-commander."))
828 proutn(_(" It can survive until stardate %d.\"") \
829 % int(scheduled(FSCDBAS)))
832 prout(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
836 game.optime = 0.0 # actually finished
838 # Check for intelligence report
839 if not game.idebug and \
841 (not communicating()) or \
842 not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].charted):
845 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
846 proutn(_(" the Super-commander is in Quadrant %s,") % game.state.kscmdr)
851 if not game.tholian or game.justin:
854 if game.tholian.location.i == 0 and game.tholian.location.j == 0:
857 elif game.tholian.location.i == 0 and game.tholian.location.j == QUADSIZE-1:
860 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == QUADSIZE-1:
863 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == 0:
867 # something is wrong!
868 game.tholian.move(None)
869 prout("***Internal error: Tholian in a bad spot.")
871 # do nothing if we are blocked
872 if game.quad[tid.i][tid.j] not in ('.', '#'):
874 here = copy.copy(game.tholian.location)
875 delta = (tid - game.tholian.location).sgn()
877 while here.i != tid.i:
879 if game.quad[here.i][here.j] == '.':
880 game.tholian.move(here)
882 while here.j != tid.j:
884 if game.quad[here.i][here.j] == '.':
885 game.tholian.move(here)
886 # check to see if all holes plugged
887 for i in range(QUADSIZE):
888 if game.quad[0][i] != '#' and game.quad[0][i] != 'T':
890 if game.quad[QUADSIZE-1][i] != '#' and game.quad[QUADSIZE-1][i] != 'T':
892 if game.quad[i][0] != '#' and game.quad[i][0] != 'T':
894 if game.quad[i][QUADSIZE-1] != '#' and game.quad[i][QUADSIZE-1] != 'T':
896 # All plugged up -- Tholian splits
897 game.quad[game.tholian.location.i][game.tholian.location.j] = '#'
899 prout(crmena(True, 'T', "sector", game.tholian) + _(" completes web."))
900 game.tholian.move(None)
903 # Code from battle.c begins here
905 def doshield(shraise):
906 "Change shield status."
912 key = scanner.nexttok()
914 if scanner.sees("transfer"):
918 prout(_("Shields damaged and down."))
920 if scanner.sees("up"):
922 elif scanner.sees("down"):
925 proutn(_("Do you wish to change shield energy? "))
928 elif damaged(DSHIELD):
929 prout(_("Shields damaged and down."))
932 proutn(_("Shields are up. Do you want them down? "))
939 proutn(_("Shields are down. Do you want them up? "))
945 if action == "SHUP": # raise shields
947 prout(_("Shields already up."))
951 if game.condition != "docked":
953 prout(_("Shields raised."))
956 prout(_("Shields raising uses up last of energy."))
961 elif action == "SHDN":
963 prout(_("Shields already down."))
967 prout(_("Shields lowered."))
970 elif action == "NRG":
971 while scanner.nexttok() != "IHREAL":
973 proutn(_("Energy to transfer to shields- "))
978 if nrg > game.energy:
979 prout(_("Insufficient ship energy."))
982 if game.shield+nrg >= game.inshld:
983 prout(_("Shield energy maximized."))
984 if game.shield+nrg > game.inshld:
985 prout(_("Excess energy requested returned to ship energy"))
986 game.energy -= game.inshld-game.shield
987 game.shield = game.inshld
989 if nrg < 0.0 and game.energy-nrg > game.inenrg:
990 # Prevent shield drain loophole
992 prout(_("Engineering to bridge--"))
993 prout(_(" Scott here. Power circuit problem, Captain."))
994 prout(_(" I can't drain the shields."))
997 if game.shield+nrg < 0:
998 prout(_("All shield energy transferred to ship."))
999 game.energy += game.shield
1002 proutn(_("Scotty- \""))
1004 prout(_("Transferring energy to shields.\""))
1006 prout(_("Draining energy from shields.\""))
1012 "Choose a device to damage, at random."
1014 105, # DSRSENS: short range scanners 10.5%
1015 105, # DLRSENS: long range scanners 10.5%
1016 120, # DPHASER: phasers 12.0%
1017 120, # DPHOTON: photon torpedoes 12.0%
1018 25, # DLIFSUP: life support 2.5%
1019 65, # DWARPEN: warp drive 6.5%
1020 70, # DIMPULS: impulse engines 6.5%
1021 145, # DSHIELD: deflector shields 14.5%
1022 30, # DRADIO: subspace radio 3.0%
1023 45, # DSHUTTL: shuttle 4.5%
1024 15, # DCOMPTR: computer 1.5%
1025 20, # NAVCOMP: navigation system 2.0%
1026 75, # DTRANSP: transporter 7.5%
1027 20, # DSHCTRL: high-speed shield controller 2.0%
1028 10, # DDRAY: death ray 1.0%
1029 30, # DDSP: deep-space probes 3.0%
1031 assert(sum(weights) == 1000)
1032 idx = randrange(1000)
1034 for (i, w) in enumerate(weights):
1038 return None # we should never get here
1040 def collision(rammed, enemy):
1041 "Collision handling for rammong events."
1042 prouts(_("***RED ALERT! RED ALERT!"))
1044 prout(_("***COLLISION IMMINENT."))
1048 hardness = {'R':1.5, 'C':2.0, 'S':2.5, 'T':0.5, '?':4.0}.get(enemy.type, 1.0)
1050 proutn(_(" rammed by "))
1053 proutn(crmena(False, enemy.type, "sector", enemy.location))
1055 proutn(_(" (original position)"))
1057 deadkl(enemy.location, enemy.type, game.sector)
1058 proutn("***" + crmshp() + " heavily damaged.")
1059 icas = randrange(10, 30)
1060 prout(_("***Sickbay reports %d casualties") % icas)
1062 game.state.crew -= icas
1063 # In the pre-SST2K version, all devices got equiprobably damaged,
1064 # which was silly. Instead, pick up to half the devices at
1065 # random according to our weighting table,
1066 ncrits = randrange(NDEVICES/2)
1070 if game.damage[dev] < 0:
1072 extradm = (10.0*hardness*randreal()+1.0)*game.damfac
1073 # Damage for at least time of travel!
1074 game.damage[dev] += game.optime + extradm
1076 prout(_("***Shields are down."))
1077 if game.state.remkl + len(game.state.kcmdr) + game.state.nscrem:
1084 def torpedo(origin, bearing, dispersion, number, nburst):
1085 "Let a photon torpedo fly"
1086 if not damaged(DSRSENS) or game.condition == "docked":
1087 setwnd(srscan_window)
1089 setwnd(message_window)
1090 ac = bearing + 0.25*dispersion # dispersion is a random variable
1091 bullseye = (15.0 - bearing)*0.5235988
1092 track = course(bearing=ac, distance=QUADSIZE, origin=cartesian(origin))
1093 bumpto = Coord(0, 0)
1094 # Loop to move a single torpedo
1095 setwnd(message_window)
1096 for step in range(1, QUADSIZE*2):
1097 if not track.nexttok():
1100 if not w.valid_sector():
1102 iquad = game.quad[w.i][w.j]
1103 tracktorpedo(w, step, number, nburst, iquad)
1107 setwnd(message_window)
1108 if not damaged(DSRSENS) or game.condition == "docked":
1109 skip(1) # start new line after text track
1110 if iquad in ('E', 'F'): # Hit our ship
1112 prout(_("Torpedo hits %s.") % crmshp())
1113 hit = 700.0 + randreal(100) - \
1114 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1115 newcnd() # we're blown out of dock
1116 if game.landed or game.condition == "docked":
1117 return hit # Cheat if on a planet
1118 # In the C/FORTRAN version, dispersion was 2.5 radians, which
1119 # is 143 degrees, which is almost exactly 4.8 clockface units
1120 displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
1121 displacement.nexttok()
1122 bumpto = displacement.sector()
1123 if not bumpto.valid_sector():
1125 if game.quad[bumpto.i][bumpto.j] == ' ':
1128 if game.quad[bumpto.i][bumpto.j] != '.':
1129 # can't move into object
1131 game.sector = bumpto
1133 game.quad[w.i][w.j] = '.'
1134 game.quad[bumpto.i][bumpto.j] = iquad
1135 prout(_(" displaced by blast to Sector %s ") % bumpto)
1136 for enemy in game.enemies:
1137 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1140 elif iquad in ('C', 'S', 'R', 'K'): # Hit a regular enemy
1142 if iquad in ('C', 'S') and withprob(0.05):
1143 prout(crmena(True, iquad, "sector", w) + _(" uses anti-photon device;"))
1144 prout(_(" torpedo neutralized."))
1146 for enemy in game.enemies:
1147 if w == enemy.location:
1148 kp = math.fabs(enemy.power)
1149 h1 = 700.0 + randrange(100) - \
1150 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1158 if enemy.power == 0:
1161 proutn(crmena(True, iquad, "sector", w))
1162 displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
1163 displacement.nexttok()
1164 bumpto = displacement.sector()
1165 if not bumpto.valid_sector():
1166 prout(_(" damaged but not destroyed."))
1168 if game.quad[bumpto.i][bumpto.j] == ' ':
1169 prout(_(" buffeted into black hole."))
1170 deadkl(w, iquad, bumpto)
1171 if game.quad[bumpto.i][bumpto.j] != '.':
1172 prout(_(" damaged but not destroyed."))
1174 prout(_(" damaged-- displaced by blast to Sector %s ")%bumpto)
1175 enemy.location = bumpto
1176 game.quad[w.i][w.j] = '.'
1177 game.quad[bumpto.i][bumpto.j] = iquad
1178 for enemy in game.enemies:
1179 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1183 prout("Internal error, no enemy where expected!")
1186 elif iquad == 'B': # Hit a base
1188 prout(_("***STARBASE DESTROYED.."))
1189 game.state.baseq = [x for x in game.state.baseq if x != game.quadrant]
1190 game.quad[w.i][w.j] = '.'
1191 game.base.invalidate()
1192 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
1193 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = False
1194 game.state.basekl += 1
1197 elif iquad == 'P': # Hit a planet
1198 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1199 game.state.nplankl += 1
1200 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1201 game.iplnet.pclass = "destroyed"
1203 game.plnet.invalidate()
1204 game.quad[w.i][w.j] = '.'
1206 # captain perishes on planet
1209 elif iquad == '@': # Hit an inhabited world -- very bad!
1210 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1211 game.state.nworldkl += 1
1212 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1213 game.iplnet.pclass = "destroyed"
1215 game.plnet.invalidate()
1216 game.quad[w.i][w.j] = '.'
1218 # captain perishes on planet
1220 prout(_("The torpedo destroyed an inhabited planet."))
1222 elif iquad == '*': # Hit a star
1226 prout(crmena(True, '*', "sector", w) + _(" unaffected by photon blast."))
1228 elif iquad == '?': # Hit a thingy
1229 if not (game.options & OPTION_THINGY) or withprob(0.3):
1231 prouts(_("AAAAIIIIEEEEEEEEAAAAAAAAUUUUUGGGGGHHHHHHHHHHHH!!!"))
1233 prouts(_(" HACK! HACK! HACK! *CHOKE!* "))
1235 proutn(_("Mr. Spock-"))
1236 prouts(_(" \"Fascinating!\""))
1240 # Stas Sergeev added the possibility that
1241 # you can shove the Thingy and piss it off.
1242 # It then becomes an enemy and may fire at you.
1245 elif iquad == ' ': # Black hole
1247 prout(crmena(True, ' ', "sector", w) + _(" swallows torpedo."))
1249 elif iquad == '#': # hit the web
1251 prout(_("***Torpedo absorbed by Tholian web."))
1253 elif iquad == 'T': # Hit a Tholian
1254 h1 = 700.0 + randrange(100) - \
1255 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1258 game.quad[w.i][w.j] = '.'
1263 proutn(crmena(True, 'T', "sector", w))
1265 prout(_(" survives photon blast."))
1267 prout(_(" disappears."))
1268 game.tholian.move(None)
1269 game.quad[w.i][w.j] = '#'
1274 proutn("Don't know how to handle torpedo collision with ")
1275 proutn(crmena(True, iquad, "sector", w))
1280 setwnd(message_window)
1281 prout(_("Torpedo missed."))
1285 "Critical-hit resolution."
1286 if hit < (275.0-25.0*game.skill)*randreal(1.0, 1.5):
1288 ncrit = int(1.0 + hit/(500.0+randreal(100)))
1289 proutn(_("***CRITICAL HIT--"))
1290 # Select devices and cause damage
1295 # Cheat to prevent shuttle damage unless on ship
1296 if not (game.damage[j]<0.0 or (j == DSHUTTL and game.iscraft != "onship")):
1299 extradm = (hit*game.damfac)/(ncrit*randreal(75, 100))
1300 game.damage[j] += extradm
1303 for (i, j) in enumerate(cdam):
1305 if skipcount % 3 == 2 and i < len(cdam)-1:
1310 prout(_(" damaged."))
1311 if damaged(DSHIELD) and game.shldup:
1312 prout(_("***Shields knocked down."))
1315 def attack(torps_ok):
1316 # bad guy attacks us
1317 # torps_ok == False forces use of phasers in an attack
1318 # game could be over at this point, check
1328 prout("=== ATTACK!")
1329 # Tholian gets to move before attacking
1332 # if you have just entered the RNZ, you'll get a warning
1333 if game.neutz: # The one chance not to be attacked
1336 # commanders get a chance to tac-move towards you
1337 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:
1338 for (bugout, enemy, old, goto) in moveklings():
1340 # we know about this if either short or long range
1341 # sensors are working
1342 if damaged(DSRSENS) and damaged(DLRSENS) \
1343 and game.condition != "docked":
1344 prout(crmena(True, enemy.type, "sector", old) + \
1345 (_(" escapes to Quadrant %s (and regains strength).") % goto))
1346 else: # Enemy still in-sector
1347 if enemy.move(goto):
1348 if not damaged(DSRSENS) or game.condition == "docked":
1349 proutn(_("*** %s from Sector %s") % (cramen(enemy.type), enemy.location))
1350 if enemy.kdist < old:
1351 proutn(_(" advances to "))
1353 proutn(_(" retreats to "))
1354 prout("Sector %s." % goto)
1356 # if no enemies remain after movement, we're done
1357 if len(game.enemies) == 0 or (len(game.enemies) == 1 and thing.at(game.quadrant) and not thing.angered):
1359 # set up partial hits if attack happens during shield status change
1360 pfac = 1.0/game.inshld
1362 chgfac = 0.25 + randreal(0.5)
1364 # message verbosity control
1365 if game.skill <= SKILL_FAIR:
1367 for enemy in game.enemies:
1369 continue # too weak to attack
1370 # compute hit strength and diminish shield power
1372 # Increase chance of photon torpedos if docked or enemy energy is low
1373 if game.condition == "docked":
1375 if enemy.power < 500:
1377 if enemy.type == 'T' or (enemy.type == '?' and not thing.angered):
1379 # different enemies have different probabilities of throwing a torp
1380 usephasers = not torps_ok or \
1381 (enemy.type == 'K' and r > 0.0005) or \
1382 (enemy.type == 'C' and r > 0.015) or \
1383 (enemy.type == 'R' and r > 0.3) or \
1384 (enemy.type == 'S' and r > 0.07) or \
1385 (enemy.type == '?' and r > 0.05)
1386 if usephasers: # Enemy uses phasers
1387 if game.condition == "docked":
1388 continue # Don't waste the effort!
1389 attempt = True # Attempt to attack
1390 dustfac = randreal(0.8, 0.85)
1391 hit = enemy.power*math.pow(dustfac, enemy.kavgd)
1393 else: # Enemy uses photon torpedo
1394 # We should be able to make the bearing() method work here
1395 pcourse = 1.90985*math.atan2(game.sector.j-enemy.location.j, enemy.location.i-game.sector.i)
1397 proutn(_("***TORPEDO INCOMING"))
1398 if not damaged(DSRSENS):
1399 proutn(_(" From ") + crmena(False, enemy.type, where, enemy.location))
1402 dispersion = (randreal()+randreal())*0.5 - 0.5
1403 dispersion += 0.002*enemy.power*dispersion
1404 hit = torpedo(enemy.location, pcourse, dispersion, number=1, nburst=1)
1405 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
1406 finish(FWON) # Klingons did themselves in!
1407 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.alldone:
1408 return # Supernova or finished
1411 # incoming phaser or torpedo, shields may dissipate it
1412 if game.shldup or game.shldchg or game.condition == "docked":
1413 # shields will take hits
1414 propor = pfac * game.shield
1415 if game.condition == "docked":
1419 hitsh = propor*chgfac*hit+1.0
1421 if absorb > game.shield:
1422 absorb = game.shield
1423 game.shield -= absorb
1425 # taking a hit blasts us out of a starbase dock
1426 if game.condition == "docked":
1428 # but the shields may take care of it
1429 if propor > 0.1 and hit < 0.005*game.energy:
1431 # hit from this opponent got through shields, so take damage
1433 proutn(_("%d unit hit") % int(hit))
1434 if (damaged(DSRSENS) and usephasers) or game.skill<=SKILL_FAIR:
1435 proutn(_(" on the ") + crmshp())
1436 if not damaged(DSRSENS) and usephasers:
1437 prout(_(" from ") + crmena(False, enemy.type, where, enemy.location))
1439 # Decide if hit is critical
1445 if game.energy <= 0:
1446 # Returning home upon your shield, not with it...
1449 if not attempt and game.condition == "docked":
1450 prout(_("***Enemies decide against attacking your ship."))
1451 percent = 100.0*pfac*game.shield+0.5
1453 # Shields fully protect ship
1454 proutn(_("Enemy attack reduces shield strength to "))
1456 # Emit message if starship suffered hit(s)
1458 proutn(_("Energy left %2d shields ") % int(game.energy))
1461 elif not damaged(DSHIELD):
1464 proutn(_("damaged, "))
1465 prout(_("%d%%, torpedoes left %d") % (percent, game.torps))
1466 # Check if anyone was hurt
1467 if hitmax >= 200 or hittot >= 500:
1468 icas = randrange(int(hittot * 0.015))
1471 prout(_("Mc Coy- \"Sickbay to bridge. We suffered %d casualties") % icas)
1472 prout(_(" in that last attack.\""))
1474 game.state.crew -= icas
1475 # After attack, reset average distance to enemies
1476 for enemy in game.enemies:
1477 enemy.kavgd = enemy.kdist
1481 def deadkl(w, etype, mv):
1482 "Kill a Klingon, Tholian, Romulan, or Thingy."
1483 # Added mv to allow enemy to "move" before dying
1484 proutn(crmena(True, etype, "sector", mv))
1485 # Decide what kind of enemy it is and update appropriately
1487 # Chalk up a Romulan
1488 game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans -= 1
1490 game.state.nromrem -= 1
1499 # Killed some type of Klingon
1500 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
1503 game.state.kcmdr.remove(game.quadrant)
1505 if game.state.kcmdr:
1506 schedule(FTBEAM, expran(1.0*game.incom/len(game.state.kcmdr)))
1507 if is_scheduled(FCDBAS) and game.battle == game.quadrant:
1510 game.state.remkl -= 1
1512 game.state.nscrem -= 1
1513 game.state.kscmdr.invalidate()
1518 # For each kind of enemy, finish message to player
1519 prout(_(" destroyed."))
1520 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
1523 # Remove enemy ship from arrays describing local conditions
1524 for e in game.enemies:
1531 "Return None if target is invalid, otherwise return a course angle."
1532 if not w.valid_sector():
1536 # C code this was translated from is wacky -- why the sign reversal?
1537 delta.j = (w.j - game.sector.j)
1538 delta.i = (game.sector.i - w.i)
1539 if delta == Coord(0, 0):
1541 prout(_("Spock- \"Bridge to sickbay. Dr. McCoy,"))
1542 prout(_(" I recommend an immediate review of"))
1543 prout(_(" the Captain's psychological profile.\""))
1546 return delta.bearing()
1549 "Launch photon torpedo salvo."
1552 if damaged(DPHOTON):
1553 prout(_("Photon tubes damaged."))
1557 prout(_("No torpedoes left."))
1560 # First, get torpedo count
1563 if scanner.token == "IHALPHA":
1566 elif scanner.token == "IHEOL" or not scanner.waiting():
1567 prout(_("%d torpedoes left.") % game.torps)
1569 proutn(_("Number of torpedoes to fire- "))
1570 continue # Go back around to get a number
1571 else: # key == "IHREAL"
1573 if n <= 0: # abort command
1578 prout(_("Maximum of %d torpedoes per burst.") % MAXBURST)
1581 scanner.chew() # User requested more torps than available
1582 continue # Go back around
1583 break # All is good, go to next stage
1587 key = scanner.nexttok()
1588 if i == 0 and key == "IHEOL":
1589 break # no coordinate waiting, we will try prompting
1590 if i == 1 and key == "IHEOL":
1591 # direct all torpedoes at one target
1593 target.append(target[0])
1594 tcourse.append(tcourse[0])
1597 scanner.push(scanner.token)
1598 target.append(scanner.getcoord())
1599 if target[-1] is None:
1601 tcourse.append(targetcheck(target[-1]))
1602 if tcourse[-1] is None:
1605 if len(target) == 0:
1606 # prompt for each one
1608 proutn(_("Target sector for torpedo number %d- ") % (i+1))
1610 target.append(scanner.getcoord())
1611 if target[-1] is None:
1613 tcourse.append(targetcheck(target[-1]))
1614 if tcourse[-1] is None:
1617 # Loop for moving <n> torpedoes
1619 if game.condition != "docked":
1621 dispersion = (randreal()+randreal())*0.5 -0.5
1622 if math.fabs(dispersion) >= 0.47:
1624 dispersion *= randreal(1.2, 2.2)
1626 prouts(_("***TORPEDO NUMBER %d MISFIRES") % (i+1))
1628 prouts(_("***TORPEDO MISFIRES."))
1631 prout(_(" Remainder of burst aborted."))
1633 prout(_("***Photon tubes damaged by misfire."))
1634 game.damage[DPHOTON] = game.damfac * randreal(1.0, 3.0)
1636 if game.shldup or game.condition == "docked":
1637 dispersion *= 1.0 + 0.0001*game.shield
1638 torpedo(game.sector, tcourse[i], dispersion, number=i, nburst=n)
1639 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
1641 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)<=0:
1645 "Check for phasers overheating."
1647 checkburn = (rpow-1500.0)*0.00038
1648 if withprob(checkburn):
1649 prout(_("Weapons officer Sulu- \"Phasers overheated, sir.\""))
1650 game.damage[DPHASER] = game.damfac* randreal(1.0, 2.0) * (1.0+checkburn)
1652 def checkshctrl(rpow):
1653 "Check shield control."
1656 prout(_("Shields lowered."))
1658 # Something bad has happened
1659 prouts(_("***RED ALERT! RED ALERT!"))
1661 hit = rpow*game.shield/game.inshld
1662 game.energy -= rpow+hit*0.8
1663 game.shield -= hit*0.2
1664 if game.energy <= 0.0:
1665 prouts(_("Sulu- \"Captain! Shield malf***********************\""))
1670 prouts(_("Sulu- \"Captain! Shield malfunction! Phaser fire contained!\""))
1672 prout(_("Lt. Uhura- \"Sir, all decks reporting damage.\""))
1673 icas = randrange(int(hit*0.012))
1678 prout(_("McCoy to bridge- \"Severe radiation burns, Jim."))
1679 prout(_(" %d casualties so far.\"") % icas)
1681 game.state.crew -= icas
1683 prout(_("Phaser energy dispersed by shields."))
1684 prout(_("Enemy unaffected."))
1689 "Register a phaser hit on Klingons and Romulans."
1696 dustfac = randreal(0.9, 1.0)
1697 hit = wham*math.pow(dustfac, game.enemies[kk].kdist)
1698 kpini = game.enemies[kk].power
1699 kp = math.fabs(kpini)
1700 if PHASEFAC*hit < kp:
1702 if game.enemies[kk].power < 0:
1703 game.enemies[kk].power -= -kp
1705 game.enemies[kk].power -= kp
1706 kpow = game.enemies[kk].power
1707 w = game.enemies[kk].location
1709 if not damaged(DSRSENS):
1711 proutn(_("%d unit hit on ") % int(hit))
1713 proutn(_("Very small hit on "))
1714 ienm = game.quad[w.i][w.j]
1717 proutn(crmena(False, ienm, "sector", w))
1721 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1725 kk -= 1 # don't do the increment
1727 else: # decide whether or not to emasculate klingon
1728 if kpow > 0 and withprob(0.9) and kpow <= randreal(0.4, 0.8)*kpini:
1729 prout(_("***Mr. Spock- \"Captain, the vessel at Sector %s")%w)
1730 prout(_(" has just lost its firepower.\""))
1731 game.enemies[kk].power = -kpow
1736 "Fire phasers at bad guys."
1740 irec = 0 # Cheating inhibitor
1749 # SR sensors and Computer are needed for automode
1750 if damaged(DSRSENS) or damaged(DCOMPTR):
1752 if game.condition == "docked":
1753 prout(_("Phasers can't be fired through base shields."))
1756 if damaged(DPHASER):
1757 prout(_("Phaser control damaged."))
1761 if damaged(DSHCTRL):
1762 prout(_("High speed shield control damaged."))
1765 if game.energy <= 200.0:
1766 prout(_("Insufficient energy to activate high-speed shield control."))
1769 prout(_("Weapons Officer Sulu- \"High-speed shield control enabled, sir.\""))
1771 # Original code so convoluted, I re-did it all
1772 # (That was Tom Almy talking about the C code, I think -- ESR)
1773 while automode == "NOTSET":
1774 key = scanner.nexttok()
1775 if key == "IHALPHA":
1776 if scanner.sees("manual"):
1777 if len(game.enemies)==0:
1778 prout(_("There is no enemy present to select."))
1781 automode = "AUTOMATIC"
1784 key = scanner.nexttok()
1785 elif scanner.sees("automatic"):
1786 if (not itarg) and len(game.enemies) != 0:
1787 automode = "FORCEMAN"
1789 if len(game.enemies)==0:
1790 prout(_("Energy will be expended into space."))
1791 automode = "AUTOMATIC"
1792 key = scanner.nexttok()
1793 elif scanner.sees("no"):
1798 elif key == "IHREAL":
1799 if len(game.enemies)==0:
1800 prout(_("Energy will be expended into space."))
1801 automode = "AUTOMATIC"
1803 automode = "FORCEMAN"
1805 automode = "AUTOMATIC"
1808 if len(game.enemies)==0:
1809 prout(_("Energy will be expended into space."))
1810 automode = "AUTOMATIC"
1812 automode = "FORCEMAN"
1814 proutn(_("Manual or automatic? "))
1819 if automode == "AUTOMATIC":
1820 if key == "IHALPHA" and scanner.sees("no"):
1822 key = scanner.nexttok()
1823 if key != "IHREAL" and len(game.enemies) != 0:
1824 prout(_("Phasers locked on target. Energy available: %.2f")%avail)
1829 for i in range(len(game.enemies)):
1830 irec += math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))*randreal(1.01, 1.06) + 1.0
1832 proutn(_("%d units required. ") % irec)
1834 proutn(_("Units to fire= "))
1835 key = scanner.nexttok()
1840 proutn(_("Energy available= %.2f") % avail)
1843 if not rpow > avail:
1849 key = scanner.nexttok()
1850 if key == "IHALPHA" and scanner.sees("no"):
1853 game.energy -= 200 # Go and do it!
1854 if checkshctrl(rpow):
1859 if len(game.enemies):
1862 for i in range(len(game.enemies)):
1866 hits[i] = math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))
1867 over = randreal(1.01, 1.06) * hits[i]
1869 powrem -= hits[i] + over
1870 if powrem <= 0 and temp < hits[i]:
1879 if extra > 0 and not game.alldone:
1881 proutn(_("*** Tholian web absorbs "))
1882 if len(game.enemies)>0:
1883 proutn(_("excess "))
1884 prout(_("phaser energy."))
1886 prout(_("%d expended on empty space.") % int(extra))
1887 elif automode == "FORCEMAN":
1890 if damaged(DCOMPTR):
1891 prout(_("Battle computer damaged, manual fire only."))
1894 prouts(_("---WORKING---"))
1896 prout(_("Short-range-sensors-damaged"))
1897 prout(_("Insufficient-data-for-automatic-phaser-fire"))
1898 prout(_("Manual-fire-must-be-used"))
1900 elif automode == "MANUAL":
1902 for k in range(len(game.enemies)):
1903 aim = game.enemies[k].location
1904 ienm = game.quad[aim.i][aim.j]
1906 proutn(_("Energy available= %.2f") % (avail-0.006))
1910 if damaged(DSRSENS) and \
1911 not game.sector.distance(aim)<2**0.5 and ienm in ('C', 'S'):
1912 prout(cramen(ienm) + _(" can't be located without short range scan."))
1915 hits[k] = 0 # prevent overflow -- thanks to Alexei Voitenko
1920 if itarg and k > kz:
1921 irec = (abs(game.enemies[k].power)/(PHASEFAC*math.pow(0.9, game.enemies[k].kdist))) * randreal(1.01, 1.06) + 1.0
1924 if not damaged(DCOMPTR):
1929 proutn(_("units to fire at %s- ") % crmena(False, ienm, "sector", aim))
1930 key = scanner.nexttok()
1931 if key == "IHALPHA" and scanner.sees("no"):
1933 key = scanner.nexttok()
1935 if key == "IHALPHA":
1939 if k == 1: # Let me say I'm baffled by this
1942 if scanner.real < 0:
1946 hits[k] = scanner.real
1947 rpow += scanner.real
1948 # If total requested is too much, inform and start over
1950 prout(_("Available energy exceeded -- try again."))
1953 key = scanner.nexttok() # scan for next value
1956 # zero energy -- abort
1959 if key == "IHALPHA" and scanner.sees("no"):
1964 game.energy -= 200.0
1965 if checkshctrl(rpow):
1969 # Say shield raised or malfunction, if necessary
1976 prout(_("Sulu- \"Sir, the high-speed shield control has malfunctioned . . ."))
1977 prouts(_(" CLICK CLICK POP . . ."))
1978 prout(_(" No response, sir!"))
1981 prout(_("Shields raised."))
1986 # Code from events,c begins here.
1988 # This isn't a real event queue a la BSD Trek yet -- you can only have one
1989 # event of each type active at any given time. Mostly these means we can
1990 # only have one FDISTR/FENSLV/FREPRO sequence going at any given time
1991 # BSD Trek, from which we swiped the idea, can have up to 5.
1993 def unschedule(evtype):
1994 "Remove an event from the schedule."
1995 game.future[evtype].date = FOREVER
1996 return game.future[evtype]
1998 def is_scheduled(evtype):
1999 "Is an event of specified type scheduled."
2000 return game.future[evtype].date != FOREVER
2002 def scheduled(evtype):
2003 "When will this event happen?"
2004 return game.future[evtype].date
2006 def schedule(evtype, offset):
2007 "Schedule an event of specified type."
2008 game.future[evtype].date = game.state.date + offset
2009 return game.future[evtype]
2011 def postpone(evtype, offset):
2012 "Postpone a scheduled event."
2013 game.future[evtype].date += offset
2016 "Rest period is interrupted by event."
2019 proutn(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
2021 game.resting = False
2027 "Run through the event queue looking for things to do."
2029 fintim = game.state.date + game.optime
2038 def tractorbeam(yank):
2039 "Tractor-beaming cases merge here."
2041 game.optime = (10.0/(7.5*7.5))*yank # 7.5 is yank rate (warp 7.5)
2043 prout("***" + crmshp() + _(" caught in long range tractor beam--"))
2044 # If Kirk & Co. screwing around on planet, handle
2045 atover(True) # atover(true) is Grab
2048 if game.icraft: # Caught in Galileo?
2051 # Check to see if shuttle is aboard
2052 if game.iscraft == "offship":
2055 prout(_("Galileo, left on the planet surface, is captured"))
2056 prout(_("by aliens and made into a flying McDonald's."))
2057 game.damage[DSHUTTL] = -10
2058 game.iscraft = "removed"
2060 prout(_("Galileo, left on the planet surface, is well hidden."))
2062 game.quadrant = game.state.kscmdr
2064 game.quadrant = game.state.kcmdr[i]
2065 game.sector = randplace(QUADSIZE)
2066 prout(crmshp() + _(" is pulled to Quadrant %s, Sector %s") \
2067 % (game.quadrant, game.sector))
2069 prout(_("(Remainder of rest/repair period cancelled.)"))
2070 game.resting = False
2072 if not damaged(DSHIELD) and game.shield > 0:
2073 doshield(shraise=True) # raise shields
2074 game.shldchg = False
2076 prout(_("(Shields not currently useable.)"))
2078 # Adjust finish time to time of tractor beaming?
2079 # fintim = game.state.date+game.optime
2080 attack(torps_ok=False)
2081 if not game.state.kcmdr:
2084 schedule(FTBEAM, game.optime+expran(1.5*game.intime/len(game.state.kcmdr)))
2087 "Code merges here for any commander destroying a starbase."
2088 # Not perfect, but will have to do
2089 # Handle case where base is in same quadrant as starship
2090 if game.battle == game.quadrant:
2091 game.state.chart[game.battle.i][game.battle.j].starbase = False
2092 game.quad[game.base.i][game.base.j] = '.'
2093 game.base.invalidate()
2096 prout(_("Spock- \"Captain, I believe the starbase has been destroyed.\""))
2097 elif game.state.baseq and communicating():
2098 # Get word via subspace radio
2101 prout(_("Lt. Uhura- \"Captain, Starfleet Command reports that"))
2102 proutn(_(" the starbase in Quadrant %s has been destroyed by") % game.battle)
2104 prout(_("the Klingon Super-Commander"))
2106 prout(_("a Klingon Commander"))
2107 game.state.chart[game.battle.i][game.battle.j].starbase = False
2108 # Remove Starbase from galaxy
2109 game.state.galaxy[game.battle.i][game.battle.j].starbase = False
2110 game.state.baseq = [x for x in game.state.baseq if x != game.battle]
2112 # reinstate a commander's base attack
2116 game.battle.invalidate()
2118 prout("=== EVENTS from %.2f to %.2f:" % (game.state.date, fintim))
2119 for i in range(1, NEVENTS):
2120 if i == FSNOVA: proutn("=== Supernova ")
2121 elif i == FTBEAM: proutn("=== T Beam ")
2122 elif i == FSNAP: proutn("=== Snapshot ")
2123 elif i == FBATTAK: proutn("=== Base Attack ")
2124 elif i == FCDBAS: proutn("=== Base Destroy ")
2125 elif i == FSCMOVE: proutn("=== SC Move ")
2126 elif i == FSCDBAS: proutn("=== SC Base Destroy ")
2127 elif i == FDSPROB: proutn("=== Probe Move ")
2128 elif i == FDISTR: proutn("=== Distress Call ")
2129 elif i == FENSLV: proutn("=== Enslavement ")
2130 elif i == FREPRO: proutn("=== Klingon Build ")
2132 prout("%.2f" % (scheduled(i)))
2135 radio_was_broken = damaged(DRADIO)
2138 # Select earliest extraneous event, evcode==0 if no events
2143 for l in range(1, NEVENTS):
2144 if game.future[l].date < datemin:
2147 prout("== Event %d fires" % evcode)
2148 datemin = game.future[l].date
2149 xtime = datemin-game.state.date
2150 game.state.date = datemin
2151 # Decrement Federation resources and recompute remaining time
2152 game.state.remres -= (game.state.remkl+4*len(game.state.kcmdr))*xtime
2154 if game.state.remtime <= 0:
2157 # Any crew left alive?
2158 if game.state.crew <= 0:
2161 # Is life support adequate?
2162 if damaged(DLIFSUP) and game.condition != "docked":
2163 if game.lsupres < xtime and game.damage[DLIFSUP] > game.lsupres:
2166 game.lsupres -= xtime
2167 if game.damage[DLIFSUP] <= xtime:
2168 game.lsupres = game.inlsr
2171 if game.condition == "docked":
2173 # Don't fix Deathray here
2174 for l in range(NDEVICES):
2175 if game.damage[l] > 0.0 and l != DDRAY:
2176 if game.damage[l]-repair > 0.0:
2177 game.damage[l] -= repair
2179 game.damage[l] = 0.0
2180 # If radio repaired, update star chart and attack reports
2181 if radio_was_broken and not damaged(DRADIO):
2182 prout(_("Lt. Uhura- \"Captain, the sub-space radio is working and"))
2183 prout(_(" surveillance reports are coming in."))
2185 if not game.iseenit:
2189 prout(_(" The star chart is now up to date.\""))
2191 # Cause extraneous event EVCODE to occur
2192 game.optime -= xtime
2193 if evcode == FSNOVA: # Supernova
2196 schedule(FSNOVA, expran(0.5*game.intime))
2197 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2199 elif evcode == FSPY: # Check with spy to see if SC should tractor beam
2200 if game.state.nscrem == 0 or \
2201 ictbeam or istract or \
2202 game.condition == "docked" or game.isatb == 1 or game.iscate:
2204 if game.ientesc or \
2205 (game.energy<2000 and game.torps<4 and game.shield < 1250) or \
2206 (damaged(DPHASER) and (damaged(DPHOTON) or game.torps<4)) or \
2207 (damaged(DSHIELD) and \
2208 (game.energy < 2500 or damaged(DPHASER)) and \
2209 (game.torps < 5 or damaged(DPHOTON))):
2211 istract = ictbeam = True
2212 tractorbeam((game.state.kscmdr-game.quadrant).distance())
2215 elif evcode == FTBEAM: # Tractor beam
2216 if not game.state.kcmdr:
2219 i = randrange(len(game.state.kcmdr))
2220 yank = (game.state.kcmdr[i]-game.quadrant).distance()
2221 if istract or game.condition == "docked" or yank == 0:
2222 # Drats! Have to reschedule
2224 game.optime + expran(1.5*game.intime/len(game.state.kcmdr)))
2228 elif evcode == FSNAP: # Snapshot of the universe (for time warp)
2229 game.snapsht = copy.deepcopy(game.state)
2230 game.state.snap = True
2231 schedule(FSNAP, expran(0.5 * game.intime))
2232 elif evcode == FBATTAK: # Commander attacks starbase
2233 if not game.state.kcmdr or not game.state.baseq:
2238 ibq = None # Force battle location to persist past loop
2240 for ibq in game.state.baseq:
2241 for cmdr in game.state.kcmdr:
2242 if ibq == cmdr and ibq != game.quadrant and ibq != game.state.kscmdr:
2244 # no match found -- try later
2245 schedule(FBATTAK, expran(0.3*game.intime))
2250 # commander + starbase combination found -- launch attack
2252 schedule(FCDBAS, randreal(1.0, 4.0))
2253 if game.isatb: # extra time if SC already attacking
2254 postpone(FCDBAS, scheduled(FSCDBAS)-game.state.date)
2255 game.future[FBATTAK].date = game.future[FCDBAS].date + expran(0.3*game.intime)
2256 game.iseenit = False
2257 if not communicating():
2258 continue # No warning :-(
2262 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") % game.battle)
2263 prout(_(" reports that it is under attack and that it can"))
2264 prout(_(" hold out only until stardate %d.\"") % (int(scheduled(FCDBAS))))
2267 elif evcode == FSCDBAS: # Supercommander destroys base
2270 if not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].starbase:
2271 continue # WAS RETURN!
2273 game.battle = game.state.kscmdr
2275 elif evcode == FCDBAS: # Commander succeeds in destroying base
2276 if evcode == FCDBAS:
2278 if not game.state.baseq() \
2279 or not game.state.galaxy[game.battle.i][game.battle.j].starbase:
2280 game.battle.invalidate()
2282 # find the lucky pair
2283 for cmdr in game.state.kcmdr:
2284 if cmdr == game.battle:
2287 # No action to take after all
2290 elif evcode == FSCMOVE: # Supercommander moves
2291 schedule(FSCMOVE, 0.2777)
2292 if not game.ientesc and not istract and game.isatb != 1 and \
2293 (not game.iscate or not game.justin):
2295 elif evcode == FDSPROB: # Move deep space probe
2296 schedule(FDSPROB, 0.01)
2297 if not game.probe.nexttok():
2298 if not game.probe.quadrant().valid_quadrant() or \
2299 game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j].supernova:
2300 # Left galaxy or ran into supernova
2304 proutn(_("Lt. Uhura- \"The deep space probe "))
2305 if not game.probe.quadrant().valid_quadrant():
2306 prout(_("has left the galaxy.\""))
2308 prout(_("is no longer transmitting.\""))
2314 prout(_("Lt. Uhura- \"The deep space probe is now in Quadrant %s.\"") % game.probe.quadrant())
2315 pquad = game.probe.quadrant()
2316 pdest = game.state.galaxy[pquad.i][pquad.j]
2318 game.state.chart[pquad.i][pquad.j].klingons = pdest.klingons
2319 game.state.chart[pquad.i][pquad.j].starbase = pdest.starbase
2320 game.state.chart[pquad.i][pquad.j].stars = pdest.stars
2321 pdest.charted = True
2322 game.probe.moves -= 1 # One less to travel
2323 if game.probe.arrived() and game.isarmed and pdest.stars:
2324 supernova(game.probe) # fire in the hole!
2326 if game.state.galaxy[pquad.i][pquad.j].supernova:
2328 elif evcode == FDISTR: # inhabited system issues distress call
2330 # try a whole bunch of times to find something suitable
2331 for i in range(100):
2332 # need a quadrant which is not the current one,
2333 # which has some stars which are inhabited and
2334 # not already under attack, which is not
2335 # supernova'ed, and which has some Klingons in it
2336 w = randplace(GALSIZE)
2337 q = game.state.galaxy[w.i][w.j]
2338 if not (game.quadrant == w or q.planet is None or \
2339 not q.planet.inhabited or \
2340 q.supernova or q.status!="secure" or q.klingons<=0):
2343 # can't seem to find one; ignore this call
2345 prout("=== Couldn't find location for distress event.")
2347 # got one!! Schedule its enslavement
2348 ev = schedule(FENSLV, expran(game.intime))
2350 q.status = "distressed"
2351 # tell the captain about it if we can
2353 prout(_("Uhura- Captain, %s in Quadrant %s reports it is under attack") \
2354 % (q.planet, repr(w)))
2355 prout(_("by a Klingon invasion fleet."))
2358 elif evcode == FENSLV: # starsystem is enslaved
2359 ev = unschedule(FENSLV)
2360 # see if current distress call still active
2361 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2365 q.status = "enslaved"
2367 # play stork and schedule the first baby
2368 ev2 = schedule(FREPRO, expran(2.0 * game.intime))
2369 ev2.quadrant = ev.quadrant
2371 # report the disaster if we can
2373 prout(_("Uhura- We've lost contact with starsystem %s") % \
2375 prout(_("in Quadrant %s.\n") % ev.quadrant)
2376 elif evcode == FREPRO: # Klingon reproduces
2377 # If we ever switch to a real event queue, we'll need to
2378 # explicitly retrieve and restore the x and y.
2379 ev = schedule(FREPRO, expran(1.0 * game.intime))
2380 # see if current distress call still active
2381 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2385 if game.state.remkl >= MAXKLGAME:
2386 continue # full right now
2387 # reproduce one Klingon
2390 if game.klhere >= MAXKLQUAD:
2392 # this quadrant not ok, pick an adjacent one
2393 for m.i in range(w.i - 1, w.i + 2):
2394 for m.j in range(w.j - 1, w.j + 2):
2395 if not m.valid_quadrant():
2397 q = game.state.galaxy[m.i][m.j]
2398 # check for this quad ok (not full & no snova)
2399 if q.klingons >= MAXKLQUAD or q.supernova:
2402 # search for eligible quadrant failed
2407 game.state.remkl += 1
2409 if game.quadrant == w:
2411 game.enemies.append(newkling())
2412 # recompute time left
2415 if game.quadrant == w:
2416 prout(_("Spock- sensors indicate the Klingons have"))
2417 prout(_("launched a warship from %s.") % q.planet)
2419 prout(_("Uhura- Starfleet reports increased Klingon activity"))
2420 if q.planet != None:
2421 proutn(_("near %s ") % q.planet)
2422 prout(_("in Quadrant %s.") % w)
2428 key = scanner.nexttok()
2431 proutn(_("How long? "))
2436 origTime = delay = scanner.real
2439 if delay >= game.state.remtime or len(game.enemies) != 0:
2440 proutn(_("Are you sure? "))
2443 # Alternate resting periods (events) with attacks
2447 game.resting = False
2448 if not game.resting:
2449 prout(_("%d stardates left.") % int(game.state.remtime))
2451 temp = game.optime = delay
2452 if len(game.enemies):
2453 rtime = randreal(1.0, 2.0)
2457 if game.optime < delay:
2458 attack(torps_ok=False)
2466 # Repair Deathray if long rest at starbase
2467 if origTime-delay >= 9.99 and game.condition == "docked":
2468 game.damage[DDRAY] = 0.0
2469 # leave if quadrant supernovas
2470 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2472 game.resting = False
2477 ncourse = (0.0, 10.5, 12.0, 1.5, 9.0, 0.0, 3.0, 7.5, 6.0, 4.5)
2478 newc = Coord(); neighbor = Coord(); bump = Coord(0, 0)
2480 # Wow! We've supernova'ed
2481 supernova(game.quadrant)
2483 # handle initial nova
2484 game.quad[nov.i][nov.j] = '.'
2485 prout(crmena(False, '*', "sector", nov) + _(" novas."))
2486 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2487 game.state.starkl += 1
2488 # Set up queue to recursively trigger adjacent stars
2494 for offset.i in range(-1, 1+1):
2495 for offset.j in range(-1, 1+1):
2496 if offset.j == 0 and offset.i == 0:
2498 neighbor = start + offset
2499 if not neighbor.valid_sector():
2501 iquad = game.quad[neighbor.i][neighbor.j]
2502 # Empty space ends reaction
2503 if iquad in ('.', '?', ' ', 'T', '#'):
2505 elif iquad == '*': # Affect another star
2507 # This star supernovas
2508 supernova(game.quadrant)
2511 hits.append(neighbor)
2512 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2513 game.state.starkl += 1
2514 proutn(crmena(True, '*', "sector", neighbor))
2516 game.quad[neighbor.i][neighbor.j] = '.'
2518 elif iquad in ('P', '@'): # Destroy planet
2519 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
2521 game.state.nplankl += 1
2523 game.state.nworldkl += 1
2524 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2525 game.iplnet.pclass = "destroyed"
2527 game.plnet.invalidate()
2531 game.quad[neighbor.i][neighbor.j] = '.'
2532 elif iquad == 'B': # Destroy base
2533 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
2534 game.state.baseq = [x for x in game.state.baseq if x!= game.quadrant]
2535 game.base.invalidate()
2536 game.state.basekl += 1
2538 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2539 game.quad[neighbor.i][neighbor.j] = '.'
2540 elif iquad in ('E', 'F'): # Buffet ship
2541 prout(_("***Starship buffeted by nova."))
2543 if game.shield >= 2000.0:
2544 game.shield -= 2000.0
2546 diff = 2000.0 - game.shield
2550 prout(_("***Shields knocked out."))
2551 game.damage[DSHIELD] += 0.005*game.damfac*randreal()*diff
2553 game.energy -= 2000.0
2554 if game.energy <= 0:
2557 # add in course nova contributes to kicking starship
2558 bump += (game.sector-hits[-1]).sgn()
2559 elif iquad == 'K': # kill klingon
2560 deadkl(neighbor, iquad, neighbor)
2561 elif iquad in ('C','S','R'): # Damage/destroy big enemies
2563 for ll in range(len(game.enemies)):
2564 if game.enemies[ll].location == neighbor:
2565 target = game.enemies[ll]
2567 if target is not None:
2568 target.power -= 800.0 # If firepower is lost, die
2569 if target.power <= 0.0:
2570 deadkl(neighbor, iquad, neighbor)
2571 continue # neighbor loop
2572 # Else enemy gets flung by the blast wave
2573 newc = neighbor + neighbor - hits[-1]
2574 proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged"))
2575 if not newc.valid_sector():
2576 # can't leave quadrant
2579 iquad1 = game.quad[newc.i][newc.j]
2581 proutn(_(", blasted into ") + crmena(False, ' ', "sector", newc))
2583 deadkl(neighbor, iquad, newc)
2586 # can't move into something else
2589 proutn(_(", buffeted to Sector %s") % newc)
2590 game.quad[neighbor.i][neighbor.j] = '.'
2591 game.quad[newc.i][newc.j] = iquad
2593 # Starship affected by nova -- kick it away.
2595 direc = ncourse[3*(bump.i+1)+bump.j+2]
2600 scourse = course(bearing=direc, distance=dist)
2601 game.optime = scourse.time(w=4)
2603 prout(_("Force of nova displaces starship."))
2604 imove(scourse, noattack=True)
2605 game.optime = scourse.time(w=4)
2609 "Star goes supernova."
2614 # Scheduled supernova -- select star at random.
2617 for nq.i in range(GALSIZE):
2618 for nq.j in range(GALSIZE):
2619 nstars += game.state.galaxy[nq.i][nq.j].stars
2621 return # nothing to supernova exists
2622 num = randrange(nstars) + 1
2623 for nq.i in range(GALSIZE):
2624 for nq.j in range(GALSIZE):
2625 num -= game.state.galaxy[nq.i][nq.j].stars
2631 proutn("=== Super nova here?")
2634 if not nq == game.quadrant or game.justin:
2635 # it isn't here, or we just entered (treat as enroute)
2638 prout(_("Message from Starfleet Command Stardate %.2f") % game.state.date)
2639 prout(_(" Supernova in Quadrant %s; caution advised.") % nq)
2642 # we are in the quadrant!
2643 num = randrange(game.state.galaxy[nq.i][nq.j].stars) + 1
2644 for ns.i in range(QUADSIZE):
2645 for ns.j in range(QUADSIZE):
2646 if game.quad[ns.i][ns.j]=='*':
2653 prouts(_("***RED ALERT! RED ALERT!"))
2655 prout(_("***Incipient supernova detected at Sector %s") % ns)
2656 if (ns.i-game.sector.i)**2 + (ns.j-game.sector.j)**2 <= 2.1:
2657 proutn(_("Emergency override attempts t"))
2658 prouts("***************")
2662 # destroy any Klingons in supernovaed quadrant
2663 kldead = game.state.galaxy[nq.i][nq.j].klingons
2664 game.state.galaxy[nq.i][nq.j].klingons = 0
2665 if nq == game.state.kscmdr:
2666 # did in the Supercommander!
2667 game.state.nscrem = game.state.kscmdr.i = game.state.kscmdr.j = game.isatb = 0
2671 survivors = filter(lambda w: w != nq, game.state.kcmdr)
2672 comkills = len(game.state.kcmdr) - len(survivors)
2673 game.state.kcmdr = survivors
2675 if not game.state.kcmdr:
2677 game.state.remkl -= kldead
2678 # destroy Romulans and planets in supernovaed quadrant
2679 nrmdead = game.state.galaxy[nq.i][nq.j].romulans
2680 game.state.galaxy[nq.i][nq.j].romulans = 0
2681 game.state.nromrem -= nrmdead
2683 for loop in range(game.inplan):
2684 if game.state.planets[loop].quadrant == nq:
2685 game.state.planets[loop].pclass = "destroyed"
2687 # Destroy any base in supernovaed quadrant
2688 game.state.baseq = [x for x in game.state.baseq if x != nq]
2689 # If starship caused supernova, tally up destruction
2691 game.state.starkl += game.state.galaxy[nq.i][nq.j].stars
2692 game.state.basekl += game.state.galaxy[nq.i][nq.j].starbase
2693 game.state.nplankl += npdead
2694 # mark supernova in galaxy and in star chart
2695 if game.quadrant == nq or communicating():
2696 game.state.galaxy[nq.i][nq.j].supernova = True
2697 # If supernova destroys last Klingons give special message
2698 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0 and not nq == game.quadrant:
2701 prout(_("Lucky you!"))
2702 proutn(_("A supernova in %s has just destroyed the last Klingons.") % nq)
2705 # if some Klingons remain, continue or die in supernova
2710 # Code from finish.c ends here.
2713 "Self-destruct maneuver. Finish with a BANG!"
2715 if damaged(DCOMPTR):
2716 prout(_("Computer damaged; cannot execute destruct sequence."))
2718 prouts(_("---WORKING---")); skip(1)
2719 prouts(_("SELF-DESTRUCT-SEQUENCE-ACTIVATED")); skip(1)
2720 prouts(" 10"); skip(1)
2721 prouts(" 9"); skip(1)
2722 prouts(" 8"); skip(1)
2723 prouts(" 7"); skip(1)
2724 prouts(" 6"); skip(1)
2726 prout(_("ENTER-CORRECT-PASSWORD-TO-CONTINUE-"))
2728 prout(_("SELF-DESTRUCT-SEQUENCE-OTHERWISE-"))
2730 prout(_("SELF-DESTRUCT-SEQUENCE-WILL-BE-ABORTED"))
2733 if game.passwd != scanner.token:
2734 prouts(_("PASSWORD-REJECTED;"))
2736 prouts(_("CONTINUITY-EFFECTED"))
2739 prouts(_("PASSWORD-ACCEPTED")); skip(1)
2740 prouts(" 5"); skip(1)
2741 prouts(" 4"); skip(1)
2742 prouts(" 3"); skip(1)
2743 prouts(" 2"); skip(1)
2744 prouts(" 1"); skip(1)
2746 prouts(_("GOODBYE-CRUEL-WORLD"))
2754 prouts(_("********* Entropy of %s maximized *********") % crmshp())
2758 if len(game.enemies) != 0:
2759 whammo = 25.0 * game.energy
2760 for l in range(len(game.enemies)):
2761 if game.enemies[l].power*game.enemies[l].kdist <= whammo:
2762 deadkl(game.enemies[l].location, game.quad[game.enemies[l].location.i][game.enemies[l].location.j], game.enemies[l].location)
2766 "Compute our rate of kils over time."
2767 elapsed = game.state.date - game.indate
2768 if elapsed == 0: # Avoid divide-by-zero error if calculated on turn 0
2771 starting = (game.inkling + game.incom + game.inscom)
2772 remaining = (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)
2773 return (starting - remaining)/elapsed
2777 badpt = 5.0*game.state.starkl + \
2779 10.0*game.state.nplankl + \
2780 300*game.state.nworldkl + \
2782 100.0*game.state.basekl +\
2784 if game.ship == 'F':
2786 elif game.ship is None:
2791 # end the game, with appropriate notfications
2795 prout(_("It is stardate %.1f.") % game.state.date)
2797 if ifin == FWON: # Game has been won
2798 if game.state.nromrem != 0:
2799 prout(_("The remaining %d Romulans surrender to Starfleet Command.") %
2802 prout(_("You have smashed the Klingon invasion fleet and saved"))
2803 prout(_("the Federation."))
2808 badpt = 0.0 # Close enough!
2809 # killsPerDate >= RateMax
2810 if game.state.date-game.indate < 5.0 or \
2811 killrate() >= 0.1*game.skill*(game.skill+1.0) + 0.1 + 0.008*badpt:
2813 prout(_("In fact, you have done so well that Starfleet Command"))
2814 if game.skill == SKILL_NOVICE:
2815 prout(_("promotes you one step in rank from \"Novice\" to \"Fair\"."))
2816 elif game.skill == SKILL_FAIR:
2817 prout(_("promotes you one step in rank from \"Fair\" to \"Good\"."))
2818 elif game.skill == SKILL_GOOD:
2819 prout(_("promotes you one step in rank from \"Good\" to \"Expert\"."))
2820 elif game.skill == SKILL_EXPERT:
2821 prout(_("promotes you to Commodore Emeritus."))
2823 prout(_("Now that you think you're really good, try playing"))
2824 prout(_("the \"Emeritus\" game. It will splatter your ego."))
2825 elif game.skill == SKILL_EMERITUS:
2827 proutn(_("Computer- "))
2828 prouts(_("ERROR-ERROR-ERROR-ERROR"))
2830 prouts(_(" YOUR-SKILL-HAS-EXCEEDED-THE-CAPACITY-OF-THIS-PROGRAM"))
2832 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2834 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2836 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2838 prouts(_(" THIS-PROGRAM-MUST?- MUST ? - SUR? ? -? VI"))
2840 prout(_("Now you can retire and write your own Star Trek game!"))
2842 elif game.skill >= SKILL_EXPERT:
2843 if game.thawed and not game.idebug:
2844 prout(_("You cannot get a citation, so..."))
2846 proutn(_("Do you want your Commodore Emeritus Citation printed? "))
2850 # Only grant long life if alive (original didn't!)
2852 prout(_("LIVE LONG AND PROSPER."))
2857 elif ifin == FDEPLETE: # Federation Resources Depleted
2858 prout(_("Your time has run out and the Federation has been"))
2859 prout(_("conquered. Your starship is now Klingon property,"))
2860 prout(_("and you are put on trial as a war criminal. On the"))
2861 proutn(_("basis of your record, you are "))
2862 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)*3.0 > (game.inkling + game.incom + game.inscom):
2863 prout(_("acquitted."))
2865 prout(_("LIVE LONG AND PROSPER."))
2867 prout(_("found guilty and"))
2868 prout(_("sentenced to death by slow torture."))
2872 elif ifin == FLIFESUP:
2873 prout(_("Your life support reserves have run out, and"))
2874 prout(_("you die of thirst, starvation, and asphyxiation."))
2875 prout(_("Your starship is a derelict in space."))
2877 prout(_("Your energy supply is exhausted."))
2879 prout(_("Your starship is a derelict in space."))
2880 elif ifin == FBATTLE:
2881 prout(_("The %s has been destroyed in battle.") % crmshp())
2883 prout(_("Dulce et decorum est pro patria mori."))
2885 prout(_("You have made three attempts to cross the negative energy"))
2886 prout(_("barrier which surrounds the galaxy."))
2888 prout(_("Your navigation is abominable."))
2891 prout(_("Your starship has been destroyed by a nova."))
2892 prout(_("That was a great shot."))
2894 elif ifin == FSNOVAED:
2895 prout(_("The %s has been fried by a supernova.") % crmshp())
2896 prout(_("...Not even cinders remain..."))
2897 elif ifin == FABANDN:
2898 prout(_("You have been captured by the Klingons. If you still"))
2899 prout(_("had a starbase to be returned to, you would have been"))
2900 prout(_("repatriated and given another chance. Since you have"))
2901 prout(_("no starbases, you will be mercilessly tortured to death."))
2902 elif ifin == FDILITHIUM:
2903 prout(_("Your starship is now an expanding cloud of subatomic particles"))
2904 elif ifin == FMATERIALIZE:
2905 prout(_("Starbase was unable to re-materialize your starship."))
2906 prout(_("Sic transit gloria mundi"))
2907 elif ifin == FPHASER:
2908 prout(_("The %s has been cremated by its own phasers.") % crmshp())
2910 prout(_("You and your landing party have been"))
2911 prout(_("converted to energy, disipating through space."))
2912 elif ifin == FMINING:
2913 prout(_("You are left with your landing party on"))
2914 prout(_("a wild jungle planet inhabited by primitive cannibals."))
2916 prout(_("They are very fond of \"Captain Kirk\" soup."))
2918 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
2919 elif ifin == FDPLANET:
2920 prout(_("You and your mining party perish."))
2922 prout(_("That was a great shot."))
2925 prout(_("The Galileo is instantly annihilated by the supernova."))
2926 prout(_("You and your mining party are atomized."))
2928 prout(_("Mr. Spock takes command of the %s and") % crmshp())
2929 prout(_("joins the Romulans, wreaking terror on the Federation."))
2930 elif ifin == FPNOVA:
2931 prout(_("You and your mining party are atomized."))
2933 prout(_("Mr. Spock takes command of the %s and") % crmshp())
2934 prout(_("joins the Romulans, wreaking terror on the Federation."))
2935 elif ifin == FSTRACTOR:
2936 prout(_("The shuttle craft Galileo is also caught,"))
2937 prout(_("and breaks up under the strain."))
2939 prout(_("Your debris is scattered for millions of miles."))
2940 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
2942 prout(_("The mutants attack and kill Spock."))
2943 prout(_("Your ship is captured by Klingons, and"))
2944 prout(_("your crew is put on display in a Klingon zoo."))
2945 elif ifin == FTRIBBLE:
2946 prout(_("Tribbles consume all remaining water,"))
2947 prout(_("food, and oxygen on your ship."))
2949 prout(_("You die of thirst, starvation, and asphyxiation."))
2950 prout(_("Your starship is a derelict in space."))
2952 prout(_("Your ship is drawn to the center of the black hole."))
2953 prout(_("You are crushed into extremely dense matter."))
2955 prout(_("Your last crew member has died."))
2956 if game.ship == 'F':
2958 elif game.ship == 'E':
2961 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0:
2962 goodies = game.state.remres/game.inresor
2963 baddies = (game.state.remkl + 2.0*len(game.state.kcmdr))/(game.inkling+2.0*game.incom)
2964 if goodies/baddies >= randreal(1.0, 1.5):
2965 prout(_("As a result of your actions, a treaty with the Klingon"))
2966 prout(_("Empire has been signed. The terms of the treaty are"))
2967 if goodies/baddies >= randreal(3.0):
2968 prout(_("favorable to the Federation."))
2970 prout(_("Congratulations!"))
2972 prout(_("highly unfavorable to the Federation."))
2974 prout(_("The Federation will be destroyed."))
2976 prout(_("Since you took the last Klingon with you, you are a"))
2977 prout(_("martyr and a hero. Someday maybe they'll erect a"))
2978 prout(_("statue in your memory. Rest in peace, and try not"))
2979 prout(_("to think about pigeons."))
2984 "Compute player's score."
2985 timused = game.state.date - game.indate
2986 if (timused == 0 or (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0) and timused < 5.0:
2988 game.perdate = killrate()
2989 ithperd = 500*game.perdate + 0.5
2992 iwon = 100*game.skill
2993 if game.ship == 'E':
2995 elif game.ship == 'F':
2999 game.score = 10*(game.inkling - game.state.remkl) \
3000 + 50*(game.incom - len(game.state.kcmdr)) \
3002 + 20*(game.inrom - game.state.nromrem) \
3003 + 200*(game.inscom - game.state.nscrem) \
3004 - game.state.nromrem \
3009 prout(_("Your score --"))
3010 if game.inrom - game.state.nromrem:
3011 prout(_("%6d Romulans destroyed %5d") %
3012 (game.inrom - game.state.nromrem, 20*(game.inrom - game.state.nromrem)))
3013 if game.state.nromrem and game.gamewon:
3014 prout(_("%6d Romulans captured %5d") %
3015 (game.state.nromrem, game.state.nromrem))
3016 if game.inkling - game.state.remkl:
3017 prout(_("%6d ordinary Klingons destroyed %5d") %
3018 (game.inkling - game.state.remkl, 10*(game.inkling - game.state.remkl)))
3019 if game.incom - len(game.state.kcmdr):
3020 prout(_("%6d Klingon commanders destroyed %5d") %
3021 (game.incom - len(game.state.kcmdr), 50*(game.incom - len(game.state.kcmdr))))
3022 if game.inscom - game.state.nscrem:
3023 prout(_("%6d Super-Commander destroyed %5d") %
3024 (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem)))
3026 prout(_("%6.2f Klingons per stardate %5d") %
3027 (game.perdate, ithperd))
3028 if game.state.starkl:
3029 prout(_("%6d stars destroyed by your action %5d") %
3030 (game.state.starkl, -5*game.state.starkl))
3031 if game.state.nplankl:
3032 prout(_("%6d planets destroyed by your action %5d") %
3033 (game.state.nplankl, -10*game.state.nplankl))
3034 if (game.options & OPTION_WORLDS) and game.state.nworldkl:
3035 prout(_("%6d inhabited planets destroyed by your action %5d") %
3036 (game.state.nworldkl, -300*game.state.nworldkl))
3037 if game.state.basekl:
3038 prout(_("%6d bases destroyed by your action %5d") %
3039 (game.state.basekl, -100*game.state.basekl))
3041 prout(_("%6d calls for help from starbase %5d") %
3042 (game.nhelp, -45*game.nhelp))
3044 prout(_("%6d casualties incurred %5d") %
3045 (game.casual, -game.casual))
3047 prout(_("%6d crew abandoned in space %5d") %
3048 (game.abandoned, -3*game.abandoned))
3050 prout(_("%6d ship(s) lost or destroyed %5d") %
3051 (klship, -100*klship))
3053 prout(_("Penalty for getting yourself killed -200"))
3055 proutn(_("Bonus for winning "))
3056 if game.skill == SKILL_NOVICE: proutn(_("Novice game "))
3057 elif game.skill == SKILL_FAIR: proutn(_("Fair game "))
3058 elif game.skill == SKILL_GOOD: proutn(_("Good game "))
3059 elif game.skill == SKILL_EXPERT: proutn(_("Expert game "))
3060 elif game.skill == SKILL_EMERITUS: proutn(_("Emeritus game"))
3061 prout(" %5d" % iwon)
3063 prout(_("TOTAL SCORE %5d") % game.score)
3066 "Emit winner's commemmorative plaque."
3069 proutn(_("File or device name for your plaque: "))
3072 fp = open(winner, "w")
3075 prout(_("Invalid name."))
3077 proutn(_("Enter name to go on plaque (up to 30 characters): "))
3079 # The 38 below must be 64 for 132-column paper
3080 nskip = 38 - len(winner)/2
3081 fp.write("\n\n\n\n")
3082 # --------DRAW ENTERPRISE PICTURE.
3083 fp.write(" EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n" )
3084 fp.write(" EEE E : : : E\n" )
3085 fp.write(" EE EEE E : : NCC-1701 : E\n")
3086 fp.write("EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEE : : : E\n")
3087 fp.write(" E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n")
3088 fp.write(" EEEEEEEEE EEEEEEEEEEEEE E E\n")
3089 fp.write(" EEEEEEE EEEEE E E E E\n")
3090 fp.write(" EEE E E E E\n")
3091 fp.write(" E E E E\n")
3092 fp.write(" EEEEEEEEEEEEE E E\n")
3093 fp.write(" EEE : EEEEEEE EEEEEEEE\n")
3094 fp.write(" :E : EEEE E\n")
3095 fp.write(" .-E -:----- E\n")
3096 fp.write(" :E : E\n")
3097 fp.write(" EE : EEEEEEEE\n")
3098 fp.write(" EEEEEEEEEEEEEEEEEEEEEEE\n")
3100 fp.write(_(" U. S. S. ENTERPRISE\n"))
3101 fp.write("\n\n\n\n")
3102 fp.write(_(" For demonstrating outstanding ability as a starship captain\n"))
3104 fp.write(_(" Starfleet Command bestows to you\n"))
3106 fp.write("%*s%s\n\n" % (nskip, "", winner))
3107 fp.write(_(" the rank of\n\n"))
3108 fp.write(_(" \"Commodore Emeritus\"\n\n"))
3110 if game.skill == SKILL_EXPERT:
3111 fp.write(_(" Expert level\n\n"))
3112 elif game.skill == SKILL_EMERITUS:
3113 fp.write(_("Emeritus level\n\n"))
3115 fp.write(_(" Cheat level\n\n"))
3116 timestring = time.ctime()
3117 fp.write(_(" This day of %.6s %.4s, %.8s\n\n") %
3118 (timestring+4, timestring+20, timestring+11))
3119 fp.write(_(" Your score: %d\n\n") % game.score)
3120 fp.write(_(" Klingons per stardate: %.2f\n") % game.perdate)
3123 # Code from io.c begins here
3125 rows = linecount = 0 # for paging
3128 fullscreen_window = None
3129 srscan_window = None # Short range scan
3130 report_window = None # Report legends for status window
3131 status_window = None # The status window itself
3132 lrscan_window = None # Long range scan
3133 message_window = None # Main window for scrolling text
3134 prompt_window = None # Prompt window at bottom of display
3139 # for some recent versions of python2, the following enables UTF8
3140 # for the older ones we probably need to set C locale, and python3
3141 # has no problems at all
3142 if sys.version_info[0] < 3:
3143 locale.setlocale(locale.LC_ALL, "")
3144 gettext.bindtextdomain("sst", "/usr/local/share/locale")
3145 gettext.textdomain("sst")
3146 if not (game.options & OPTION_CURSES):
3147 ln_env = os.getenv("LINES")
3153 stdscr = curses.initscr()
3157 if game.options & OPTION_COLOR:
3158 curses.start_color()
3159 curses.use_default_colors()
3160 curses.init_pair(curses.COLOR_BLACK, curses.COLOR_BLACK, -1)
3161 curses.init_pair(curses.COLOR_GREEN, curses.COLOR_GREEN, -1)
3162 curses.init_pair(curses.COLOR_RED, curses.COLOR_RED, -1)
3163 curses.init_pair(curses.COLOR_CYAN, curses.COLOR_CYAN, -1)
3164 curses.init_pair(curses.COLOR_WHITE, curses.COLOR_WHITE, -1)
3165 curses.init_pair(curses.COLOR_MAGENTA, curses.COLOR_MAGENTA, -1)
3166 curses.init_pair(curses.COLOR_BLUE, curses.COLOR_BLUE, -1)
3167 curses.init_pair(curses.COLOR_YELLOW, curses.COLOR_YELLOW, -1)
3168 global fullscreen_window, srscan_window, report_window, status_window
3169 global lrscan_window, message_window, prompt_window
3170 (rows, _columns) = stdscr.getmaxyx()
3171 fullscreen_window = stdscr
3172 srscan_window = curses.newwin(12, 25, 0, 0)
3173 report_window = curses.newwin(11, 0, 1, 25)
3174 status_window = curses.newwin(10, 0, 1, 39)
3175 lrscan_window = curses.newwin(5, 0, 0, 64)
3176 message_window = curses.newwin(0, 0, 12, 0)
3177 prompt_window = curses.newwin(1, 0, rows-2, 0)
3178 message_window.scrollok(True)
3179 setwnd(fullscreen_window)
3183 if game.options & OPTION_CURSES:
3184 stdscr.keypad(False)
3190 "Wait for user action -- OK to do nothing if on a TTY"
3191 if game.options & OPTION_CURSES:
3196 prouts(_("[ANNOUNCEMENT ARRIVING...]"))
3200 if game.skill > SKILL_FAIR:
3201 prompt = _("[CONTINUE?]")
3203 prompt = _("[PRESS ENTER TO CONTINUE]")
3205 if game.options & OPTION_CURSES:
3207 setwnd(prompt_window)
3208 prompt_window.clear()
3209 prompt_window.addstr(prompt)
3210 prompt_window.getstr()
3211 prompt_window.clear()
3212 prompt_window.refresh()
3213 setwnd(message_window)
3216 sys.stdout.write('\n')
3220 sys.stdout.write('\n' * rows)
3224 "Skip i lines. Pause game if this would cause a scrolling event."
3225 for _dummy in range(i):
3226 if game.options & OPTION_CURSES:
3227 (y, _x) = curwnd.getyx()
3230 except curses.error:
3235 if rows and linecount >= rows:
3238 sys.stdout.write('\n')
3240 def proutn(proutntline):
3241 "Utter a line with no following line feed."
3242 if game.options & OPTION_CURSES:
3243 (y, x) = curwnd.getyx()
3244 (my, _mx) = curwnd.getmaxyx()
3245 if curwnd == message_window and y >= my - 2:
3248 # Uncomment this to debug curses problems
3250 logfp.write("#curses: at %s proutn(%s)\n" % ((y, x), repr(proutntline)))
3251 curwnd.addstr(proutntline)
3254 sys.stdout.write(proutntline)
3257 def prout(proutline):
3261 def prouts(proutsline):
3263 for c in proutsline:
3264 if not replayfp or replayfp.closed: # Don't slow down replays
3267 if game.options & OPTION_CURSES:
3271 if not replayfp or replayfp.closed:
3275 "Get a line of input."
3276 if game.options & OPTION_CURSES:
3277 linein = curwnd.getstr() + "\n"
3280 if replayfp and not replayfp.closed:
3282 linein = replayfp.readline()
3285 prout("*** Replay finished")
3288 elif linein[0] != "#":
3291 linein = eval(input()) + "\n"
3297 "Change windows -- OK for this to be a no-op in tty mode."
3299 if game.options & OPTION_CURSES:
3300 # Uncomment this to debug curses problems
3302 if wnd == fullscreen_window:
3303 legend = "fullscreen"
3304 elif wnd == srscan_window:
3306 elif wnd == report_window:
3308 elif wnd == status_window:
3310 elif wnd == lrscan_window:
3312 elif wnd == message_window:
3314 elif wnd == prompt_window:
3318 logfp.write("#curses: setwnd(%s)\n" % legend)
3320 # Some curses implementations get confused when you try this.
3322 curses.curs_set(wnd in (fullscreen_window, message_window, prompt_window))
3323 except curses.error:
3327 "Clear to end of line -- can be a no-op in tty mode"
3328 if game.options & OPTION_CURSES:
3333 "Clear screen -- can be a no-op in tty mode."
3335 if game.options & OPTION_CURSES:
3341 def textcolor(color=DEFAULT):
3342 if game.options & OPTION_COLOR:
3343 if color == DEFAULT:
3345 elif color == BLACK:
3346 curwnd.attron(curses.color_pair(curses.COLOR_BLACK))
3348 curwnd.attron(curses.color_pair(curses.COLOR_BLUE))
3349 elif color == GREEN:
3350 curwnd.attron(curses.color_pair(curses.COLOR_GREEN))
3352 curwnd.attron(curses.color_pair(curses.COLOR_CYAN))
3354 curwnd.attron(curses.color_pair(curses.COLOR_RED))
3355 elif color == MAGENTA:
3356 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA))
3357 elif color == BROWN:
3358 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW))
3359 elif color == LIGHTGRAY:
3360 curwnd.attron(curses.color_pair(curses.COLOR_WHITE))
3361 elif color == DARKGRAY:
3362 curwnd.attron(curses.color_pair(curses.COLOR_BLACK) | curses.A_BOLD)
3363 elif color == LIGHTBLUE:
3364 curwnd.attron(curses.color_pair(curses.COLOR_BLUE) | curses.A_BOLD)
3365 elif color == LIGHTGREEN:
3366 curwnd.attron(curses.color_pair(curses.COLOR_GREEN) | curses.A_BOLD)
3367 elif color == LIGHTCYAN:
3368 curwnd.attron(curses.color_pair(curses.COLOR_CYAN) | curses.A_BOLD)
3369 elif color == LIGHTRED:
3370 curwnd.attron(curses.color_pair(curses.COLOR_RED) | curses.A_BOLD)
3371 elif color == LIGHTMAGENTA:
3372 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA) | curses.A_BOLD)
3373 elif color == YELLOW:
3374 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW) | curses.A_BOLD)
3375 elif color == WHITE:
3376 curwnd.attron(curses.color_pair(curses.COLOR_WHITE) | curses.A_BOLD)
3379 if game.options & OPTION_COLOR:
3380 curwnd.attron(curses.A_REVERSE)
3383 # Things past this point have policy implications.
3387 "Hook to be called after moving to redraw maps."
3388 if game.options & OPTION_CURSES:
3391 setwnd(srscan_window)
3395 setwnd(status_window)
3396 status_window.clear()
3397 status_window.move(0, 0)
3398 setwnd(report_window)
3399 report_window.clear()
3400 report_window.move(0, 0)
3402 setwnd(lrscan_window)
3403 lrscan_window.clear()
3404 lrscan_window.move(0, 0)
3405 lrscan(silent=False)
3407 def put_srscan_sym(w, sym):
3408 "Emit symbol for short-range scan."
3409 srscan_window.move(w.i+1, w.j*2+2)
3410 srscan_window.addch(sym)
3411 srscan_window.refresh()
3414 "Enemy fall down, go boom."
3415 if game.options & OPTION_CURSES:
3417 setwnd(srscan_window)
3418 srscan_window.attron(curses.A_REVERSE)
3419 put_srscan_sym(w, game.quad[w.i][w.j])
3423 srscan_window.attroff(curses.A_REVERSE)
3424 put_srscan_sym(w, game.quad[w.i][w.j])
3425 curses.delay_output(500)
3426 setwnd(message_window)
3429 "Sound and visual effects for teleportation."
3430 if game.options & OPTION_CURSES:
3432 setwnd(message_window)
3434 prouts(" . . . . . ")
3435 if game.options & OPTION_CURSES:
3436 #curses.delay_output(1000)
3440 def tracktorpedo(w, step, i, n, iquad):
3441 "Torpedo-track animation."
3442 if not game.options & OPTION_CURSES:
3446 proutn(_("Track for torpedo number %d- ") % (i+1))
3449 proutn(_("Torpedo track- "))
3450 elif step==4 or step==9:
3454 if not damaged(DSRSENS) or game.condition=="docked":
3455 if i != 0 and step == 1:
3458 if (iquad=='.') or (iquad==' '):
3459 put_srscan_sym(w, '+')
3463 put_srscan_sym(w, iquad)
3465 curwnd.attron(curses.A_REVERSE)
3466 put_srscan_sym(w, iquad)
3470 curwnd.attroff(curses.A_REVERSE)
3471 put_srscan_sym(w, iquad)
3476 "Display the current galaxy chart."
3477 if game.options & OPTION_CURSES:
3478 setwnd(message_window)
3479 message_window.clear()
3481 if game.options & OPTION_TTY:
3486 def prstat(txt, data):
3488 if game.options & OPTION_CURSES:
3490 setwnd(status_window)
3492 proutn(" " * (NSYM - len(txt)))
3495 if game.options & OPTION_CURSES:
3496 setwnd(report_window)
3498 # Code from moving.c begins here
3500 def imove(icourse=None, noattack=False):
3501 "Movement execution for warp, impulse, supernova, and tractor-beam events."
3504 def newquadrant(noattack):
3505 # Leaving quadrant -- allow final enemy attack
3506 # Don't do it if being pushed by Nova
3507 if len(game.enemies) != 0 and not noattack:
3509 for enemy in game.enemies:
3510 finald = (w - enemy.location).distance()
3511 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3512 # Stas Sergeev added the condition
3513 # that attacks only happen if Klingons
3514 # are present and your skill is good.
3515 if game.skill > SKILL_GOOD and game.klhere > 0 and not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3516 attack(torps_ok=False)
3519 # check for edge of galaxy
3525 if icourse.final.i < 0:
3526 icourse.final.i = -icourse.final.i
3528 if icourse.final.j < 0:
3529 icourse.final.j = -icourse.final.j
3531 if icourse.final.i >= GALSIZE*QUADSIZE:
3532 icourse.final.i = (GALSIZE*QUADSIZE*2) - icourse.final.i
3534 if icourse.final.j >= GALSIZE*QUADSIZE:
3535 icourse.final.j = (GALSIZE*QUADSIZE*2) - icourse.final.j
3543 if game.nkinks == 3:
3544 # Three strikes -- you're out!
3548 prout(_("YOU HAVE ATTEMPTED TO CROSS THE NEGATIVE ENERGY BARRIER"))
3549 prout(_("AT THE EDGE OF THE GALAXY. THE THIRD TIME YOU TRY THIS,"))
3550 prout(_("YOU WILL BE DESTROYED."))
3551 # Compute final position in new quadrant
3552 if trbeam: # Don't bother if we are to be beamed
3554 game.quadrant = icourse.final.quadrant()
3555 game.sector = icourse.final.sector()
3557 prout(_("Entering Quadrant %s.") % game.quadrant)
3558 game.quad[game.sector.i][game.sector.j] = game.ship
3560 if game.skill>SKILL_NOVICE:
3561 attack(torps_ok=False)
3563 def check_collision(h):
3564 iquad = game.quad[h.i][h.j]
3566 # object encountered in flight path
3567 stopegy = 50.0*icourse.distance/game.optime
3568 if iquad in ('T', 'K', 'C', 'S', 'R', '?'):
3569 for enemy in game.enemies:
3570 if enemy.location == game.sector:
3571 collision(rammed=False, enemy=enemy)
3573 # This should not happen
3574 prout(_("Which way did he go?"))
3578 prouts(_("***RED ALERT! RED ALERT!"))
3580 proutn("***" + crmshp())
3581 proutn(_(" pulled into black hole at Sector %s") % h)
3582 # Getting pulled into a black hole was certain
3583 # death in Almy's original. Stas Sergeev added a
3584 # possibility that you'll get timewarped instead.
3586 for m in range(NDEVICES):
3587 if game.damage[m]>0:
3589 probf=math.pow(1.4,(game.energy+game.shield)/5000.0-1.0)*math.pow(1.3,1.0/(n+1)-1.0)
3590 if (game.options & OPTION_BLKHOLE) and withprob(1-probf):
3600 prout(_(" encounters Tholian web at %s;") % h)
3602 prout(_(" blocked by object at %s;") % h)
3603 proutn(_("Emergency stop required "))
3604 prout(_("%2d units of energy.") % int(stopegy))
3605 game.energy -= stopegy
3606 if game.energy <= 0:
3613 prout(_("Helmsman Sulu- \"Leaving standard orbit.\""))
3614 game.inorbit = False
3615 # If tractor beam is to occur, don't move full distance
3616 if game.state.date+game.optime >= scheduled(FTBEAM):
3618 game.condition = "red"
3619 icourse.distance = icourse.distance*(scheduled(FTBEAM)-game.state.date)/game.optime + 0.1
3620 game.optime = scheduled(FTBEAM) - game.state.date + 1e-5
3622 game.quad[game.sector.i][game.sector.j] = '.'
3623 for _m in range(icourse.moves):
3625 w = icourse.sector()
3626 if icourse.origin.quadrant() != icourse.location.quadrant():
3627 newquadrant(noattack)
3629 elif check_collision(w):
3630 print("Collision detected")
3634 # We're in destination quadrant -- compute new average enemy distances
3635 game.quad[game.sector.i][game.sector.j] = game.ship
3637 for enemy in game.enemies:
3638 finald = (w-enemy.location).distance()
3639 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3640 enemy.kdist = finald
3642 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3643 attack(torps_ok=False)
3644 for enemy in game.enemies:
3645 enemy.kavgd = enemy.kdist
3648 setwnd(message_window)
3652 "Dock our ship at a starbase."
3654 if game.condition == "docked" and verbose:
3655 prout(_("Already docked."))
3658 prout(_("You must first leave standard orbit."))
3660 if not game.base.is_valid() or abs(game.sector.i-game.base.i) > 1 or abs(game.sector.j-game.base.j) > 1:
3661 prout(crmshp() + _(" not adjacent to base."))
3663 game.condition = "docked"
3667 if game.energy < game.inenrg:
3668 game.energy = game.inenrg
3669 game.shield = game.inshld
3670 game.torps = game.intorps
3671 game.lsupres = game.inlsr
3672 game.state.crew = FULLCREW
3673 if not damaged(DRADIO) and \
3674 ((is_scheduled(FCDBAS) or game.isatb == 1) and not game.iseenit):
3675 # get attack report from base
3676 prout(_("Lt. Uhura- \"Captain, an important message from the starbase:\""))
3680 def cartesian(loc1=None, loc2=None):
3682 return game.quadrant * QUADSIZE + game.sector
3684 return game.quadrant * QUADSIZE + loc1
3686 return loc1 * QUADSIZE + loc2
3688 def getcourse(isprobe):
3689 "Get a course and distance from the user."
3691 dquad = copy.copy(game.quadrant)
3692 navmode = "unspecified"
3696 if game.landed and not isprobe:
3697 prout(_("Dummy! You can't leave standard orbit until you"))
3698 proutn(_("are back aboard the ship."))
3701 while navmode == "unspecified":
3702 if damaged(DNAVSYS):
3704 prout(_("Computer damaged; manual navigation only"))
3706 prout(_("Computer damaged; manual movement only"))
3711 key = scanner.nexttok()
3713 proutn(_("Manual or automatic- "))
3716 elif key == "IHALPHA":
3717 if scanner.sees("manual"):
3719 key = scanner.nexttok()
3721 elif scanner.sees("automatic"):
3722 navmode = "automatic"
3723 key = scanner.nexttok()
3731 prout(_("(Manual navigation assumed.)"))
3733 prout(_("(Manual movement assumed.)"))
3737 if navmode == "automatic":
3738 while key == "IHEOL":
3740 proutn(_("Target quadrant or quadrant§or- "))
3742 proutn(_("Destination sector or quadrant§or- "))
3745 key = scanner.nexttok()
3749 xi = int(round(scanner.real))-1
3750 key = scanner.nexttok()
3754 xj = int(round(scanner.real))-1
3755 key = scanner.nexttok()
3757 # both quadrant and sector specified
3758 xk = int(round(scanner.real))-1
3759 key = scanner.nexttok()
3763 xl = int(round(scanner.real))-1
3769 # only one pair of numbers was specified
3771 # only quadrant specified -- go to center of dest quad
3774 dsect.j = dsect.i = 4 # preserves 1-origin behavior
3776 # only sector specified
3780 if not dquad.valid_quadrant() or not dsect.valid_sector():
3787 prout(_("Helmsman Sulu- \"Course locked in for Sector %s.\"") % dsect)
3789 prout(_("Ensign Chekov- \"Course laid in, Captain.\""))
3790 # the actual deltas get computed here
3791 delta.j = dquad.j-game.quadrant.j + (dsect.j-game.sector.j)/(QUADSIZE*1.0)
3792 delta.i = game.quadrant.i-dquad.i + (game.sector.i-dsect.i)/(QUADSIZE*1.0)
3794 while key == "IHEOL":
3795 proutn(_("X and Y displacements- "))
3798 key = scanner.nexttok()
3803 delta.j = scanner.real
3804 key = scanner.nexttok()
3808 delta.i = scanner.real
3809 # Check for zero movement
3810 if delta.i == 0 and delta.j == 0:
3813 if itemp == "verbose" and not isprobe:
3815 prout(_("Helmsman Sulu- \"Aye, Sir.\""))
3817 return course(bearing=delta.bearing(), distance=delta.distance())
3820 def __init__(self, bearing, distance, origin=None):
3821 self.distance = distance
3822 self.bearing = bearing
3824 self.origin = cartesian(game.quadrant, game.sector)
3826 self.origin = origin
3827 # The bearing() code we inherited from FORTRAN is actually computing
3828 # clockface directions!
3829 if self.bearing < 0.0:
3830 self.bearing += 12.0
3831 self.angle = ((15.0 - self.bearing) * 0.5235988)
3832 self.increment = Coord(-math.sin(self.angle), math.cos(self.angle))
3833 bigger = max(abs(self.increment.i), abs(self.increment.j))
3834 self.increment /= bigger
3835 self.moves = int(round(10*self.distance*bigger))
3837 self.final = (self.location + self.moves*self.increment).roundtogrid()
3838 self.location = self.origin
3839 self.nextlocation = None
3841 self.location = self.origin
3844 return self.location.roundtogrid() == self.final
3846 "Next step on course."
3848 self.nextlocation = self.location + self.increment
3849 samequad = (self.location.quadrant() == self.nextlocation.quadrant())
3850 self.location = self.nextlocation
3853 return self.location.quadrant()
3855 return self.location.sector()
3857 return self.distance*(w**3)*(game.shldup+1)
3859 return 10.0*self.distance/w**2
3862 "Move under impulse power."
3864 if damaged(DIMPULS):
3867 prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
3869 if game.energy > 30.0:
3871 icourse = getcourse(isprobe=False)
3874 power = 20.0 + 100.0*icourse.distance
3877 if power >= game.energy:
3878 # Insufficient power for trip
3880 prout(_("First Officer Spock- \"Captain, the impulse engines"))
3881 prout(_("require 20.0 units to engage, plus 100.0 units per"))
3882 if game.energy > 30:
3883 proutn(_("quadrant. We can go, therefore, a maximum of %d") %
3884 int(0.01 * (game.energy-20.0)-0.05))
3885 prout(_(" quadrants.\""))
3887 prout(_("quadrant. They are, therefore, useless.\""))
3890 # Make sure enough time is left for the trip
3891 game.optime = icourse.distance/0.095
3892 if game.optime >= game.state.remtime:
3893 prout(_("First Officer Spock- \"Captain, our speed under impulse"))
3894 prout(_("power is only 0.95 sectors per stardate. Are you sure"))
3895 proutn(_("we dare spend the time?\" "))
3898 # Activate impulse engines and pay the cost
3899 imove(icourse, noattack=False)
3903 power = 20.0 + 100.0*icourse.distance
3904 game.energy -= power
3905 game.optime = icourse.distance/0.095
3906 if game.energy <= 0:
3910 def warp(wcourse, involuntary):
3911 "ove under warp drive."
3912 blooey = False; twarp = False
3913 if not involuntary: # Not WARPX entry
3915 if game.damage[DWARPEN] > 10.0:
3918 prout(_("Engineer Scott- \"The warp engines are damaged, Sir.\""))
3920 if damaged(DWARPEN) and game.warpfac > 4.0:
3923 prout(_("Engineer Scott- \"Sorry, Captain. Until this damage"))
3924 prout(_(" is repaired, I can only give you warp 4.\""))
3926 # Read in course and distance
3929 wcourse = getcourse(isprobe=False)
3932 # Make sure starship has enough energy for the trip
3933 # Note: this formula is slightly different from the C version,
3934 # and lets you skate a bit closer to the edge.
3935 if wcourse.power(game.warpfac) >= game.energy:
3936 # Insufficient power for trip
3939 prout(_("Engineering to bridge--"))
3940 if not game.shldup or 0.5*wcourse.power(game.warpfac) > game.energy:
3941 iwarp = (game.energy/(wcourse.distance+0.05)) ** 0.333333333
3943 prout(_("We can't do it, Captain. We don't have enough energy."))
3945 proutn(_("We don't have enough energy, but we could do it at warp %d") % iwarp)
3948 prout(_("if you'll lower the shields."))
3952 prout(_("We haven't the energy to go that far with the shields up."))
3954 # Make sure enough time is left for the trip
3955 game.optime = wcourse.time(game.warpfac)
3956 if game.optime >= 0.8*game.state.remtime:
3958 prout(_("First Officer Spock- \"Captain, I compute that such"))
3959 proutn(_(" a trip would require approximately %2.0f") %
3960 (100.0*game.optime/game.state.remtime))
3961 prout(_(" percent of our"))
3962 proutn(_(" remaining time. Are you sure this is wise?\" "))
3968 if game.warpfac > 6.0:
3969 # Decide if engine damage will occur
3970 # ESR: Seems wrong. Probability of damage goes *down* with distance?
3971 prob = wcourse.distance*(6.0-game.warpfac)**2/66.666666666
3972 if prob > randreal():
3974 wcourse.distance = randreal(wcourse.distance)
3975 # Decide if time warp will occur
3976 if 0.5*wcourse.distance*math.pow(7.0,game.warpfac-10.0) > randreal():
3978 if game.idebug and game.warpfac==10 and not twarp:
3980 proutn("=== Force time warp? ")
3984 # If time warp or engine damage, check path
3985 # If it is obstructed, don't do warp or damage
3986 look = wcourse.moves
3990 w = wcourse.sector()
3991 if not w.valid_sector():
3993 if game.quad[w.i][w.j] != '.':
3997 # Activate Warp Engines and pay the cost
3998 imove(wcourse, noattack=False)
4001 game.energy -= wcourse.power(game.warpfac)
4002 if game.energy <= 0:
4004 game.optime = wcourse.time(game.warpfac)
4008 game.damage[DWARPEN] = game.damfac * randreal(1.0, 4.0)
4010 prout(_("Engineering to bridge--"))
4011 prout(_(" Scott here. The warp engines are damaged."))
4012 prout(_(" We'll have to reduce speed to warp 4."))
4017 "Change the warp factor."
4019 key=scanner.nexttok()
4023 proutn(_("Warp factor- "))
4027 if game.damage[DWARPEN] > 10.0:
4028 prout(_("Warp engines inoperative."))
4030 if damaged(DWARPEN) and scanner.real > 4.0:
4031 prout(_("Engineer Scott- \"I'm doing my best, Captain,"))
4032 prout(_(" but right now we can only go warp 4.\""))
4034 if scanner.real > 10.0:
4035 prout(_("Helmsman Sulu- \"Our top speed is warp 10, Captain.\""))
4037 if scanner.real < 1.0:
4038 prout(_("Helmsman Sulu- \"We can't go below warp 1, Captain.\""))
4040 oldfac = game.warpfac
4041 game.warpfac = scanner.real
4042 if game.warpfac <= oldfac or game.warpfac <= 6.0:
4043 prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\"") %
4046 if game.warpfac < 8.00:
4047 prout(_("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\""))
4049 if game.warpfac == 10.0:
4050 prout(_("Engineer Scott- \"Aye, Captain, we'll try it.\""))
4052 prout(_("Engineer Scott- \"Aye, Captain, but our engines may not take it.\""))
4056 "Cope with being tossed out of quadrant by supernova or yanked by beam."
4058 # is captain on planet?
4060 if damaged(DTRANSP):
4063 prout(_("Scotty rushes to the transporter controls."))
4065 prout(_("But with the shields up it's hopeless."))
4067 prouts(_("His desperate attempt to rescue you . . ."))
4072 prout(_("SUCCEEDS!"))
4075 proutn(_("The crystals mined were "))
4083 # Check to see if captain in shuttle craft
4088 # Inform captain of attempt to reach safety
4092 prouts(_("***RED ALERT! RED ALERT!"))
4094 proutn(_("The %s has stopped in a quadrant containing") % crmshp())
4095 prouts(_(" a supernova."))
4097 prout(_("***Emergency automatic override attempts to hurl ")+crmshp())
4098 prout(_("safely out of quadrant."))
4099 if not damaged(DRADIO):
4100 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
4101 # Try to use warp engines
4102 if damaged(DWARPEN):
4104 prout(_("Warp engines damaged."))
4107 game.warpfac = randreal(6.0, 8.0)
4108 prout(_("Warp factor set to %d") % int(game.warpfac))
4109 power = 0.75*game.energy
4110 dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1))
4111 dist = max(dist, randreal(math.sqrt(2)))
4112 bugout = course(bearing=randreal(12), distance=dist) # How dumb!
4113 game.optime = bugout.time(game.warpfac)
4115 game.inorbit = False
4116 warp(bugout, involuntary=True)
4118 # This is bad news, we didn't leave quadrant.
4122 prout(_("Insufficient energy to leave quadrant."))
4125 # Repeat if another snova
4126 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
4128 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
4129 finish(FWON) # Snova killed remaining enemy.
4132 "Let's do the time warp again."
4133 prout(_("***TIME WARP ENTERED."))
4134 if game.state.snap and withprob(0.5):
4136 prout(_("You are traveling backwards in time %d stardates.") %
4137 int(game.state.date-game.snapsht.date))
4138 game.state = game.snapsht
4139 game.state.snap = False
4140 if len(game.state.kcmdr):
4141 schedule(FTBEAM, expran(game.intime/len(game.state.kcmdr)))
4142 schedule(FBATTAK, expran(0.3*game.intime))
4143 schedule(FSNOVA, expran(0.5*game.intime))
4144 # next snapshot will be sooner
4145 schedule(FSNAP, expran(0.25*game.state.remtime))
4147 if game.state.nscrem:
4148 schedule(FSCMOVE, 0.2777)
4152 game.battle.invalidate()
4153 # Make sure Galileo is consistant -- Snapshot may have been taken
4154 # when on planet, which would give us two Galileos!
4156 for l in range(game.inplan):
4157 if game.state.planets[l].known == "shuttle_down":
4159 if game.iscraft == "onship" and game.ship=='E':
4160 prout(_("Chekov- \"Security reports the Galileo has disappeared, Sir!"))
4161 game.iscraft = "offship"
4162 # Likewise, if in the original time the Galileo was abandoned, but
4163 # was on ship earlier, it would have vanished -- let's restore it.
4164 if game.iscraft == "offship" and not gotit and game.damage[DSHUTTL] >= 0.0:
4165 prout(_("Chekov- \"Security reports the Galileo has reappeared in the dock!\""))
4166 game.iscraft = "onship"
4167 # There used to be code to do the actual reconstrction here,
4168 # but the starchart is now part of the snapshotted galaxy state.
4169 prout(_("Spock has reconstructed a correct star chart from memory"))
4171 # Go forward in time
4172 game.optime = expran(0.5*game.intime)
4173 prout(_("You are traveling forward in time %d stardates.") % int(game.optime))
4174 # cheat to make sure no tractor beams occur during time warp
4175 postpone(FTBEAM, game.optime)
4176 game.damage[DRADIO] += game.optime
4178 events() # Stas Sergeev added this -- do pending events
4181 "Launch deep-space probe."
4182 # New code to launch a deep space probe
4183 if game.nprobes == 0:
4186 if game.ship == 'E':
4187 prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\""))
4189 prout(_("Ye Faerie Queene has no deep space probes."))
4194 prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\""))
4196 if is_scheduled(FDSPROB):
4199 if damaged(DRADIO) and game.condition != "docked":
4200 prout(_("Spock- \"Records show the previous probe has not yet"))
4201 prout(_(" reached its destination.\""))
4203 prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""))
4205 key = scanner.nexttok()
4207 if game.nprobes == 1:
4208 prout(_("1 probe left."))
4210 prout(_("%d probes left") % game.nprobes)
4211 proutn(_("Are you sure you want to fire a probe? "))
4214 game.isarmed = False
4215 if key == "IHALPHA" and scanner.token == "armed":
4217 key = scanner.nexttok()
4218 elif key == "IHEOL":
4219 proutn(_("Arm NOVAMAX warhead? "))
4221 elif key == "IHREAL": # first element of course
4222 scanner.push(scanner.token)
4224 game.probe = getcourse(isprobe=True)
4228 schedule(FDSPROB, 0.01) # Time to move one sector
4229 prout(_("Ensign Chekov- \"The deep space probe is launched, Captain.\""))
4234 "Yell for help from nearest starbase."
4235 # There's more than one way to move in this game!
4237 # Test for conditions which prevent calling for help
4238 if game.condition == "docked":
4239 prout(_("Lt. Uhura- \"But Captain, we're already docked.\""))
4242 prout(_("Subspace radio damaged."))
4244 if not game.state.baseq:
4245 prout(_("Lt. Uhura- \"Captain, I'm not getting any response from Starbase.\""))
4248 prout(_("You must be aboard the %s.") % crmshp())
4250 # OK -- call for help from nearest starbase
4253 # There's one in this quadrant
4254 ddist = (game.base - game.sector).distance()
4256 ibq = None # Force base-quadrant game to persist past loop
4258 for ibq in game.state.baseq:
4259 xdist = QUADSIZE * (ibq - game.quadrant).distance()
4263 prout(_("No starbases remain. You are alone in a hostile galaxy."))
4265 # Since starbase not in quadrant, set up new quadrant
4268 # dematerialize starship
4269 game.quad[game.sector.i][game.sector.j]='.'
4270 proutn(_("Starbase in Quadrant %s responds--%s dematerializes") \
4271 % (game.quadrant, crmshp()))
4272 game.sector.invalidate()
4273 for m in range(1, 5+1):
4274 w = game.base.scatter()
4275 if w.valid_sector() and game.quad[w.i][w.j]=='.':
4276 # found one -- finish up
4279 if not game.sector.is_valid():
4280 prout(_("You have been lost in space..."))
4281 finish(FMATERIALIZE)
4283 # Give starbase three chances to rematerialize starship
4284 probf = math.pow((1.0 - math.pow(0.98,ddist)), 0.33333333)
4285 for m in range(1, 3+1):
4286 if m == 1: proutn(_("1st"))
4287 elif m == 2: proutn(_("2nd"))
4288 elif m == 3: proutn(_("3rd"))
4289 proutn(_(" attempt to re-materialize ") + crmshp())
4290 game.quad[game.sector.i][game.sector.j]=('-','o','O')[m-1]
4293 if randreal() > probf:
4297 curses.delay_output(500)
4299 game.quad[game.sector.i][game.sector.j]='?'
4302 setwnd(message_window)
4303 finish(FMATERIALIZE)
4305 game.quad[game.sector.i][game.sector.j]=game.ship
4307 prout(_("succeeds."))
4311 prout(_("Lt. Uhura- \"Captain, we made it!\""))
4316 if game.condition=="docked":
4318 prout(_("You cannot abandon Ye Faerie Queene."))
4321 # Must take shuttle craft to exit
4322 if game.damage[DSHUTTL]==-1:
4323 prout(_("Ye Faerie Queene has no shuttle craft."))
4325 if game.damage[DSHUTTL]<0:
4326 prout(_("Shuttle craft now serving Big Macs."))
4328 if game.damage[DSHUTTL]>0:
4329 prout(_("Shuttle craft damaged."))
4332 prout(_("You must be aboard the ship."))
4334 if game.iscraft != "onship":
4335 prout(_("Shuttle craft not currently available."))
4337 # Emit abandon ship messages
4339 prouts(_("***ABANDON SHIP! ABANDON SHIP!"))
4341 prouts(_("***ALL HANDS ABANDON SHIP!"))
4343 prout(_("Captain and crew escape in shuttle craft."))
4344 if not game.state.baseq:
4345 # Oops! no place to go...
4348 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
4350 if not (game.options & OPTION_WORLDS) and not damaged(DTRANSP):
4351 prout(_("Remainder of ship's complement beam down"))
4352 prout(_("to nearest habitable planet."))
4353 elif q.planet != None and not damaged(DTRANSP):
4354 prout(_("Remainder of ship's complement beam down to %s.") %
4357 prout(_("Entire crew of %d left to die in outer space.") %
4359 game.casual += game.state.crew
4360 game.abandoned += game.state.crew
4361 # If at least one base left, give 'em the Faerie Queene
4363 game.icrystl = False # crystals are lost
4364 game.nprobes = 0 # No probes
4365 prout(_("You are captured by Klingons and released to"))
4366 prout(_("the Federation in a prisoner-of-war exchange."))
4367 nb = randrange(len(game.state.baseq))
4368 # Set up quadrant and position FQ adjacient to base
4369 if not game.quadrant == game.state.baseq[nb]:
4370 game.quadrant = game.state.baseq[nb]
4371 game.sector.i = game.sector.j = 5
4374 # position next to base by trial and error
4375 game.quad[game.sector.i][game.sector.j] = '.'
4377 for l in range(QUADSIZE):
4378 game.sector = game.base.scatter()
4379 if game.sector.valid_sector() and \
4380 game.quad[game.sector.i][game.sector.j] == '.':
4383 break # found a spot
4384 game.sector.i=QUADSIZE/2
4385 game.sector.j=QUADSIZE/2
4387 # Get new commission
4388 game.quad[game.sector.i][game.sector.j] = game.ship = 'F'
4389 game.state.crew = FULLCREW
4390 prout(_("Starfleet puts you in command of another ship,"))
4391 prout(_("the Faerie Queene, which is antiquated but,"))
4392 prout(_("still useable."))
4394 prout(_("The dilithium crystals have been moved."))
4396 game.iscraft = "offship" # Galileo disappears
4398 game.condition="docked"
4399 for l in range(NDEVICES):
4400 game.damage[l] = 0.0
4401 game.damage[DSHUTTL] = -1
4402 game.energy = game.inenrg = 3000.0
4403 game.shield = game.inshld = 1250.0
4404 game.torps = game.intorps = 6
4405 game.lsupres=game.inlsr=3.0
4410 # Code from planets.c begins here.
4413 "Abort a lengthy operation if an event interrupts it."
4416 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.justin:
4421 "Report on (uninhabited) planets in the galaxy."
4425 prout(_("Spock- \"Planet report follows, Captain.\""))
4427 for i in range(game.inplan):
4428 if game.state.planets[i].pclass == "destroyed":
4430 if (game.state.planets[i].known != "unknown" \
4431 and not game.state.planets[i].inhabited) \
4434 if game.idebug and game.state.planets[i].known=="unknown":
4435 proutn("(Unknown) ")
4436 proutn(_("Quadrant %s") % game.state.planets[i].quadrant)
4437 proutn(_(" class "))
4438 proutn(game.state.planets[i].pclass)
4440 if game.state.planets[i].crystals != "present":
4442 prout(_("dilithium crystals present."))
4443 if game.state.planets[i].known=="shuttle_down":
4444 prout(_(" Shuttle Craft Galileo on surface."))
4446 prout(_("No information available."))
4449 "Enter standard orbit."
4453 prout(_("Already in standard orbit."))
4455 if damaged(DWARPEN) and damaged(DIMPULS):
4456 prout(_("Both warp and impulse engines damaged."))
4458 if not game.plnet.is_valid():
4459 prout("There is no planet in this sector.")
4461 if abs(game.sector.i-game.plnet.i)>1 or abs(game.sector.j-game.plnet.j)>1:
4462 prout(crmshp() + _(" not adjacent to planet."))
4465 game.optime = randreal(0.02, 0.05)
4466 prout(_("Helmsman Sulu- \"Entering standard orbit, Sir.\""))
4470 game.height = randreal(1400, 8600)
4471 prout(_("Sulu- \"Entered orbit at altitude %.2f kilometers.\"") % game.height)
4476 "Examine planets in this quadrant."
4477 if damaged(DSRSENS):
4478 if game.options & OPTION_TTY:
4479 prout(_("Short range sensors damaged."))
4481 if game.iplnet is None:
4482 if game.options & OPTION_TTY:
4483 prout(_("Spock- \"No planet in this quadrant, Captain.\""))
4485 if game.iplnet.known == "unknown":
4486 prout(_("Spock- \"Sensor scan for Quadrant %s-") % game.quadrant)
4488 prout(_(" Planet at Sector %s is of class %s.") %
4489 (game.plnet, game.iplnet.pclass))
4490 if game.iplnet.known=="shuttle_down":
4491 prout(_(" Sensors show Galileo still on surface."))
4492 proutn(_(" Readings indicate"))
4493 if game.iplnet.crystals != "present":
4495 prout(_(" dilithium crystals present.\""))
4496 if game.iplnet.known == "unknown":
4497 game.iplnet.known = "known"
4498 elif game.iplnet.inhabited:
4499 prout(_("Spock- \"The inhabited planet %s ") % game.iplnet.name)
4500 prout(_(" is located at Sector %s, Captain.\"") % game.plnet)
4503 "Use the transporter."
4507 if damaged(DTRANSP):
4508 prout(_("Transporter damaged."))
4509 if not damaged(DSHUTTL) and (game.iplnet.known=="shuttle_down" or game.iscraft == "onship"):
4511 proutn(_("Spock- \"May I suggest the shuttle craft, Sir?\" "))
4515 if not game.inorbit:
4516 prout(crmshp() + _(" not in standard orbit."))
4519 prout(_("Impossible to transport through shields."))
4521 if game.iplnet.known=="unknown":
4522 prout(_("Spock- \"Captain, we have no information on this planet"))
4523 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4524 prout(_(" you may not go down.\""))
4526 if not game.landed and game.iplnet.crystals=="absent":
4527 prout(_("Spock- \"Captain, I fail to see the logic in"))
4528 prout(_(" exploring a planet with no dilithium crystals."))
4529 proutn(_(" Are you sure this is wise?\" "))
4533 if not (game.options & OPTION_PLAIN):
4534 nrgneed = 50 * game.skill + game.height / 100.0
4535 if nrgneed > game.energy:
4536 prout(_("Engineering to bridge--"))
4537 prout(_(" Captain, we don't have enough energy for transportation."))
4539 if not game.landed and nrgneed * 2 > game.energy:
4540 prout(_("Engineering to bridge--"))
4541 prout(_(" Captain, we have enough energy only to transport you down to"))
4542 prout(_(" the planet, but there wouldn't be an energy for the trip back."))
4543 if game.iplnet.known == "shuttle_down":
4544 prout(_(" Although the Galileo shuttle craft may still be on a surface."))
4545 proutn(_(" Are you sure this is wise?\" "))
4550 # Coming from planet
4551 if game.iplnet.known=="shuttle_down":
4552 proutn(_("Spock- \"Wouldn't you rather take the Galileo?\" "))
4556 prout(_("Your crew hides the Galileo to prevent capture by aliens."))
4557 prout(_("Landing party assembled, ready to beam up."))
4559 prout(_("Kirk whips out communicator..."))
4560 prouts(_("BEEP BEEP BEEP"))
4562 prout(_("\"Kirk to enterprise- Lock on coordinates...energize.\""))
4565 prout(_("Scotty- \"Transporter room ready, Sir.\""))
4567 prout(_("Kirk and landing party prepare to beam down to planet surface."))
4569 prout(_("Kirk- \"Energize.\""))
4572 prouts("WWHOOOIIIIIRRRRREEEE.E.E. . . . . . .")
4574 if not withprob(0.98):
4575 prouts("BOOOIIIOOOIIOOOOIIIOIING . . .")
4577 prout(_("Scotty- \"Oh my God! I've lost them.\""))
4580 prouts(". . . . . . .E.E.EEEERRRRRIIIIIOOOHWW")
4581 game.landed = not game.landed
4582 game.energy -= nrgneed
4584 prout(_("Transport complete."))
4585 if game.landed and game.iplnet.known=="shuttle_down":
4586 prout(_("The shuttle craft Galileo is here!"))
4587 if not game.landed and game.imine:
4594 "Strip-mine a world for dilithium."
4598 prout(_("Mining party not on planet."))
4600 if game.iplnet.crystals == "mined":
4601 prout(_("This planet has already been strip-mined for dilithium."))
4603 elif game.iplnet.crystals == "absent":
4604 prout(_("No dilithium crystals on this planet."))
4607 prout(_("You've already mined enough crystals for this trip."))
4609 if game.icrystl and game.cryprob == 0.05:
4610 prout(_("With all those fresh crystals aboard the ") + crmshp())
4611 prout(_("there's no reason to mine more at this time."))
4613 game.optime = randreal(0.1, 0.3)*(ord(game.iplnet.pclass)-ord("L"))
4616 prout(_("Mining operation complete."))
4617 game.iplnet.crystals = "mined"
4618 game.imine = game.ididit = True
4621 "Use dilithium crystals."
4625 if not game.icrystl:
4626 prout(_("No dilithium crystals available."))
4628 if game.energy >= 1000:
4629 prout(_("Spock- \"Captain, Starfleet Regulations prohibit such an operation"))
4630 prout(_(" except when Condition Yellow exists."))
4632 prout(_("Spock- \"Captain, I must warn you that loading"))
4633 prout(_(" raw dilithium crystals into the ship's power"))
4634 prout(_(" system may risk a severe explosion."))
4635 proutn(_(" Are you sure this is wise?\" "))
4640 prout(_("Engineering Officer Scott- \"(GULP) Aye Sir."))
4641 prout(_(" Mr. Spock and I will try it.\""))
4643 prout(_("Spock- \"Crystals in place, Sir."))
4644 prout(_(" Ready to activate circuit.\""))
4646 prouts(_("Scotty- \"Keep your fingers crossed, Sir!\""))
4648 if withprob(game.cryprob):
4649 prouts(_(" \"Activating now! - - No good! It's***"))
4651 prouts(_("***RED ALERT! RED A*L********************************"))
4654 prouts(_("****************** KA-BOOM!!!! *******************"))
4658 game.energy += randreal(5000.0, 5500.0)
4659 prouts(_(" \"Activating now! - - "))
4660 prout(_("The instruments"))
4661 prout(_(" are going crazy, but I think it's"))
4662 prout(_(" going to work!! Congratulations, Sir!\""))
4667 "Use shuttlecraft for planetary jaunt."
4670 if damaged(DSHUTTL):
4671 if game.damage[DSHUTTL] == -1.0:
4672 if game.inorbit and game.iplnet.known == "shuttle_down":
4673 prout(_("Ye Faerie Queene has no shuttle craft bay to dock it at."))
4675 prout(_("Ye Faerie Queene had no shuttle craft."))
4676 elif game.damage[DSHUTTL] > 0:
4677 prout(_("The Galileo is damaged."))
4678 else: # game.damage[DSHUTTL] < 0
4679 prout(_("Shuttle craft is now serving Big Macs."))
4681 if not game.inorbit:
4682 prout(crmshp() + _(" not in standard orbit."))
4684 if (game.iplnet.known != "shuttle_down") and game.iscraft != "onship":
4685 prout(_("Shuttle craft not currently available."))
4687 if not game.landed and game.iplnet.known=="shuttle_down":
4688 prout(_("You will have to beam down to retrieve the shuttle craft."))
4690 if game.shldup or game.condition == "docked":
4691 prout(_("Shuttle craft cannot pass through shields."))
4693 if game.iplnet.known=="unknown":
4694 prout(_("Spock- \"Captain, we have no information on this planet"))
4695 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4696 prout(_(" you may not fly down.\""))
4698 game.optime = 3.0e-5*game.height
4699 if game.optime >= 0.8*game.state.remtime:
4700 prout(_("First Officer Spock- \"Captain, I compute that such"))
4701 proutn(_(" a maneuver would require approximately %2d%% of our") % \
4702 int(100*game.optime/game.state.remtime))
4703 prout(_("remaining time."))
4704 proutn(_("Are you sure this is wise?\" "))
4710 if game.iscraft == "onship":
4712 if not damaged(DTRANSP):
4713 proutn(_("Spock- \"Would you rather use the transporter?\" "))
4717 proutn(_("Shuttle crew"))
4719 proutn(_("Rescue party"))
4720 prout(_(" boards Galileo and swoops toward planet surface."))
4721 game.iscraft = "offship"
4725 game.iplnet.known="shuttle_down"
4726 prout(_("Trip complete."))
4729 # Ready to go back to ship
4730 prout(_("You and your mining party board the"))
4731 prout(_("shuttle craft for the trip back to the Enterprise."))
4733 prouts(_("The short hop begins . . ."))
4735 game.iplnet.known="known"
4741 game.iscraft = "onship"
4747 prout(_("Trip complete."))
4750 # Kirk on ship and so is Galileo
4751 prout(_("Mining party assembles in the hangar deck,"))
4752 prout(_("ready to board the shuttle craft \"Galileo\"."))
4754 prouts(_("The hangar doors open; the trip begins."))
4757 game.iscraft = "offship"
4760 game.iplnet.known = "shuttle_down"
4763 prout(_("Trip complete."))
4767 "Use the big zapper."
4771 if game.ship != 'E':
4772 prout(_("Ye Faerie Queene has no death ray."))
4774 if len(game.enemies)==0:
4775 prout(_("Sulu- \"But Sir, there are no enemies in this quadrant.\""))
4778 prout(_("Death Ray is damaged."))
4780 prout(_("Spock- \"Captain, the 'Experimental Death Ray'"))
4781 prout(_(" is highly unpredictible. Considering the alternatives,"))
4782 proutn(_(" are you sure this is wise?\" "))
4785 prout(_("Spock- \"Acknowledged.\""))
4788 prouts(_("WHOOEE ... WHOOEE ... WHOOEE ... WHOOEE"))
4790 prout(_("Crew scrambles in emergency preparation."))
4791 prout(_("Spock and Scotty ready the death ray and"))
4792 prout(_("prepare to channel all ship's power to the device."))
4794 prout(_("Spock- \"Preparations complete, sir.\""))
4795 prout(_("Kirk- \"Engage!\""))
4797 prouts(_("WHIRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"))
4800 if game.options & OPTION_PLAIN:
4804 prouts(_("Sulu- \"Captain! It's working!\""))
4806 while len(game.enemies) > 0:
4807 deadkl(game.enemies[1].location, game.quad[game.enemies[1].location.i][game.enemies[1].location.j],game.enemies[1].location)
4808 prout(_("Ensign Chekov- \"Congratulations, Captain!\""))
4809 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
4811 if (game.options & OPTION_PLAIN) == 0:
4812 prout(_("Spock- \"Captain, I believe the `Experimental Death Ray'"))
4814 prout(_(" is still operational.\""))
4816 prout(_(" has been rendered nonfunctional.\""))
4817 game.damage[DDRAY] = 39.95
4819 r = randreal() # Pick failure method
4821 prouts(_("Sulu- \"Captain! It's working!\""))
4823 prouts(_("***RED ALERT! RED ALERT!"))
4825 prout(_("***MATTER-ANTIMATTER IMPLOSION IMMINENT!"))
4827 prouts(_("***RED ALERT! RED A*L********************************"))
4830 prouts(_("****************** KA-BOOM!!!! *******************"))
4835 prouts(_("Sulu- \"Captain! Yagabandaghangrapl, brachriigringlanbla!\""))
4837 prout(_("Lt. Uhura- \"Graaeek! Graaeek!\""))
4839 prout(_("Spock- \"Fascinating! . . . All humans aboard"))
4840 prout(_(" have apparently been transformed into strange mutations."))
4841 prout(_(" Vulcans do not seem to be affected."))
4843 prout(_("Kirk- \"Raauch! Raauch!\""))
4847 prouts(_("Sulu- \"Captain! It's --WHAT?!?!\""))
4849 proutn(_("Spock- \"I believe the word is"))
4850 prouts(_(" *ASTONISHING*"))
4851 prout(_(" Mr. Sulu."))
4852 for i in range(QUADSIZE):
4853 for j in range(QUADSIZE):
4854 if game.quad[i][j] == '.':
4855 game.quad[i][j] = '?'
4856 prout(_(" Captain, our quadrant is now infested with"))
4857 prouts(_(" - - - - - - *THINGS*."))
4859 prout(_(" I have no logical explanation.\""))
4861 prouts(_("Sulu- \"Captain! The Death Ray is creating tribbles!\""))
4863 prout(_("Scotty- \"There are so many tribbles down here"))
4864 prout(_(" in Engineering, we can't move for 'em, Captain.\""))
4868 # Code from reports.c begins here
4870 def attackreport(curt):
4871 "eport status of bases under attack."
4873 if is_scheduled(FCDBAS):
4874 prout(_("Starbase in Quadrant %s is currently under Commander attack.") % game.battle)
4875 prout(_("It can hold out until Stardate %d.") % int(scheduled(FCDBAS)))
4876 elif game.isatb == 1:
4877 prout(_("Starbase in Quadrant %s is under Super-commander attack.") % game.state.kscmdr)
4878 prout(_("It can hold out until Stardate %d.") % int(scheduled(FSCDBAS)))
4880 prout(_("No Starbase is currently under attack."))
4882 if is_scheduled(FCDBAS):
4883 proutn(_("Base in %s attacked by C. Alive until %.1f") % (game.battle, scheduled(FCDBAS)))
4885 proutn(_("Base in %s attacked by S. Alive until %.1f") % (game.state.kscmdr, scheduled(FSCDBAS)))
4889 # report on general game status
4891 s1 = (game.thawed and _("thawed ")) or ""
4892 s2 = {1:"short", 2:"medium", 4:"long"}[game.length]
4893 s3 = (None, _("novice"), _("fair"),
4894 _("good"), _("expert"), _("emeritus"))[game.skill]
4895 prout(_("You %s a %s%s %s game.") % ((_("were playing"), _("are playing"))[game.alldone], s1, s2, s3))
4896 if game.skill>SKILL_GOOD and game.thawed and not game.alldone:
4897 prout(_("No plaque is allowed."))
4899 prout(_("This is tournament game %d.") % game.tourn)
4900 prout(_("Your secret password is \"%s\"") % game.passwd)
4901 proutn(_("%d of %d Klingons have been killed") % (((game.inkling + game.incom + game.inscom) - (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)),
4902 (game.inkling + game.incom + game.inscom)))
4903 if game.incom - len(game.state.kcmdr):
4904 prout(_(", including %d Commander%s.") % (game.incom - len(game.state.kcmdr), (_("s"), "")[(game.incom - len(game.state.kcmdr))==1]))
4905 elif game.inkling - game.state.remkl + (game.inscom - game.state.nscrem) > 0:
4906 prout(_(", but no Commanders."))
4909 if game.skill > SKILL_FAIR:
4910 prout(_("The Super Commander has %sbeen destroyed.") % ("", _("not "))[game.state.nscrem])
4911 if len(game.state.baseq) != game.inbase:
4913 if game.inbase-len(game.state.baseq)==1:
4914 proutn(_("has been 1 base"))
4916 proutn(_("have been %d bases") % (game.inbase-len(game.state.baseq)))
4917 prout(_(" destroyed, %d remaining.") % len(game.state.baseq))
4919 prout(_("There are %d bases.") % game.inbase)
4920 if communicating() or game.iseenit:
4921 # Don't report this if not seen and
4922 # either the radio is dead or not at base!
4926 prout(_("%d casualt%s suffered so far.") % (game.casual, ("y", "ies")[game.casual!=1]))
4928 prout(_("There were %d call%s for help.") % (game.nhelp, ("" , _("s"))[game.nhelp!=1]))
4929 if game.ship == 'E':
4930 proutn(_("You have "))
4932 proutn("%d" % (game.nprobes))
4935 proutn(_(" deep space probe"))
4939 if communicating() and is_scheduled(FDSPROB):
4941 proutn(_("An armed deep space probe is in "))
4943 proutn(_("A deep space probe is in "))
4944 prout("Quadrant %s." % game.probe.quadrant())
4946 if game.cryprob <= .05:
4947 prout(_("Dilithium crystals aboard ship... not yet used."))
4951 while game.cryprob > ai:
4954 prout(_("Dilithium crystals have been used %d time%s.") % \
4955 (i, (_("s"), "")[i==1]))
4959 "Long-range sensor scan."
4960 if damaged(DLRSENS):
4961 # Now allow base's sensors if docked
4962 if game.condition != "docked":
4964 prout(_("LONG-RANGE SENSORS DAMAGED."))
4967 prout(_("Starbase's long-range scan"))
4969 prout(_("Long-range scan"))
4970 for x in range(game.quadrant.i-1, game.quadrant.i+2):
4973 for y in range(game.quadrant.j-1, game.quadrant.j+2):
4974 if not Coord(x, y).valid_quadrant():
4978 if not damaged(DRADIO):
4979 game.state.galaxy[x][y].charted = True
4980 game.state.chart[x][y].klingons = game.state.galaxy[x][y].klingons
4981 game.state.chart[x][y].starbase = game.state.galaxy[x][y].starbase
4982 game.state.chart[x][y].stars = game.state.galaxy[x][y].stars
4983 if not silent and game.state.galaxy[x][y].supernova:
4986 proutn(" %3d" % (game.state.chart[x][y].klingons*100 + game.state.chart[x][y].starbase * 10 + game.state.chart[x][y].stars))
4994 for i in range(NDEVICES):
4997 prout(_("\tDEVICE\t\t\t-REPAIR TIMES-"))
4998 prout(_("\t\t\tIN FLIGHT\t\tDOCKED"))
5000 prout(" %-26s\t%8.2f\t\t%8.2f" % (device[i],
5001 game.damage[i]+0.05,
5002 DOCKFAC*game.damage[i]+0.005))
5004 prout(_("All devices functional."))
5007 "Update the chart in the Enterprise's computer from galaxy data."
5008 game.lastchart = game.state.date
5009 for i in range(GALSIZE):
5010 for j in range(GALSIZE):
5011 if game.state.galaxy[i][j].charted:
5012 game.state.chart[i][j].klingons = game.state.galaxy[i][j].klingons
5013 game.state.chart[i][j].starbase = game.state.galaxy[i][j].starbase
5014 game.state.chart[i][j].stars = game.state.galaxy[i][j].stars
5017 "Display the star chart."
5019 if (game.options & OPTION_AUTOSCAN):
5021 if not damaged(DRADIO):
5023 if game.lastchart < game.state.date and game.condition == "docked":
5024 prout(_("Spock- \"I revised the Star Chart from the starbase's records.\""))
5026 prout(_(" STAR CHART FOR THE KNOWN GALAXY"))
5027 if game.state.date > game.lastchart:
5028 prout(_("(Last surveillance update %d stardates ago).") % ((int)(game.state.date-game.lastchart)))
5029 prout(" 1 2 3 4 5 6 7 8")
5030 for i in range(GALSIZE):
5031 proutn("%d |" % (i+1))
5032 for j in range(GALSIZE):
5033 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5037 if game.state.galaxy[i][j].supernova:
5039 elif not game.state.galaxy[i][j].charted and game.state.galaxy[i][j].starbase:
5041 elif game.state.galaxy[i][j].charted:
5042 show = "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars)
5046 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5054 def sectscan(goodScan, i, j):
5055 "Light up an individual dot in a sector."
5056 if goodScan or (abs(i-game.sector.i)<= 1 and abs(j-game.sector.j) <= 1):
5057 textcolor({"green":GREEN,
5061 "dead":BROWN}[game.condition])
5062 if game.quad[i][j] != game.ship:
5064 proutn("%c " % game.quad[i][j])
5070 "Emit status report lines"
5071 if not req or req == 1:
5072 prstat(_("Stardate"), _("%.1f, Time Left %.2f") \
5073 % (game.state.date, game.state.remtime))
5074 if not req or req == 2:
5075 if game.condition != "docked":
5077 prstat(_("Condition"), _("%s, %i DAMAGES") % \
5078 (game.condition.upper(), sum([x > 0 for x in game.damage])))
5079 if not req or req == 3:
5080 prstat(_("Position"), "%s , %s" % (game.quadrant, game.sector))
5081 if not req or req == 4:
5082 if damaged(DLIFSUP):
5083 if game.condition == "docked":
5084 s = _("DAMAGED, Base provides")
5086 s = _("DAMAGED, reserves=%4.2f") % game.lsupres
5089 prstat(_("Life Support"), s)
5090 if not req or req == 5:
5091 prstat(_("Warp Factor"), "%.1f" % game.warpfac)
5092 if not req or req == 6:
5094 if game.icrystl and (game.options & OPTION_SHOWME):
5095 extra = _(" (have crystals)")
5096 prstat(_("Energy"), "%.2f%s" % (game.energy, extra))
5097 if not req or req == 7:
5098 prstat(_("Torpedoes"), "%d" % (game.torps))
5099 if not req or req == 8:
5100 if damaged(DSHIELD):
5106 data = _(" %d%% %.1f units") \
5107 % (int((100.0*game.shield)/game.inshld + 0.5), game.shield)
5108 prstat(_("Shields"), s+data)
5109 if not req or req == 9:
5110 prstat(_("Klingons Left"), "%d" \
5111 % (game.state.remkl+len(game.state.kcmdr)+game.state.nscrem))
5112 if not req or req == 10:
5113 if game.options & OPTION_WORLDS:
5114 plnet = game.state.galaxy[game.quadrant.i][game.quadrant.j].planet
5115 if plnet and plnet.inhabited:
5116 prstat(_("Major system"), plnet.name)
5118 prout(_("Sector is uninhabited"))
5119 elif not req or req == 11:
5120 attackreport(not req)
5123 "Request specified status data, a historical relic from slow TTYs."
5124 requests = ("da","co","po","ls","wa","en","to","sh","kl","sy", "ti")
5125 while scanner.nexttok() == "IHEOL":
5126 proutn(_("Information desired? "))
5128 if scanner.token in requests:
5129 status(requests.index(scanner.token))
5131 prout(_("UNRECOGNIZED REQUEST. Legal requests are:"))
5132 prout((" date, condition, position, lsupport, warpfactor,"))
5133 prout((" energy, torpedoes, shields, klingons, system, time."))
5138 if damaged(DSRSENS):
5139 # Allow base's sensors if docked
5140 if game.condition != "docked":
5141 prout(_(" S.R. SENSORS DAMAGED!"))
5144 prout(_(" [Using Base's sensors]"))
5146 prout(_(" Short-range scan"))
5147 if goodScan and not damaged(DRADIO):
5148 game.state.chart[game.quadrant.i][game.quadrant.j].klingons = game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons
5149 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase
5150 game.state.chart[game.quadrant.i][game.quadrant.j].stars = game.state.galaxy[game.quadrant.i][game.quadrant.j].stars
5151 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
5152 prout(" 1 2 3 4 5 6 7 8 9 10")
5153 if game.condition != "docked":
5155 for i in range(QUADSIZE):
5156 proutn("%2d " % (i+1))
5157 for j in range(QUADSIZE):
5158 sectscan(goodScan, i, j)
5162 "Use computer to get estimated time of arrival for a warp jump."
5163 w1 = Coord(); w2 = Coord()
5165 if damaged(DCOMPTR):
5166 prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR."))
5169 if scanner.nexttok() != "IHREAL":
5172 proutn(_("Destination quadrant and/or sector? "))
5173 if scanner.nexttok()!="IHREAL":
5176 w1.j = int(scanner.real-0.5)
5177 if scanner.nexttok() != "IHREAL":
5180 w1.i = int(scanner.real-0.5)
5181 if scanner.nexttok() == "IHREAL":
5182 w2.j = int(scanner.real-0.5)
5183 if scanner.nexttok() != "IHREAL":
5186 w2.i = int(scanner.real-0.5)
5188 if game.quadrant.j>w1.i:
5192 if game.quadrant.i>w1.j:
5196 if not w1.valid_quadrant() or not w2.valid_sector():
5199 dist = math.sqrt((w1.j-game.quadrant.j+(w2.j-game.sector.j)/(QUADSIZE*1.0))**2+
5200 (w1.i-game.quadrant.i+(w2.i-game.sector.i)/(QUADSIZE*1.0))**2)
5203 prout(_("Answer \"no\" if you don't know the value:"))
5206 proutn(_("Time or arrival date? "))
5207 if scanner.nexttok()=="IHREAL":
5208 ttime = scanner.real
5209 if ttime > game.state.date:
5210 ttime -= game.state.date # Actually a star date
5211 twarp=(math.floor(math.sqrt((10.0*dist)/ttime)*10.0)+1.0)/10.0
5212 if ttime <= 1e-10 or twarp > 10:
5213 prout(_("We'll never make it, sir."))
5220 proutn(_("Warp factor? "))
5221 if scanner.nexttok()== "IHREAL":
5223 twarp = scanner.real
5224 if twarp<1.0 or twarp > 10.0:
5228 prout(_("Captain, certainly you can give me one of these."))
5231 ttime = (10.0*dist)/twarp**2
5232 tpower = dist*twarp*twarp*twarp*(game.shldup+1)
5233 if tpower >= game.energy:
5234 prout(_("Insufficient energy, sir."))
5235 if not game.shldup or tpower > game.energy*2.0:
5238 proutn(_("New warp factor to try? "))
5239 if scanner.nexttok() == "IHREAL":
5241 twarp = scanner.real
5242 if twarp<1.0 or twarp > 10.0:
5250 prout(_("But if you lower your shields,"))
5251 proutn(_("remaining"))
5254 proutn(_("Remaining"))
5255 prout(_(" energy will be %.2f.") % (game.energy-tpower))
5257 prout(_("And we will arrive at stardate %.2f.") % (game.state.date+ttime))
5259 prout(_("Any warp speed is adequate."))
5261 prout(_("Minimum warp needed is %.2f,") % (twarp))
5262 prout(_("and we will arrive at stardate %.2f.") % (game.state.date+ttime))
5263 if game.state.remtime < ttime:
5264 prout(_("Unfortunately, the Federation will be destroyed by then."))
5266 prout(_("You'll be taking risks at that speed, Captain"))
5267 if (game.isatb==1 and game.state.kscmdr == w1 and \
5268 scheduled(FSCDBAS)< ttime+game.state.date) or \
5269 (scheduled(FCDBAS)<ttime+game.state.date and game.battle == w1):
5270 prout(_("The starbase there will be destroyed by then."))
5271 proutn(_("New warp factor to try? "))
5272 if scanner.nexttok() == "IHREAL":
5274 twarp = scanner.real
5275 if twarp<1.0 or twarp > 10.0:
5283 # Code from setup.c begins here
5286 "Issue a historically correct banner."
5288 prout(_("-SUPER- STAR TREK"))
5290 # From the FORTRAN original
5291 # prout(_("Latest update-21 Sept 78"))
5297 scanner.push("emsave.trk")
5298 key = scanner.nexttok()
5300 proutn(_("File name: "))
5301 key = scanner.nexttok()
5302 if key != "IHALPHA":
5305 if '.' not in scanner.token:
5306 scanner.token += ".trk"
5308 fp = open(scanner.token, "wb")
5310 prout(_("Can't freeze game as file %s") % scanner.token)
5312 pickle.dump(game, fp)
5317 "Retrieve saved game."
5320 key = scanner.nexttok()
5322 proutn(_("File name: "))
5323 key = scanner.nexttok()
5324 if key != "IHALPHA":
5327 if '.' not in scanner.token:
5328 scanner.token += ".trk"
5330 fp = open(scanner.token, "rb")
5332 prout(_("Can't thaw game in %s") % scanner.token)
5334 game = pickle.load(fp)
5339 # I used <http://www.memory-alpha.org> to find planets
5340 # with references in ST:TOS. Earth and the Alpha Centauri
5341 # Colony have been omitted.
5343 # Some planets marked Class G and P here will be displayed as class M
5344 # because of the way planets are generated. This is a known bug.
5347 _("Andoria (Fesoan)"), # several episodes
5348 _("Tellar Prime (Miracht)"), # TOS: "Journey to Babel"
5349 _("Vulcan (T'Khasi)"), # many episodes
5350 _("Medusa"), # TOS: "Is There in Truth No Beauty?"
5351 _("Argelius II (Nelphia)"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5352 _("Ardana"), # TOS: "The Cloud Minders"
5353 _("Catulla (Cendo-Prae)"), # TOS: "The Way to Eden"
5354 _("Gideon"), # TOS: "The Mark of Gideon"
5355 _("Aldebaran III"), # TOS: "The Deadly Years"
5356 _("Alpha Majoris I"), # TOS: "Wolf in the Fold"
5357 _("Altair IV"), # TOS: "Amok Time
5358 _("Ariannus"), # TOS: "Let That Be Your Last Battlefield"
5359 _("Benecia"), # TOS: "The Conscience of the King"
5360 _("Beta Niobe I (Sarpeidon)"), # TOS: "All Our Yesterdays"
5361 _("Alpha Carinae II"), # TOS: "The Ultimate Computer"
5362 _("Capella IV (Kohath)"), # TOS: "Friday's Child" (Class G)
5363 _("Daran V"), # TOS: "For the World is Hollow and I Have Touched the Sky"
5364 _("Deneb II"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5365 _("Eminiar VII"), # TOS: "A Taste of Armageddon"
5366 _("Gamma Canaris IV"), # TOS: "Metamorphosis"
5367 _("Gamma Tranguli VI (Vaalel)"), # TOS: "The Apple"
5368 _("Ingraham B"), # TOS: "Operation: Annihilate"
5369 _("Janus IV"), # TOS: "The Devil in the Dark"
5370 _("Makus III"), # TOS: "The Galileo Seven"
5371 _("Marcos XII"), # TOS: "And the Children Shall Lead",
5372 _("Omega IV"), # TOS: "The Omega Glory"
5373 _("Regulus V"), # TOS: "Amok Time
5374 _("Deneva"), # TOS: "Operation -- Annihilate!"
5375 # Worlds from BSD Trek
5376 _("Rigel II"), # TOS: "Shore Leave" ("III" in BSD)
5377 _("Beta III"), # TOS: "The Return of the Archons"
5378 _("Triacus"), # TOS: "And the Children Shall Lead",
5379 _("Exo III"), # TOS: "What Are Little Girls Made Of?" (Class P)
5381 # _("Hansen's Planet"), # TOS: "The Galileo Seven"
5382 # _("Taurus IV"), # TOS: "The Galileo Seven" (class G)
5383 # _("Antos IV (Doraphane)"), # TOS: "Whom Gods Destroy", "Who Mourns for Adonais?"
5384 # _("Izar"), # TOS: "Whom Gods Destroy"
5385 # _("Tiburon"), # TOS: "The Way to Eden"
5386 # _("Merak II"), # TOS: "The Cloud Minders"
5387 # _("Coridan (Desotriana)"), # TOS: "Journey to Babel"
5388 # _("Iotia"), # TOS: "A Piece of the Action"
5392 _("S. R. Sensors"), \
5393 _("L. R. Sensors"), \
5395 _("Photon Tubes"), \
5396 _("Life Support"), \
5397 _("Warp Engines"), \
5398 _("Impulse Engines"), \
5400 _("Subspace Radio"), \
5401 _("Shuttle Craft"), \
5403 _("Navigation System"), \
5405 _("Shield Control"), \
5411 "Prepare to play, set up cosmos."
5413 # Decide how many of everything
5415 return # frozen game
5416 # Prepare the Enterprise
5417 game.alldone = game.gamewon = game.shldchg = game.shldup = False
5419 game.state.crew = FULLCREW
5420 game.energy = game.inenrg = 5000.0
5421 game.shield = game.inshld = 2500.0
5424 game.quadrant = randplace(GALSIZE)
5425 game.sector = randplace(QUADSIZE)
5426 game.torps = game.intorps = 10
5427 game.nprobes = randrange(2, 5)
5429 for i in range(NDEVICES):
5430 game.damage[i] = 0.0
5431 # Set up assorted game parameters
5432 game.battle = Coord()
5433 game.state.date = game.indate = 100.0 * randreal(20, 51)
5434 game.nkinks = game.nhelp = game.casual = game.abandoned = 0
5435 game.iscate = game.resting = game.imine = game.icrystl = game.icraft = False
5436 game.isatb = game.state.nplankl = 0
5437 game.state.starkl = game.state.basekl = game.state.nworldkl = 0
5438 game.iscraft = "onship"
5443 game.state.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
5445 game.state.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
5447 game.state.planets = [] # Planet information
5448 game.state.baseq = [] # Base quadrant coordinates
5449 game.state.kcmdr = [] # Commander quadrant coordinates
5450 game.statekscmdr = Coord() # Supercommander quadrant coordinates
5452 # Starchart is functional but we've never seen it
5453 game.lastchart = FOREVER
5454 # Put stars in the galaxy
5456 for i in range(GALSIZE):
5457 for j in range(GALSIZE):
5458 # Can't have more stars per quadrant than fit in one decimal digit,
5459 # if we do the chart representation will break.
5460 k = randrange(1, min(10, QUADSIZE**2/10))
5462 game.state.galaxy[i][j].stars = k
5463 # Locate star bases in galaxy
5465 prout("=== Allocating %d bases" % game.inbase)
5466 for i in range(game.inbase):
5469 w = randplace(GALSIZE)
5470 if not game.state.galaxy[w.i][w.j].starbase:
5473 # C version: for (j = i-1; j > 0; j--)
5474 # so it did them in the opposite order.
5475 for j in range(1, i):
5476 # Improved placement algorithm to spread out bases
5477 distq = (w - game.state.baseq[j]).distance()
5478 if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75):
5481 prout("=== Abandoning base #%d at %s" % (i, w))
5483 elif distq < 6.0 * (BASEMAX+1-game.inbase):
5485 prout("=== Saving base #%d, close to #%d" % (i, j))
5489 prout("=== Placing base #%d in quadrant %s" % (i, w))
5490 game.state.baseq.append(w)
5491 game.state.galaxy[w.i][w.j].starbase = game.state.chart[w.i][w.j].starbase = True
5492 # Position ordinary Klingon Battle Cruisers
5494 klumper = 0.25*game.skill*(9.0-game.length)+1.0
5495 if klumper > MAXKLQUAD:
5499 klump = (1.0 - r*r)*klumper
5504 w = randplace(GALSIZE)
5505 if not game.state.galaxy[w.i][w.j].supernova and \
5506 game.state.galaxy[w.i][w.j].klingons + klump <= MAXKLQUAD:
5508 game.state.galaxy[w.i][w.j].klingons += int(klump)
5511 # Position Klingon Commander Ships
5512 for i in range(game.incom):
5514 w = randplace(GALSIZE)
5515 if not welcoming(w) or w in game.state.kcmdr:
5517 if (game.state.galaxy[w.i][w.j].klingons or withprob(0.25)):
5519 game.state.galaxy[w.i][w.j].klingons += 1
5520 game.state.kcmdr.append(w)
5521 # Locate planets in galaxy
5522 for i in range(game.inplan):
5524 w = randplace(GALSIZE)
5525 if game.state.galaxy[w.i][w.j].planet is None:
5529 new.crystals = "absent"
5530 if (game.options & OPTION_WORLDS) and i < NINHAB:
5531 new.pclass = "M" # All inhabited planets are class M
5532 new.crystals = "absent"
5534 new.name = systnames[i]
5535 new.inhabited = True
5537 new.pclass = ("M", "N", "O")[randrange(0, 3)]
5539 new.crystals = "present"
5540 new.known = "unknown"
5541 new.inhabited = False
5542 game.state.galaxy[w.i][w.j].planet = new
5543 game.state.planets.append(new)
5545 for i in range(game.state.nromrem):
5546 w = randplace(GALSIZE)
5547 game.state.galaxy[w.i][w.j].romulans += 1
5548 # Place the Super-Commander if needed
5549 if game.state.nscrem > 0:
5551 w = randplace(GALSIZE)
5554 game.state.kscmdr = w
5555 game.state.galaxy[w.i][w.j].klingons += 1
5556 # Initialize times for extraneous events
5557 schedule(FSNOVA, expran(0.5 * game.intime))
5558 schedule(FTBEAM, expran(1.5 * (game.intime / len(game.state.kcmdr))))
5559 schedule(FSNAP, randreal(1.0, 2.0)) # Force an early snapshot
5560 schedule(FBATTAK, expran(0.3*game.intime))
5562 if game.state.nscrem:
5563 schedule(FSCMOVE, 0.2777)
5568 if (game.options & OPTION_WORLDS) and game.skill >= SKILL_GOOD:
5569 schedule(FDISTR, expran(1.0 + game.intime))
5574 # Place thing (in tournament game, we don't want one!)
5575 # New in SST2K: never place the Thing near a starbase.
5576 # This makes sense and avoids a special case in the old code.
5578 if game.tourn is None:
5580 thing = randplace(GALSIZE)
5581 if thing not in game.state.baseq:
5584 game.state.snap = False
5585 if game.skill == SKILL_NOVICE:
5586 prout(_("It is stardate %d. The Federation is being attacked by") % int(game.state.date))
5587 prout(_("a deadly Klingon invasion force. As captain of the United"))
5588 prout(_("Starship U.S.S. Enterprise, it is your mission to seek out"))
5589 prout(_("and destroy this invasion force of %d battle cruisers.") % ((game.inkling + game.incom + game.inscom)))
5590 prout(_("You have an initial allotment of %d stardates to complete") % int(game.intime))
5591 prout(_("your mission. As you proceed you may be given more time."))
5593 prout(_("You will have %d supporting starbases.") % (game.inbase))
5594 proutn(_("Starbase locations- "))
5596 prout(_("Stardate %d.") % int(game.state.date))
5598 prout(_("%d Klingons.") % (game.inkling + game.incom + game.inscom))
5599 prout(_("An unknown number of Romulans."))
5600 if game.state.nscrem:
5601 prout(_("And one (GULP) Super-Commander."))
5602 prout(_("%d stardates.") % int(game.intime))
5603 proutn(_("%d starbases in ") % game.inbase)
5604 for i in range(game.inbase):
5605 proutn(repr(game.state.baseq[i]))
5608 proutn(_("The Enterprise is currently in Quadrant %s") % game.quadrant)
5609 proutn(_(" Sector %s") % game.sector)
5611 prout(_("Good Luck!"))
5612 if game.state.nscrem:
5613 prout(_(" YOU'LL NEED IT."))
5616 setwnd(message_window)
5618 if len(game.enemies) - (thing == game.quadrant) - (game.tholian != None):
5620 if game.neutz: # bad luck to start in a Romulan Neutral Zone
5621 attack(torps_ok=False)
5624 "Choose your game type."
5626 game.tourn = game.length = 0
5628 game.skill = SKILL_NONE
5630 # if not scanner.inqueue: # Can start with command line options
5631 proutn(_("Would you like a regular, tournament, or saved game? "))
5633 if scanner.sees("tournament"):
5634 while scanner.nexttok() == "IHEOL":
5635 proutn(_("Type in tournament number-"))
5636 if scanner.real == 0:
5638 continue # We don't want a blank entry
5639 game.tourn = int(round(scanner.real))
5640 random.seed(scanner.real)
5642 logfp.write("# random.seed(%d)\n" % scanner.real)
5644 if scanner.sees("saved") or scanner.sees("frozen"):
5648 if game.passwd is None:
5650 if not game.alldone:
5651 game.thawed = True # No plaque if not finished
5655 if scanner.sees("regular"):
5657 proutn(_("What is \"%s\"? ") % scanner.token)
5659 while game.length==0 or game.skill==SKILL_NONE:
5660 if scanner.nexttok() == "IHALPHA":
5661 if scanner.sees("short"):
5663 elif scanner.sees("medium"):
5665 elif scanner.sees("long"):
5667 elif scanner.sees("novice"):
5668 game.skill = SKILL_NOVICE
5669 elif scanner.sees("fair"):
5670 game.skill = SKILL_FAIR
5671 elif scanner.sees("good"):
5672 game.skill = SKILL_GOOD
5673 elif scanner.sees("expert"):
5674 game.skill = SKILL_EXPERT
5675 elif scanner.sees("emeritus"):
5676 game.skill = SKILL_EMERITUS
5678 proutn(_("What is \""))
5679 proutn(scanner.token)
5684 proutn(_("Would you like a Short, Medium, or Long game? "))
5685 elif game.skill == SKILL_NONE:
5686 proutn(_("Are you a Novice, Fair, Good, Expert, or Emeritus player? "))
5687 # Choose game options -- added by ESR for SST2K
5688 if scanner.nexttok() != "IHALPHA":
5690 proutn(_("Choose your game style (plain, almy, fancy or just press enter): "))
5692 if scanner.sees("plain"):
5693 # Approximates the UT FORTRAN version.
5694 game.options &=~ (OPTION_THOLIAN | OPTION_PLANETS | OPTION_THINGY | OPTION_PROBE | OPTION_RAMMING | OPTION_MVBADDY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
5695 game.options |= OPTION_PLAIN
5696 elif scanner.sees("almy"):
5697 # Approximates Tom Almy's version.
5698 game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
5699 game.options |= OPTION_ALMY
5700 elif scanner.sees("fancy") or scanner.sees("\n"):
5702 elif len(scanner.token):
5703 proutn(_("What is \"%s\"?") % scanner.token)
5704 game.options &=~ OPTION_COLOR
5706 if game.passwd == "debug":
5708 prout("=== Debug mode enabled.")
5709 # Use parameters to generate initial values of things
5710 game.damfac = 0.5 * game.skill
5711 game.inbase = randrange(BASEMIN, BASEMAX+1)
5713 if game.options & OPTION_PLANETS:
5714 game.inplan += randrange(MAXUNINHAB/2, MAXUNINHAB+1)
5715 if game.options & OPTION_WORLDS:
5716 game.inplan += int(NINHAB)
5717 game.state.nromrem = game.inrom = randrange(2 *game.skill)
5718 game.state.nscrem = game.inscom = (game.skill > SKILL_FAIR)
5719 game.state.remtime = 7.0 * game.length
5720 game.intime = game.state.remtime
5721 game.state.remkl = game.inkling = 2.0*game.intime*((game.skill+1 - 2*randreal())*game.skill*0.1+.15)
5722 game.incom = min(MINCMDR, int(game.skill + 0.0625*game.inkling*randreal()))
5723 game.state.remres = (game.inkling+4*game.incom)*game.intime
5724 game.inresor = game.state.remres
5725 if game.inkling > 50:
5729 def dropin(iquad=None):
5730 "Drop a feature on a random dot in the current quadrant."
5732 w = randplace(QUADSIZE)
5733 if game.quad[w.i][w.j] == '.':
5735 if iquad is not None:
5736 game.quad[w.i][w.j] = iquad
5740 "Update our alert status."
5741 game.condition = "green"
5742 if game.energy < 1000.0:
5743 game.condition = "yellow"
5744 if game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons or game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans:
5745 game.condition = "red"
5747 game.condition="dead"
5750 "Drop new Klingon into current quadrant."
5751 return Enemy('K', loc=dropin(), power=randreal(300,450)+25.0*game.skill)
5754 "Sort enemies by distance so 'nearest' is meaningful."
5755 game.enemies.sort(key=lambda x: x.kdist)
5758 "Set up a new state of quadrant, for when we enter or re-enter it."
5761 game.neutz = game.inorbit = game.landed = False
5762 game.ientesc = game.iseenit = False
5763 # Create a blank quadrant
5764 game.quad = fill2d(QUADSIZE, lambda i, j: '.')
5766 # Attempt to escape Super-commander, so tbeam back!
5769 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
5770 # cope with supernova
5773 game.klhere = q.klingons
5774 game.irhere = q.romulans
5776 game.quad[game.sector.i][game.sector.j] = game.ship
5779 # Position ordinary Klingons
5780 for _i in range(game.klhere):
5782 # If we need a commander, promote a Klingon
5783 for cmdr in game.state.kcmdr:
5784 if cmdr == game.quadrant:
5785 e = game.enemies[game.klhere-1]
5786 game.quad[e.location.i][e.location.j] = 'C'
5787 e.power = randreal(950,1350) + 50.0*game.skill
5789 # If we need a super-commander, promote a Klingon
5790 if game.quadrant == game.state.kscmdr:
5792 game.quad[e.location.i][e.location.j] = 'S'
5793 e.power = randreal(1175.0, 1575.0) + 125.0*game.skill
5794 game.iscate = (game.state.remkl > 1)
5795 # Put in Romulans if needed
5796 for _i in range(q.romulans):
5797 Enemy('R', loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill)
5798 # If quadrant needs a starbase, put it in
5800 game.base = dropin('B')
5801 # If quadrant needs a planet, put it in
5803 game.iplnet = q.planet
5804 if not q.planet.inhabited:
5805 game.plnet = dropin('P')
5807 game.plnet = dropin('@')
5808 # Check for condition
5811 if game.irhere > 0 and game.klhere == 0:
5813 if not damaged(DRADIO):
5815 prout(_("LT. Uhura- \"Captain, an urgent message."))
5816 prout(_(" I'll put it on audio.\" CLICK"))
5818 prout(_("INTRUDER! YOU HAVE VIOLATED THE ROMULAN NEUTRAL ZONE."))
5819 prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!"))
5820 # Put in THING if needed
5821 if thing == game.quadrant:
5822 Enemy(etype='?', loc=dropin(),
5823 power=randreal(6000,6500.0)+250.0*game.skill)
5824 if not damaged(DSRSENS):
5826 prout(_("Mr. Spock- \"Captain, this is most unusual."))
5827 prout(_(" Please examine your short-range scan.\""))
5828 # Decide if quadrant needs a Tholian; lighten up if skill is low
5829 if game.options & OPTION_THOLIAN:
5830 if (game.skill < SKILL_GOOD and withprob(0.02)) or \
5831 (game.skill == SKILL_GOOD and withprob(0.05)) or \
5832 (game.skill > SKILL_GOOD and withprob(0.08)):
5835 w.i = withprob(0.5) * (QUADSIZE-1)
5836 w.j = withprob(0.5) * (QUADSIZE-1)
5837 if game.quad[w.i][w.j] == '.':
5839 game.tholian = Enemy(etype='T', loc=w,
5840 power=randrange(100, 500) + 25.0*game.skill)
5841 # Reserve unoccupied corners
5842 if game.quad[0][0]=='.':
5843 game.quad[0][0] = 'X'
5844 if game.quad[0][QUADSIZE-1]=='.':
5845 game.quad[0][QUADSIZE-1] = 'X'
5846 if game.quad[QUADSIZE-1][0]=='.':
5847 game.quad[QUADSIZE-1][0] = 'X'
5848 if game.quad[QUADSIZE-1][QUADSIZE-1]=='.':
5849 game.quad[QUADSIZE-1][QUADSIZE-1] = 'X'
5851 # And finally the stars
5852 for _i in range(q.stars):
5854 # Put in a few black holes
5855 for _i in range(1, 3+1):
5858 # Take out X's in corners if Tholian present
5860 if game.quad[0][0]=='X':
5861 game.quad[0][0] = '.'
5862 if game.quad[0][QUADSIZE-1]=='X':
5863 game.quad[0][QUADSIZE-1] = '.'
5864 if game.quad[QUADSIZE-1][0]=='X':
5865 game.quad[QUADSIZE-1][0] = '.'
5866 if game.quad[QUADSIZE-1][QUADSIZE-1]=='X':
5867 game.quad[QUADSIZE-1][QUADSIZE-1] = '.'
5870 "Set the self-destruct password."
5871 if game.options & OPTION_PLAIN:
5874 proutn(_("Please type in a secret password- "))
5876 game.passwd = scanner.token
5877 if game.passwd != None:
5881 game.passwd += chr(ord('a')+randrange(26))
5882 game.passwd += chr(ord('a')+randrange(26))
5883 game.passwd += chr(ord('a')+randrange(26))
5885 # Code from sst.c begins here
5888 ("SRSCAN", OPTION_TTY),
5889 ("STATUS", OPTION_TTY),
5890 ("REQUEST", OPTION_TTY),
5891 ("LRSCAN", OPTION_TTY),
5904 ("SENSORS", OPTION_PLANETS),
5905 ("ORBIT", OPTION_PLANETS),
5906 ("TRANSPORT", OPTION_PLANETS),
5907 ("MINE", OPTION_PLANETS),
5908 ("CRYSTALS", OPTION_PLANETS),
5909 ("SHUTTLE", OPTION_PLANETS),
5910 ("PLANETS", OPTION_PLANETS),
5915 ("PROBE", OPTION_PROBE),
5917 ("FREEZE", 0), # Synonym for SAVE
5923 ("SOS", 0), # Synonym for MAYDAY
5924 ("CALL", 0), # Synonym for MAYDAY
5931 "Generate a list of legal commands."
5932 prout(_("LEGAL COMMANDS ARE:"))
5934 for (key, opt) in commands:
5935 if not opt or (opt & game.options):
5936 proutn("%-12s " % key)
5938 if emitted % 5 == 4:
5943 "Browse on-line help."
5944 key = scanner.nexttok()
5947 setwnd(prompt_window)
5948 proutn(_("Help on what command? "))
5949 key = scanner.nexttok()
5950 setwnd(message_window)
5953 cmds = [x[0] for x in commands]
5954 if scanner.token.upper() in cmds or scanner.token.upper() == "ABBREV":
5961 cmd = scanner.token.upper()
5962 for directory in docpath:
5964 fp = open(os.path.join(directory, "sst.doc"), "r")
5969 prout(_("Spock- \"Captain, that information is missing from the"))
5970 prout(_(" computer. You need to find sst.doc and put it somewhere"))
5971 proutn(_(" in these directories: %s") % ":".join(docpath))
5973 # This used to continue: "You need to find SST.DOC and put
5974 # it in the current directory."
5977 linebuf = fp.readline()
5979 prout(_("Spock- \"Captain, there is no information on that command.\""))
5982 if linebuf[0] == '%' and linebuf[1] == '%' and linebuf[2] == ' ':
5983 linebuf = linebuf[3:].strip()
5984 if cmd.upper() == linebuf:
5987 prout(_("Spock- \"Captain, I've found the following information:\""))
5990 linebuf = fp.readline()
5991 if "******" in linebuf:
5997 "Command-interpretation loop."
5998 while True: # command loop
6000 while True: # get a command
6002 game.optime = game.justin = False
6004 setwnd(prompt_window)
6007 if scanner.nexttok() == "IHEOL":
6008 if game.options & OPTION_CURSES:
6011 elif scanner.token == "":
6015 setwnd(message_window)
6017 abandon_passed = False
6018 cmd = "" # Force cmd to persist after loop
6019 opt = 0 # Force opt to persist after loop
6020 for (cmd, opt) in commands:
6021 # commands after ABANDON cannot be abbreviated
6022 if cmd == "ABANDON":
6023 abandon_passed = True
6024 if cmd == scanner.token.upper() or (not abandon_passed \
6025 and cmd.startswith(scanner.token.upper())):
6030 elif opt and not (opt & game.options):
6034 if cmd == "SRSCAN": # srscan
6036 elif cmd == "STATUS": # status
6038 elif cmd == "REQUEST": # status request
6040 elif cmd == "LRSCAN": # long range scan
6041 lrscan(silent=False)
6042 elif cmd == "PHASERS": # phasers
6046 elif cmd in ("TORPEDO", "PHOTONS"): # photon torpedos
6050 elif cmd == "MOVE": # move under warp
6051 warp(wcourse=None, involuntary=False)
6052 elif cmd == "SHIELDS": # shields
6053 doshield(shraise=False)
6056 game.shldchg = False
6057 elif cmd == "DOCK": # dock at starbase
6060 attack(torps_ok=False)
6061 elif cmd == "DAMAGES": # damage reports
6063 elif cmd == "CHART": # chart
6065 elif cmd == "IMPULSE": # impulse
6067 elif cmd == "REST": # rest
6071 elif cmd == "WARP": # warp
6073 elif cmd == "SCORE": # score
6075 elif cmd == "SENSORS": # sensors
6077 elif cmd == "ORBIT": # orbit
6081 elif cmd == "TRANSPORT": # transport "beam"
6083 elif cmd == "MINE": # mine
6087 elif cmd == "CRYSTALS": # crystals
6091 elif cmd == "SHUTTLE": # shuttle
6095 elif cmd == "PLANETS": # Planet list
6097 elif cmd == "REPORT": # Game Report
6099 elif cmd == "COMPUTER": # use COMPUTER!
6101 elif cmd == "COMMANDS":
6103 elif cmd == "EMEXIT": # Emergency exit
6104 clrscr() # Hide screen
6105 freeze(True) # forced save
6106 raise SystemExit(1) # And quick exit
6107 elif cmd == "PROBE":
6108 probe() # Launch probe
6111 elif cmd == "ABANDON": # Abandon Ship
6113 elif cmd == "DESTRUCT": # Self Destruct
6115 elif cmd == "SAVE": # Save Game
6118 if game.skill > SKILL_GOOD:
6119 prout(_("WARNING--Saved games produce no plaques!"))
6120 elif cmd == "DEATHRAY": # Try a desparation measure
6124 elif cmd == "DEBUGCMD": # What do we want for debug???
6126 elif cmd == "MAYDAY": # Call for help
6131 game.alldone = True # quit the game
6136 break # Game has ended
6137 if game.optime != 0.0:
6140 break # Events did us in
6141 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6144 if hitme and not game.justin:
6145 attack(torps_ok=True)
6148 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6159 "Emit the name of an enemy or feature."
6160 if ch == 'R': s = _("Romulan")
6161 elif ch == 'K': s = _("Klingon")
6162 elif ch == 'C': s = _("Commander")
6163 elif ch == 'S': s = _("Super-commander")
6164 elif ch == '*': s = _("Star")
6165 elif ch == 'P': s = _("Planet")
6166 elif ch == 'B': s = _("Starbase")
6167 elif ch == ' ': s = _("Black hole")
6168 elif ch == 'T': s = _("Tholian")
6169 elif ch == '#': s = _("Tholian web")
6170 elif ch == '?': s = _("Stranger")
6171 elif ch == '@': s = _("Inhabited World")
6172 else: s = "Unknown??"
6175 def crmena(loud, enemy, loctype, w):
6176 "Emit the name of an enemy and his location."
6180 buf += cramen(enemy) + _(" at ")
6181 if loctype == "quadrant":
6182 buf += _("Quadrant ")
6183 elif loctype == "sector":
6185 return buf + repr(w)
6188 "Emit our ship name."
6189 return{'E':_("Enterprise"),'F':_("Faerie Queene")}.get(game.ship,"Ship???")
6192 "Emit a line of stars"
6193 prouts("******************************************************")
6197 return -avrage*math.log(1e-7 + randreal())
6199 def randplace(size):
6200 "Choose a random location."
6202 w.i = randrange(size)
6203 w.j = randrange(size)
6213 # Get a token from the user
6216 # Fill the token quue if nothing here
6217 while not self.inqueue:
6219 if curwnd==prompt_window:
6221 setwnd(message_window)
6228 self.inqueue = sline.lstrip().split() + ["\n"]
6229 # From here on in it's all looking at the queue
6230 self.token = self.inqueue.pop(0)
6231 if self.token == "\n":
6235 self.real = float(self.token)
6236 self.type = "IHREAL"
6241 self.token = self.token.lower()
6242 self.type = "IHALPHA"
6245 def append(self, tok):
6246 self.inqueue.append(tok)
6247 def push(self, tok):
6248 self.inqueue.insert(0, tok)
6252 # Demand input for next scan
6254 self.real = self.token = None
6256 # compares s to item and returns true if it matches to the length of s
6257 return s.startswith(self.token)
6259 # Round token value to nearest integer
6260 return int(round(self.real))
6264 if self.type != "IHREAL":
6269 if self.type != "IHREAL":
6275 return "<sstcanner: token=%s, type=%s, queue=%s>" % (self.token, self.type, self.inqueue)
6278 "Yes-or-no confirmation."
6282 if scanner.token == 'y':
6284 if scanner.token == 'n':
6287 proutn(_("Please answer with \"y\" or \"n\": "))
6290 "Complain about unparseable input."
6293 prout(_("Beg your pardon, Captain?"))
6296 "Access to the internals for debugging."
6297 proutn("Reset levels? ")
6299 if game.energy < game.inenrg:
6300 game.energy = game.inenrg
6301 game.shield = game.inshld
6302 game.torps = game.intorps
6303 game.lsupres = game.inlsr
6304 proutn("Reset damage? ")
6306 for i in range(NDEVICES):
6307 if game.damage[i] > 0.0:
6308 game.damage[i] = 0.0
6309 proutn("Toggle debug flag? ")
6311 game.idebug = not game.idebug
6313 prout("Debug output ON")
6315 prout("Debug output OFF")
6316 proutn("Cause selective damage? ")
6318 for i in range(NDEVICES):
6319 proutn("Kill %s?" % device[i])
6321 key = scanner.nexttok()
6322 if key == "IHALPHA" and scanner.sees("y"):
6323 game.damage[i] = 10.0
6324 proutn("Examine/change events? ")
6329 FSNOVA: "Supernova ",
6332 FBATTAK: "Base Attack ",
6333 FCDBAS: "Base Destroy ",
6334 FSCMOVE: "SC Move ",
6335 FSCDBAS: "SC Base Destroy ",
6336 FDSPROB: "Probe Move ",
6337 FDISTR: "Distress Call ",
6338 FENSLV: "Enslavement ",
6339 FREPRO: "Klingon Build ",
6341 for i in range(1, NEVENTS):
6344 proutn("%.2f" % (scheduled(i)-game.state.date))
6345 if i == FENSLV or i == FREPRO:
6347 proutn(" in %s" % ev.quadrant)
6352 key = scanner.nexttok()
6356 elif key == "IHREAL":
6357 ev = schedule(i, scanner.real)
6358 if i == FENSLV or i == FREPRO:
6360 proutn("In quadrant- ")
6361 key = scanner.nexttok()
6362 # "IHEOL" says to leave coordinates as they are
6365 prout("Event %d canceled, no x coordinate." % (i))
6368 w.i = int(round(scanner.real))
6369 key = scanner.nexttok()
6371 prout("Event %d canceled, no y coordinate." % (i))
6374 w.j = int(round(scanner.real))
6377 proutn("Induce supernova here? ")
6379 game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova = True
6382 if __name__ == '__main__':
6384 #global line, thing, game
6388 game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY)
6389 if os.getenv("TERM"):
6390 game.options |= OPTION_CURSES
6392 game.options |= OPTION_TTY
6393 seed = int(time.time())
6394 (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:txV")
6396 for (switch, val) in options:
6399 replayfp = open(val, "r")
6401 sys.stderr.write("sst: can't open replay file %s\n" % val)
6404 line = replayfp.readline().strip()
6405 (leader, __, seed) = line.split()
6407 sys.stderr.write("sst2k: seed set to %s\n" % seed)
6408 line = replayfp.readline().strip()
6409 arguments += line.split()[2:]
6412 sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
6414 game.options |= OPTION_TTY
6415 game.options &=~ OPTION_CURSES
6416 elif switch == '-s':
6418 elif switch == '-t':
6419 game.options |= OPTION_TTY
6420 game.options &=~ OPTION_CURSES
6421 elif switch == '-x':
6423 elif switch == '-V':
6424 print("SST2K", version)
6427 sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n")
6429 # where to save the input in case of bugs
6430 if "TMPDIR" in os.environ:
6431 tmpdir = os.environ['TMPDIR']
6435 logfp = open(os.path.join(tmpdir, "sst-input.log"), "w")
6437 sys.stderr.write("sst: warning, can't open logfile\n")
6440 logfp.write("# seed %s\n" % seed)
6441 logfp.write("# options %s\n" % " ".join(arguments))
6442 logfp.write("# SST2K version %s\n" % version)
6443 logfp.write("# recorded by %s@%s on %s\n" % \
6444 (getpass.getuser(),socket.gethostname(),time.ctime()))
6446 scanner = sstscanner()
6447 for arg in arguments:
6451 while True: # Play a game
6452 setwnd(fullscreen_window)
6458 game.alldone = False
6466 if game.tourn and game.alldone:
6467 proutn(_("Do you want your score recorded?"))
6473 proutn(_("Do you want to play again? "))
6477 prout(_("May the Great Bird of the Galaxy roost upon your home planet."))
6481 except KeyboardInterrupt: