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