3 sst.py -- Super Star Trek 2K
5 SST2K is a Python translation of a C translation of a FORTRAN
6 original dating back to 1973. Beautiful Python it is not, but it
7 works. Translation by Eric S. Raymond; original game by David Matuszek
8 and Paul Reynolds, with modifications by Don Smith, Tom Almy,
9 Stas Sergeev, and Eric S. Raymond.
11 See the doc/HACKING file in the distribution for designers notes and advice
12 on how to modify (and how not to modify!) this code.
14 import os, sys, math, curses, time, pickle, random, copy, gettext, getpass
15 import getopt, socket, locale
17 # This import only works on Unixes. The intention is to enable
18 # Ctrl-P, Ctrl-N, and friends in Cmd.
26 docpath = (".", "doc/", "/usr/share/doc/sst/")
29 return gettext.gettext(st)
31 GALSIZE = 8 # Galaxy size in quadrants
32 NINHAB = (GALSIZE * GALSIZE // 2) # Number of inhabited worlds
33 MAXUNINHAB = 10 # Maximum uninhabited worlds
34 QUADSIZE = 10 # Quadrant size in sectors
35 BASEMIN = 2 # Minimum starbases
36 BASEMAX = (GALSIZE * GALSIZE // 12) # Maximum starbases
37 MAXKLGAME = 127 # Maximum Klingons per game
38 MAXKLQUAD = 9 # Maximum Klingons per quadrant
39 FULLCREW = 428 # Crew size. BSD Trek was 387, that's wrong
40 FOREVER = 1e30 # Time for the indefinite future
41 MAXBURST = 3 # Max # of torps you can launch in one turn
42 MINCMDR = 10 # Minimum number of Klingon commanders
43 DOCKFAC = 0.25 # Repair faster when docked
44 PHASEFAC = 2.0 # Unclear what this is, it was in the C version
64 class TrekError(Exception):
67 class JumpOut(Exception):
71 def __init__(self, x=None, y=None):
74 def valid_quadrant(self):
75 return self.i >= 0 and self.i < GALSIZE and self.j >= 0 and self.j < GALSIZE
76 def valid_sector(self):
77 return self.i >= 0 and self.i < QUADSIZE and self.j >= 0 and self.j < QUADSIZE
79 self.i = self.j = None
81 return self.i != None and self.j != None
82 def __eq__(self, other):
83 return other != None and self.i == other.i and self.j == other.j
84 def __ne__(self, other):
85 return other is None or self.i != other.i or self.j != other.j
86 def __add__(self, other):
87 return Coord(self.i+other.i, self.j+other.j)
88 def __sub__(self, other):
89 return Coord(self.i-other.i, self.j-other.j)
90 def __mul__(self, other):
91 return Coord(self.i*other, self.j*other)
92 def __rmul__(self, other):
93 return Coord(self.i*other, self.j*other)
94 def __div__(self, other):
95 return Coord(self.i/other, self.j/other)
96 def __mod__(self, other):
97 return Coord(self.i % other, self.j % other)
98 def __rdiv__(self, other):
99 return Coord(self.i/other, self.j/other)
100 def roundtogrid(self):
101 return Coord(int(round(self.i)), int(round(self.j)))
102 def distance(self, other=None):
105 return math.sqrt((self.i - other.i)**2 + (self.j - other.j)**2)
107 return 1.90985*math.atan2(self.j, self.i)
113 s.i = self.i / abs(self.i)
117 s.j = self.j / abs(self.j)
120 #print "Location %s -> %s" % (self, (self / QUADSIZE).roundtogrid())
121 return self.roundtogrid() / QUADSIZE
123 return self.roundtogrid() % QUADSIZE
126 s.i = self.i + randrange(-1, 2)
127 s.j = self.j + randrange(-1, 2)
130 if self.i is None or self.j is None:
132 return "%s - %s" % (self.i+1, self.j+1)
136 "Do not anger the Space Thingy!"
143 return (q.i, q.j) == (self.i, self.j)
147 self.name = None # string-valued if inhabited
148 self.quadrant = Coord() # quadrant located
149 self.pclass = None # could be ""M", "N", "O", or "destroyed"
150 self.crystals = "absent"# could be "mined", "present", "absent"
151 self.known = "unknown" # could be "unknown", "known", "shuttle_down"
152 self.inhabited = False # is it inhabited?
160 self.starbase = False
163 self.supernova = False
165 self.status = "secure" # Could be "secure", "distressed", "enslaved"
170 self.starbase = False
173 return "<%s,%s,%s>" % (self.klingons, self.starbase, self.stars)
175 def fill2d(size, fillfun):
176 "Fill an empty list in 2D."
178 for i in range(size):
180 for j in range(size):
181 lst[i].append(fillfun(i, j))
186 self.snap = False # snapshot taken
187 self.crew = 0 # crew complement
188 self.remkl = 0 # remaining klingons
189 self.nscrem = 0 # remaining super commanders
190 self.starkl = 0 # destroyed stars
191 self.basekl = 0 # destroyed bases
192 self.nromrem = 0 # Romulans remaining
193 self.nplankl = 0 # destroyed uninhabited planets
194 self.nworldkl = 0 # destroyed inhabited planets
195 self.planets = [] # Planet information
196 self.date = 0.0 # stardate
197 self.remres = 0 # remaining resources
198 self.remtime = 0 # remaining time
199 self.baseq = [] # Base quadrant coordinates
200 self.kcmdr = [] # Commander quadrant coordinates
201 self.kscmdr = Coord() # Supercommander quadrant coordinates
203 self.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
205 self.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
209 self.date = None # A real number
210 self.quadrant = None # A coord structure
213 OPTION_ALL = 0xffffffff
214 OPTION_TTY = 0x00000001 # old interface
215 OPTION_CURSES = 0x00000002 # new interface
216 OPTION_IOMODES = 0x00000003 # cover both interfaces
217 OPTION_PLANETS = 0x00000004 # planets and mining
218 OPTION_THOLIAN = 0x00000008 # Tholians and their webs (UT 1979 version)
219 OPTION_THINGY = 0x00000010 # Space Thingy can shoot back (Stas, 2005)
220 OPTION_PROBE = 0x00000020 # deep-space probes (DECUS version, 1980)
221 OPTION_SHOWME = 0x00000040 # bracket Enterprise in chart
222 OPTION_RAMMING = 0x00000080 # enemies may ram Enterprise (Almy)
223 OPTION_MVBADDY = 0x00000100 # more enemies can move (Almy)
224 OPTION_BLKHOLE = 0x00000200 # black hole may timewarp you (Stas, 2005)
225 OPTION_BASE = 0x00000400 # bases have good shields (Stas, 2005)
226 OPTION_WORLDS = 0x00000800 # logic for inhabited worlds (ESR, 2006)
227 OPTION_AUTOSCAN = 0x00001000 # automatic LRSCAN before CHART (ESR, 2006)
228 OPTION_PLAIN = 0x01000000 # user chose plain game
229 OPTION_ALMY = 0x02000000 # user chose Almy variant
230 OPTION_COLOR = 0x04000000 # enable color display (ESR, 2010)
231 OPTION_CAPTURE = 0x80000000 # Enable BSD-Trek capture (Almy, 2013).
250 NDEVICES = 16 # Number of devices
260 return (game.damage[dev] != 0.0)
262 return not damaged(DRADIO) or game.condition=="docked"
264 # Define future events
265 FSPY = 0 # Spy event happens always (no future[] entry)
266 # can cause SC to tractor beam Enterprise
267 FSNOVA = 1 # Supernova
268 FTBEAM = 2 # Commander tractor beams Enterprise
269 FSNAP = 3 # Snapshot for time warp
270 FBATTAK = 4 # Commander attacks base
271 FCDBAS = 5 # Commander destroys base
272 FSCMOVE = 6 # Supercommander moves (might attack base)
273 FSCDBAS = 7 # Supercommander destroys base
274 FDSPROB = 8 # Move deep space probe
275 FDISTR = 9 # Emit distress call from an inhabited world
276 FENSLV = 10 # Inhabited word is enslaved */
277 FREPRO = 11 # Klingons build a ship in an enslaved system
280 # Abstract out the event handling -- underlying data structures will change
281 # when we implement stateful events
282 def findevent(evtype):
283 return game.future[evtype]
286 def __init__(self, etype=None, loc=None, power=None):
288 self.location = Coord()
293 self.power = power # enemy energy level
294 game.enemies.append(self)
296 motion = (loc != self.location)
297 if self.location.i is not None and self.location.j is not None:
300 game.quad[self.location.i][self.location.j] = '#'
302 game.quad[self.location.i][self.location.j] = '.'
304 self.location = copy.copy(loc)
305 game.quad[self.location.i][self.location.j] = self.type
306 self.kdist = self.kavgd = (game.sector - loc).distance()
308 self.location = Coord()
309 self.kdist = self.kavgd = None
310 game.enemies.remove(self)
313 return "<%s,%s.%f>" % (self.type, self.location, self.power) # For debugging
317 self.options = None # Game options
318 self.state = Snapshot() # A snapshot structure
319 self.snapsht = Snapshot() # Last snapshot taken for time-travel purposes
320 self.quad = None # contents of our quadrant
321 self.damage = [0.0] * NDEVICES # damage encountered
322 self.future = [] # future events
326 self.future.append(Event())
327 self.passwd = None # Self Destruct password
329 self.quadrant = None # where we are in the large
330 self.sector = None # where we are in the small
331 self.tholian = None # Tholian enemy object
332 self.base = None # position of base in current quadrant
333 self.battle = None # base coordinates being attacked
334 self.plnet = None # location of planet in quadrant
335 self.gamewon = False # Finished!
336 self.ididit = False # action taken -- allows enemy to attack
337 self.alive = False # we are alive (not killed)
338 self.justin = False # just entered quadrant
339 self.shldup = False # shields are up
340 self.shldchg = False # shield is changing (affects efficiency)
341 self.iscate = False # super commander is here
342 self.ientesc = False # attempted escape from supercommander
343 self.resting = False # rest time
344 self.icraft = False # Kirk in Galileo
345 self.landed = False # party on planet (true), on ship (false)
346 self.alldone = False # game is now finished
347 self.neutz = False # Romulan Neutral Zone
348 self.isarmed = False # probe is armed
349 self.inorbit = False # orbiting a planet
350 self.imine = False # mining
351 self.icrystl = False # dilithium crystals aboard
352 self.iseenit = False # seen base attack report
353 self.thawed = False # thawed game
354 self.condition = None # "green", "yellow", "red", "docked", "dead"
355 self.iscraft = None # "onship", "offship", "removed"
356 self.skill = None # Player skill level
357 self.inkling = 0 # initial number of klingons
358 self.inbase = 0 # initial number of bases
359 self.incom = 0 # initial number of commanders
360 self.inscom = 0 # initial number of commanders
361 self.inrom = 0 # initial number of commanders
362 self.instar = 0 # initial stars
363 self.intorps = 0 # initial/max torpedoes
364 self.torps = 0 # number of torpedoes
365 self.ship = 0 # ship type -- 'E' is Enterprise
366 self.abandoned = 0 # count of crew abandoned in space
367 self.length = 0 # length of game
368 self.klhere = 0 # klingons here
369 self.casual = 0 # causalties
370 self.nhelp = 0 # calls for help
371 self.nkinks = 0 # count of energy-barrier crossings
372 self.iplnet = None # planet # in quadrant
373 self.inplan = 0 # initial planets
374 self.irhere = 0 # Romulans in quadrant
375 self.isatb = 0 # =2 if super commander is attacking base
376 self.tourn = None # tournament number
377 self.nprobes = 0 # number of probes available
378 self.inresor = 0.0 # initial resources
379 self.intime = 0.0 # initial time
380 self.inenrg = 0.0 # initial/max energy
381 self.inshld = 0.0 # initial/max shield
382 self.inlsr = 0.0 # initial life support resources
383 self.indate = 0.0 # initial date
384 self.energy = 0.0 # energy level
385 self.shield = 0.0 # shield level
386 self.warpfac = 0.0 # warp speed
387 self.lsupres = 0.0 # life support reserves
388 self.optime = 0.0 # time taken by current operation
389 self.damfac = 0.0 # damage factor
390 self.lastchart = 0.0 # time star chart was last updated
391 self.cryprob = 0.0 # probability that crystal will work
392 self.probe = None # object holding probe course info
393 self.height = 0.0 # height of orbit around planet
394 self.score = 0.0 # overall score
395 self.perdate = 0.0 # rate of kills
396 self.idebug = False # Debugging instrumentation enabled?
397 self.statekscmdr = None # No SuperCommander coordinates yet.
398 self.brigcapacity = 400 # Enterprise brig capacity
399 self.brigfree = 400 # How many klingons can we put in the brig?
400 self.kcaptured = 0 # Total Klingons captured, for scoring.
402 # Stas thinks this should be (C expression):
403 # game.state.remkl + len(game.state.kcmdr) > 0 ?
404 # game.state.remres/(game.state.remkl + 4*len(game.state.kcmdr)) : 99
405 # He says the existing expression is prone to divide-by-zero errors
406 # after killing the last klingon when score is shown -- perhaps also
407 # if the only remaining klingon is SCOM.
408 self.state.remtime = self.state.remres/(self.state.remkl + 4*len(self.state.kcmdr))
434 return random.random() < p
436 def randrange(*args):
437 return random.randrange(*args)
442 v *= args[0] # from [0, args[0])
444 v = args[0] + v*(args[1]-args[0]) # from [args[0], args[1])
447 # Code from ai.c begins here
450 "Would this quadrant welcome another Klingon?"
451 return iq.valid_quadrant() and \
452 not game.state.galaxy[iq.i][iq.j].supernova and \
453 game.state.galaxy[iq.i][iq.j].klingons < MAXKLQUAD
455 def tryexit(enemy, look, irun):
456 "A bad guy attempts to bug out."
458 iq.i = game.quadrant.i+(look.i+(QUADSIZE-1))/QUADSIZE - 1
459 iq.j = game.quadrant.j+(look.j+(QUADSIZE-1))/QUADSIZE - 1
460 if not welcoming(iq):
462 if enemy.type == 'R':
463 return False # Romulans cannot escape!
465 # avoid intruding on another commander's territory
466 if enemy.type == 'C':
467 if iq in game.state.kcmdr:
469 # refuse to leave if currently attacking starbase
470 if game.battle == game.quadrant:
472 # don't leave if over 1000 units of energy
473 if enemy.power > 1000.0:
475 oldloc = copy.copy(enemy.location)
476 # handle local matters related to escape
479 if game.condition != "docked":
481 # Handle global matters related to escape
482 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
483 game.state.galaxy[iq.i][iq.j].klingons += 1
484 if enemy.type == 'S':
488 schedule(FSCMOVE, 0.2777)
490 game.state.kscmdr = iq
492 for cmdr in game.state.kcmdr:
493 if cmdr == game.quadrant:
494 game.state.kcmdr.append(iq)
496 # report move out of quadrant.
497 return [(True, enemy, oldloc, iq)]
499 # The bad-guy movement algorithm:
501 # 1. Enterprise has "force" based on condition of phaser and photon torpedoes.
502 # If both are operating full strength, force is 1000. If both are damaged,
503 # force is -1000. Having shields down subtracts an additional 1000.
505 # 2. Enemy has forces equal to the energy of the attacker plus
506 # 100*(K+R) + 500*(C+S) - 400 for novice through good levels OR
507 # 346*K + 400*R + 500*(C+S) - 400 for expert and emeritus.
509 # Attacker Initial energy levels (nominal):
510 # Klingon Romulan Commander Super-Commander
511 # Novice 400 700 1200
513 # Good 450 800 1300 1750
514 # Expert 475 850 1350 1875
515 # Emeritus 500 900 1400 2000
516 # VARIANCE 75 200 200 200
518 # Enemy vessels only move prior to their attack. In Novice - Good games
519 # only commanders move. In Expert games, all enemy vessels move if there
520 # is a commander present. In Emeritus games all enemy vessels move.
522 # 3. If Enterprise is not docked, an aggressive action is taken if enemy
523 # forces are 1000 greater than Enterprise.
525 # Agressive action on average cuts the distance between the ship and
526 # the enemy to 1/4 the original.
528 # 4. At lower energy advantage, movement units are proportional to the
529 # advantage with a 650 advantage being to hold ground, 800 to move forward
530 # 1, 950 for two, 150 for back 4, etc. Variance of 100.
532 # If docked, is reduced by roughly 1.75*game.skill, generally forcing a
533 # retreat, especially at high skill levels.
535 # 5. Motion is limited to skill level, except for SC hi-tailing it out.
537 def movebaddy(enemy):
538 "Tactical movement for the bad guys."
542 # This should probably be just (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
543 if game.skill >= SKILL_EXPERT:
544 nbaddys = (((game.quadrant in game.state.kcmdr)*2 + (game.state.kscmdr==game.quadrant)*2+game.klhere*1.23+game.irhere*1.5)/2.0)
546 nbaddys = (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
547 old_dist = enemy.kdist
548 mdist = int(old_dist + 0.5) # Nearest integer distance
549 # If SC, check with spy to see if should hi-tail it
550 if enemy.type == 'S' and \
551 (enemy.power <= 500.0 or (game.condition=="docked" and not damaged(DPHOTON))):
555 # decide whether to advance, retreat, or hold position
556 forces = enemy.power+100.0*len(game.enemies)+400*(nbaddys-1)
558 forces += 1000 # Good for enemy if shield is down!
559 if not damaged(DPHASER) or not damaged(DPHOTON):
560 if damaged(DPHASER): # phasers damaged
563 forces -= 0.2*(game.energy - 2500.0)
564 if damaged(DPHOTON): # photon torpedoes damaged
567 forces -= 50.0*game.torps
569 # phasers and photon tubes both out!
572 if forces <= 1000.0 and game.condition != "docked": # Typical situation
573 motion = ((forces + randreal(200))/150.0) - 5.0
575 if forces > 1000.0: # Very strong -- move in for kill
576 motion = (1.0 - randreal())**2 * old_dist + 1.0
577 if game.condition == "docked" and (game.options & OPTION_BASE): # protected by base -- back off !
578 motion -= game.skill*(2.0-randreal()**2)
580 proutn("=== MOTION = %d, FORCES = %1.2f, " % (motion, forces))
581 # don't move if no motion
584 # Limit motion according to skill
585 if abs(motion) > game.skill:
590 # calculate preferred number of steps
591 nsteps = abs(int(motion))
592 if motion > 0 and nsteps > mdist:
593 nsteps = mdist # don't overshoot
594 if nsteps > QUADSIZE:
595 nsteps = QUADSIZE # This shouldn't be necessary
597 nsteps = 1 # This shouldn't be necessary
599 proutn("NSTEPS = %d:" % nsteps)
600 # Compute preferred values of delta X and Y
601 m = game.sector - enemy.location
602 if 2.0 * abs(m.i) < abs(m.j):
604 if 2.0 * abs(m.j) < abs(game.sector.i-enemy.location.i):
606 m = (motion * m).sgn()
607 goto = enemy.location
609 for ll in range(nsteps):
611 proutn(" %d" % (ll+1))
612 # Check if preferred position available
623 attempts = 0 # Settle mysterious hang problem
624 while attempts < 20 and not success:
626 if look.i < 0 or look.i >= QUADSIZE:
628 return tryexit(enemy, look, irun)
629 if krawli == m.i or m.j == 0:
631 look.i = goto.i + krawli
633 elif look.j < 0 or look.j >= QUADSIZE:
635 return tryexit(enemy, look, irun)
636 if krawlj == m.j or m.i == 0:
638 look.j = goto.j + krawlj
640 elif (game.options & OPTION_RAMMING) and game.quad[look.i][look.j] != '.':
641 # See if enemy should ram ship
642 if game.quad[look.i][look.j] == game.ship and \
643 (enemy.type == 'C' or enemy.type == 'S'):
644 collision(rammed=True, enemy=enemy)
646 if krawli != m.i and m.j != 0:
647 look.i = goto.i + krawli
649 elif krawlj != m.j and m.i != 0:
650 look.j = goto.j + krawlj
653 break # we have failed
664 # Enemy moved, but is still in sector
665 return [(False, enemy, old_dist, goto)]
668 "Sequence Klingon tactical movement."
671 # Figure out which Klingon is the commander (or Supercommander)
674 if game.quadrant in game.state.kcmdr:
675 for enemy in game.enemies:
676 if enemy.type == 'C':
677 tacmoves += movebaddy(enemy)
678 if game.state.kscmdr == game.quadrant:
679 for enemy in game.enemies:
680 if enemy.type == 'S':
681 tacmoves += movebaddy(enemy)
683 # If skill level is high, move other Klingons and Romulans too!
684 # Move these last so they can base their actions on what the
686 if game.skill >= SKILL_EXPERT and (game.options & OPTION_MVBADDY):
687 for enemy in game.enemies:
688 if enemy.type in ('K', 'R'):
689 tacmoves += movebaddy(enemy)
692 def movescom(iq, avoid):
693 "Commander movement helper."
694 # Avoid quadrants with bases if we want to avoid Enterprise
695 if not welcoming(iq) or (avoid and iq in game.state.baseq):
697 if game.justin and not game.iscate:
700 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons -= 1
701 game.state.kscmdr = iq
702 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons += 1
703 if game.state.kscmdr == game.quadrant:
704 # SC has scooted, remove him from current quadrant
709 for enemy in game.enemies:
710 if enemy.type == 'S':
713 if game.condition != "docked":
716 # check for a helpful planet
717 for i in range(game.inplan):
718 if game.state.planets[i].quadrant == game.state.kscmdr and \
719 game.state.planets[i].crystals == "present":
721 game.state.planets[i].pclass = "destroyed"
722 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].planet = None
725 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
726 proutn(_(" a planet in Quadrant %s has been destroyed") % game.state.kscmdr)
727 prout(_(" by the Super-commander.\""))
729 return True # looks good!
731 def supercommander():
732 "Move the Super Commander."
739 prout("== SUPERCOMMANDER")
740 # Decide on being active or passive
741 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 \
742 (game.state.date-game.indate) < 3.0)
743 if not game.iscate and avoid:
744 # compute move away from Enterprise
745 idelta = game.state.kscmdr-game.quadrant
746 if idelta.distance() > 2.0:
748 idelta.i = game.state.kscmdr.j-game.quadrant.j
749 idelta.j = game.quadrant.i-game.state.kscmdr.i
751 # compute distances to starbases
752 if not game.state.baseq:
756 sc = game.state.kscmdr
757 for (i, base) in enumerate(game.state.baseq):
758 basetbl.append((i, (base - sc).distance()))
759 if game.state.baseq > 1:
760 basetbl.sort(key=lambda x: x[1])
761 # look for nearest base without a commander, no Enterprise, and
762 # without too many Klingons, and not already under attack.
763 ifindit = iwhichb = 0
764 for (i2, base) in enumerate(game.state.baseq):
765 i = basetbl[i2][0] # bug in original had it not finding nearest
766 if base == game.quadrant or base == game.battle or not welcoming(base):
768 # if there is a commander, and no other base is appropriate,
769 # we will take the one with the commander
770 for cmdr in game.state.kcmdr:
771 if base == cmdr and ifindit != 2:
775 else: # no commander -- use this one
780 return # Nothing suitable -- wait until next time
781 ibq = game.state.baseq[iwhichb]
782 # decide how to move toward base
783 idelta = ibq - game.state.kscmdr
784 # Maximum movement is 1 quadrant in either or both axes
785 idelta = idelta.sgn()
786 # try moving in both x and y directions
787 # there was what looked like a bug in the Almy C code here,
788 # but it might be this translation is just wrong.
789 iq = game.state.kscmdr + idelta
790 if not movescom(iq, avoid):
791 # failed -- try some other maneuvers
792 if idelta.i == 0 or idelta.j == 0:
795 iq.j = game.state.kscmdr.j + 1
796 if not movescom(iq, avoid):
797 iq.j = game.state.kscmdr.j - 1
800 iq.i = game.state.kscmdr.i + 1
801 if not movescom(iq, avoid):
802 iq.i = game.state.kscmdr.i - 1
805 # try moving just in x or y
806 iq.j = game.state.kscmdr.j
807 if not movescom(iq, avoid):
808 iq.j = game.state.kscmdr.j + idelta.j
809 iq.i = game.state.kscmdr.i
812 if len(game.state.baseq) == 0:
815 for ibq in game.state.baseq:
816 if ibq == game.state.kscmdr and game.state.kscmdr == game.battle:
819 return # no, don't attack base!
822 schedule(FSCDBAS, randreal(1.0, 3.0))
823 if is_scheduled(FCDBAS):
824 postpone(FSCDBAS, scheduled(FCDBAS)-game.state.date)
825 if not communicating():
829 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") \
831 prout(_(" reports that it is under attack from the Klingon Super-commander."))
832 proutn(_(" It can survive until stardate %d.\"") \
833 % int(scheduled(FSCDBAS)))
836 prout(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
840 game.optime = 0.0 # actually finished
842 # Check for intelligence report
843 if not game.idebug and \
845 (not communicating()) or \
846 not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].charted):
849 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
850 proutn(_(" the Super-commander is in Quadrant %s,") % game.state.kscmdr)
855 if not game.tholian or game.justin:
858 if game.tholian.location.i == 0 and game.tholian.location.j == 0:
861 elif game.tholian.location.i == 0 and game.tholian.location.j == QUADSIZE-1:
864 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == QUADSIZE-1:
867 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == 0:
871 # something is wrong!
872 game.tholian.move(None)
873 prout("***Internal error: Tholian in a bad spot.")
875 # do nothing if we are blocked
876 if game.quad[tid.i][tid.j] not in ('.', '#'):
878 here = copy.copy(game.tholian.location)
879 delta = (tid - game.tholian.location).sgn()
881 while here.i != tid.i:
883 if game.quad[here.i][here.j] == '.':
884 game.tholian.move(here)
886 while here.j != tid.j:
888 if game.quad[here.i][here.j] == '.':
889 game.tholian.move(here)
890 # check to see if all holes plugged
891 for i in range(QUADSIZE):
892 if game.quad[0][i] != '#' and game.quad[0][i] != 'T':
894 if game.quad[QUADSIZE-1][i] != '#' and game.quad[QUADSIZE-1][i] != 'T':
896 if game.quad[i][0] != '#' and game.quad[i][0] != 'T':
898 if game.quad[i][QUADSIZE-1] != '#' and game.quad[i][QUADSIZE-1] != 'T':
900 # All plugged up -- Tholian splits
901 game.quad[game.tholian.location.i][game.tholian.location.j] = '#'
903 prout(crmena(True, 'T', "sector", game.tholian) + _(" completes web."))
904 game.tholian.move(None)
907 # Code from battle.c begins here
909 def doshield(shraise):
910 "Change shield status."
916 key = scanner.nexttok()
918 if scanner.sees("transfer"):
922 prout(_("Shields damaged and down."))
924 if scanner.sees("up"):
926 elif scanner.sees("down"):
929 proutn(_("Do you wish to change shield energy? "))
932 elif damaged(DSHIELD):
933 prout(_("Shields damaged and down."))
936 proutn(_("Shields are up. Do you want them down? "))
943 proutn(_("Shields are down. Do you want them up? "))
949 if action == "SHUP": # raise shields
951 prout(_("Shields already up."))
955 if game.condition != "docked":
957 prout(_("Shields raised."))
960 prout(_("Shields raising uses up last of energy."))
965 elif action == "SHDN":
967 prout(_("Shields already down."))
971 prout(_("Shields lowered."))
974 elif action == "NRG":
975 while scanner.nexttok() != "IHREAL":
977 proutn(_("Energy to transfer to shields- "))
982 if nrg > game.energy:
983 prout(_("Insufficient ship energy."))
986 if game.shield+nrg >= game.inshld:
987 prout(_("Shield energy maximized."))
988 if game.shield+nrg > game.inshld:
989 prout(_("Excess energy requested returned to ship energy"))
990 game.energy -= game.inshld-game.shield
991 game.shield = game.inshld
993 if nrg < 0.0 and game.energy-nrg > game.inenrg:
994 # Prevent shield drain loophole
996 prout(_("Engineering to bridge--"))
997 prout(_(" Scott here. Power circuit problem, Captain."))
998 prout(_(" I can't drain the shields."))
1001 if game.shield+nrg < 0:
1002 prout(_("All shield energy transferred to ship."))
1003 game.energy += game.shield
1006 proutn(_("Scotty- \""))
1008 prout(_("Transferring energy to shields.\""))
1010 prout(_("Draining energy from shields.\""))
1016 "Choose a device to damage, at random."
1018 105, # DSRSENS: short range scanners 10.5%
1019 105, # DLRSENS: long range scanners 10.5%
1020 120, # DPHASER: phasers 12.0%
1021 120, # DPHOTON: photon torpedoes 12.0%
1022 25, # DLIFSUP: life support 2.5%
1023 65, # DWARPEN: warp drive 6.5%
1024 70, # DIMPULS: impulse engines 6.5%
1025 145, # DSHIELD: deflector shields 14.5%
1026 30, # DRADIO: subspace radio 3.0%
1027 45, # DSHUTTL: shuttle 4.5%
1028 15, # DCOMPTR: computer 1.5%
1029 20, # NAVCOMP: navigation system 2.0%
1030 75, # DTRANSP: transporter 7.5%
1031 20, # DSHCTRL: high-speed shield controller 2.0%
1032 10, # DDRAY: death ray 1.0%
1033 30, # DDSP: deep-space probes 3.0%
1035 assert(sum(weights) == 1000)
1036 idx = randrange(1000)
1038 for (i, w) in enumerate(weights):
1042 return None # we should never get here
1044 def collision(rammed, enemy):
1045 "Collision handling for rammong events."
1046 prouts(_("***RED ALERT! RED ALERT!"))
1048 prout(_("***COLLISION IMMINENT."))
1052 hardness = {'R':1.5, 'C':2.0, 'S':2.5, 'T':0.5, '?':4.0}.get(enemy.type, 1.0)
1054 proutn(_(" rammed by "))
1057 proutn(crmena(False, enemy.type, "sector", enemy.location))
1059 proutn(_(" (original position)"))
1061 deadkl(enemy.location, enemy.type, game.sector)
1062 proutn("***" + crmshp() + " heavily damaged.")
1063 icas = randrange(10, 30)
1064 prout(_("***Sickbay reports %d casualties") % icas)
1066 game.state.crew -= icas
1067 # In the pre-SST2K version, all devices got equiprobably damaged,
1068 # which was silly. Instead, pick up to half the devices at
1069 # random according to our weighting table,
1070 ncrits = randrange(NDEVICES/2)
1074 if game.damage[dev] < 0:
1076 extradm = (10.0*hardness*randreal()+1.0)*game.damfac
1077 # Damage for at least time of travel!
1078 game.damage[dev] += game.optime + extradm
1080 prout(_("***Shields are down."))
1081 if game.state.remkl + len(game.state.kcmdr) + game.state.nscrem:
1088 def torpedo(origin, bearing, dispersion, number, nburst):
1089 "Let a photon torpedo fly"
1090 if not damaged(DSRSENS) or game.condition == "docked":
1091 setwnd(srscan_window)
1093 setwnd(message_window)
1094 ac = bearing + 0.25*dispersion # dispersion is a random variable
1095 bullseye = (15.0 - bearing)*0.5235988
1096 track = course(bearing=ac, distance=QUADSIZE, origin=cartesian(origin))
1097 bumpto = Coord(0, 0)
1098 # Loop to move a single torpedo
1099 setwnd(message_window)
1100 for step in range(1, QUADSIZE*2):
1101 if not track.nexttok():
1104 if not w.valid_sector():
1106 iquad = game.quad[w.i][w.j]
1107 tracktorpedo(w, step, number, nburst, iquad)
1111 setwnd(message_window)
1112 if not damaged(DSRSENS) or game.condition == "docked":
1113 skip(1) # start new line after text track
1114 if iquad in ('E', 'F'): # Hit our ship
1116 prout(_("Torpedo hits %s.") % crmshp())
1117 hit = 700.0 + randreal(100) - \
1118 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1119 newcnd() # we're blown out of dock
1120 if game.landed or game.condition == "docked":
1121 return hit # Cheat if on a planet
1122 # In the C/FORTRAN version, dispersion was 2.5 radians, which
1123 # is 143 degrees, which is almost exactly 4.8 clockface units
1124 displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
1125 displacement.nexttok()
1126 bumpto = displacement.sector()
1127 if not bumpto.valid_sector():
1129 if game.quad[bumpto.i][bumpto.j] == ' ':
1132 if game.quad[bumpto.i][bumpto.j] != '.':
1133 # can't move into object
1135 game.sector = bumpto
1137 game.quad[w.i][w.j] = '.'
1138 game.quad[bumpto.i][bumpto.j] = iquad
1139 prout(_(" displaced by blast to Sector %s ") % bumpto)
1140 for enemy in game.enemies:
1141 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1144 elif iquad in ('C', 'S', 'R', 'K'): # Hit a regular enemy
1146 if iquad in ('C', 'S') and withprob(0.05):
1147 prout(crmena(True, iquad, "sector", w) + _(" uses anti-photon device;"))
1148 prout(_(" torpedo neutralized."))
1150 for enemy in game.enemies:
1151 if w == enemy.location:
1152 kp = math.fabs(enemy.power)
1153 h1 = 700.0 + randrange(100) - \
1154 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1162 if enemy.power == 0:
1165 proutn(crmena(True, iquad, "sector", w))
1166 displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
1167 displacement.nexttok()
1168 bumpto = displacement.sector()
1169 if not bumpto.valid_sector():
1170 prout(_(" damaged but not destroyed."))
1172 if game.quad[bumpto.i][bumpto.j] == ' ':
1173 prout(_(" buffeted into black hole."))
1174 deadkl(w, iquad, bumpto)
1175 if game.quad[bumpto.i][bumpto.j] != '.':
1176 prout(_(" damaged but not destroyed."))
1178 prout(_(" damaged-- displaced by blast to Sector %s ")%bumpto)
1179 enemy.location = bumpto
1180 game.quad[w.i][w.j] = '.'
1181 game.quad[bumpto.i][bumpto.j] = iquad
1182 for enemy in game.enemies:
1183 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1187 prout("Internal error, no enemy where expected!")
1190 elif iquad == 'B': # Hit a base
1192 prout(_("***STARBASE DESTROYED.."))
1193 game.state.baseq = [x for x in game.state.baseq if x != game.quadrant]
1194 game.quad[w.i][w.j] = '.'
1195 game.base.invalidate()
1196 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
1197 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = False
1198 game.state.basekl += 1
1201 elif iquad == 'P': # Hit a planet
1202 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1203 game.state.nplankl += 1
1204 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1205 game.iplnet.pclass = "destroyed"
1207 game.plnet.invalidate()
1208 game.quad[w.i][w.j] = '.'
1210 # captain perishes on planet
1213 elif iquad == '@': # Hit an inhabited world -- very bad!
1214 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1215 game.state.nworldkl += 1
1216 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1217 game.iplnet.pclass = "destroyed"
1219 game.plnet.invalidate()
1220 game.quad[w.i][w.j] = '.'
1222 # captain perishes on planet
1224 prout(_("The torpedo destroyed an inhabited planet."))
1226 elif iquad == '*': # Hit a star
1230 prout(crmena(True, '*', "sector", w) + _(" unaffected by photon blast."))
1232 elif iquad == '?': # Hit a thingy
1233 if not (game.options & OPTION_THINGY) or withprob(0.3):
1235 prouts(_("AAAAIIIIEEEEEEEEAAAAAAAAUUUUUGGGGGHHHHHHHHHHHH!!!"))
1237 prouts(_(" HACK! HACK! HACK! *CHOKE!* "))
1239 proutn(_("Mr. Spock-"))
1240 prouts(_(" \"Fascinating!\""))
1244 # Stas Sergeev added the possibility that
1245 # you can shove the Thingy and piss it off.
1246 # It then becomes an enemy and may fire at you.
1249 elif iquad == ' ': # Black hole
1251 prout(crmena(True, ' ', "sector", w) + _(" swallows torpedo."))
1253 elif iquad == '#': # hit the web
1255 prout(_("***Torpedo absorbed by Tholian web."))
1257 elif iquad == 'T': # Hit a Tholian
1258 h1 = 700.0 + randrange(100) - \
1259 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1262 game.quad[w.i][w.j] = '.'
1267 proutn(crmena(True, 'T', "sector", w))
1269 prout(_(" survives photon blast."))
1271 prout(_(" disappears."))
1272 game.tholian.move(None)
1273 game.quad[w.i][w.j] = '#'
1278 proutn("Don't know how to handle torpedo collision with ")
1279 proutn(crmena(True, iquad, "sector", w))
1284 setwnd(message_window)
1285 prout(_("Torpedo missed."))
1289 "Critical-hit resolution."
1290 if hit < (275.0-25.0*game.skill)*randreal(1.0, 1.5):
1292 ncrit = int(1.0 + hit/(500.0+randreal(100)))
1293 proutn(_("***CRITICAL HIT--"))
1294 # Select devices and cause damage
1299 # Cheat to prevent shuttle damage unless on ship
1300 if not (game.damage[j]<0.0 or (j == DSHUTTL and game.iscraft != "onship")):
1303 extradm = (hit*game.damfac)/(ncrit*randreal(75, 100))
1304 game.damage[j] += extradm
1307 for (i, j) in enumerate(cdam):
1309 if skipcount % 3 == 2 and i < len(cdam)-1:
1314 prout(_(" damaged."))
1315 if damaged(DSHIELD) and game.shldup:
1316 prout(_("***Shields knocked down."))
1319 def attack(torps_ok):
1320 # bad guy attacks us
1321 # torps_ok == False forces use of phasers in an attack
1322 # game could be over at this point, check
1332 prout("=== ATTACK!")
1333 # Tholian gets to move before attacking
1336 # if you have just entered the RNZ, you'll get a warning
1337 if game.neutz: # The one chance not to be attacked
1340 # commanders get a chance to tac-move towards you
1341 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:
1342 for (bugout, enemy, old, goto) in moveklings():
1344 # we know about this if either short or long range
1345 # sensors are working
1346 if damaged(DSRSENS) and damaged(DLRSENS) \
1347 and game.condition != "docked":
1348 prout(crmena(True, enemy.type, "sector", old) + \
1349 (_(" escapes to Quadrant %s (and regains strength).") % goto))
1350 else: # Enemy still in-sector
1351 if enemy.move(goto):
1352 if not damaged(DSRSENS) or game.condition == "docked":
1353 proutn(_("*** %s from Sector %s") % (cramen(enemy.type), enemy.location))
1354 if enemy.kdist < old:
1355 proutn(_(" advances to "))
1357 proutn(_(" retreats to "))
1358 prout("Sector %s." % goto)
1360 # if no enemies remain after movement, we're done
1361 if len(game.enemies) == 0 or (len(game.enemies) == 1 and thing.at(game.quadrant) and not thing.angered):
1363 # set up partial hits if attack happens during shield status change
1364 pfac = 1.0/game.inshld
1366 chgfac = 0.25 + randreal(0.5)
1368 # message verbosity control
1369 if game.skill <= SKILL_FAIR:
1371 for enemy in game.enemies:
1373 continue # too weak to attack
1374 # compute hit strength and diminish shield power
1376 # Increase chance of photon torpedos if docked or enemy energy is low
1377 if game.condition == "docked":
1379 if enemy.power < 500:
1381 if enemy.type == 'T' or (enemy.type == '?' and not thing.angered):
1383 # different enemies have different probabilities of throwing a torp
1384 usephasers = not torps_ok or \
1385 (enemy.type == 'K' and r > 0.0005) or \
1386 (enemy.type == 'C' and r > 0.015) or \
1387 (enemy.type == 'R' and r > 0.3) or \
1388 (enemy.type == 'S' and r > 0.07) or \
1389 (enemy.type == '?' and r > 0.05)
1390 if usephasers: # Enemy uses phasers
1391 if game.condition == "docked":
1392 continue # Don't waste the effort!
1393 attempt = True # Attempt to attack
1394 dustfac = randreal(0.8, 0.85)
1395 hit = enemy.power*math.pow(dustfac, enemy.kavgd)
1397 else: # Enemy uses photon torpedo
1398 # We should be able to make the bearing() method work here
1399 pcourse = 1.90985*math.atan2(game.sector.j-enemy.location.j, enemy.location.i-game.sector.i)
1401 proutn(_("***TORPEDO INCOMING"))
1402 if not damaged(DSRSENS):
1403 proutn(_(" From ") + crmena(False, enemy.type, where, enemy.location))
1406 dispersion = (randreal()+randreal())*0.5 - 0.5
1407 dispersion += 0.002*enemy.power*dispersion
1408 hit = torpedo(enemy.location, pcourse, dispersion, number=1, nburst=1)
1409 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
1410 finish(FWON) # Klingons did themselves in!
1411 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.alldone:
1412 return # Supernova or finished
1415 # incoming phaser or torpedo, shields may dissipate it
1416 if game.shldup or game.shldchg or game.condition == "docked":
1417 # shields will take hits
1418 propor = pfac * game.shield
1419 if game.condition == "docked":
1423 hitsh = propor*chgfac*hit+1.0
1425 if absorb > game.shield:
1426 absorb = game.shield
1427 game.shield -= absorb
1429 # taking a hit blasts us out of a starbase dock
1430 if game.condition == "docked":
1432 # but the shields may take care of it
1433 if propor > 0.1 and hit < 0.005*game.energy:
1435 # hit from this opponent got through shields, so take damage
1437 proutn(_("%d unit hit") % int(hit))
1438 if (damaged(DSRSENS) and usephasers) or game.skill<=SKILL_FAIR:
1439 proutn(_(" on the ") + crmshp())
1440 if not damaged(DSRSENS) and usephasers:
1441 prout(_(" from ") + crmena(False, enemy.type, where, enemy.location))
1443 # Decide if hit is critical
1449 if game.energy <= 0:
1450 # Returning home upon your shield, not with it...
1453 if not attempt and game.condition == "docked":
1454 prout(_("***Enemies decide against attacking your ship."))
1455 percent = 100.0*pfac*game.shield+0.5
1457 # Shields fully protect ship
1458 proutn(_("Enemy attack reduces shield strength to "))
1460 # Emit message if starship suffered hit(s)
1462 proutn(_("Energy left %2d shields ") % int(game.energy))
1465 elif not damaged(DSHIELD):
1468 proutn(_("damaged, "))
1469 prout(_("%d%%, torpedoes left %d") % (percent, game.torps))
1470 # Check if anyone was hurt
1471 if hitmax >= 200 or hittot >= 500:
1472 icas = randrange(int(hittot * 0.015))
1475 prout(_("Mc Coy- \"Sickbay to bridge. We suffered %d casualties") % icas)
1476 prout(_(" in that last attack.\""))
1478 game.state.crew -= icas
1479 # After attack, reset average distance to enemies
1480 for enemy in game.enemies:
1481 enemy.kavgd = enemy.kdist
1485 def deadkl(w, etype, mv):
1486 "Kill a Klingon, Tholian, Romulan, or Thingy."
1487 # Added mv to allow enemy to "move" before dying
1488 proutn(crmena(True, etype, "sector", mv))
1489 # Decide what kind of enemy it is and update appropriately
1491 # Chalk up a Romulan
1492 game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans -= 1
1494 game.state.nromrem -= 1
1503 # Killed some type of Klingon
1504 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
1507 game.state.kcmdr.remove(game.quadrant)
1509 if game.state.kcmdr:
1510 schedule(FTBEAM, expran(1.0*game.incom/len(game.state.kcmdr)))
1511 if is_scheduled(FCDBAS) and game.battle == game.quadrant:
1514 game.state.remkl -= 1
1516 game.state.nscrem -= 1
1517 game.state.kscmdr.invalidate()
1522 # For each kind of enemy, finish message to player
1523 prout(_(" destroyed."))
1524 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
1527 # Remove enemy ship from arrays describing local conditions
1528 for e in game.enemies:
1535 "Return None if target is invalid, otherwise return a course angle."
1536 if not w.valid_sector():
1540 # C code this was translated from is wacky -- why the sign reversal?
1541 delta.j = (w.j - game.sector.j)
1542 delta.i = (game.sector.i - w.i)
1543 if delta == Coord(0, 0):
1545 prout(_("Spock- \"Bridge to sickbay. Dr. McCoy,"))
1546 prout(_(" I recommend an immediate review of"))
1547 prout(_(" the Captain's psychological profile.\""))
1550 return delta.bearing()
1553 "Launch photon torpedo salvo."
1556 if damaged(DPHOTON):
1557 prout(_("Photon tubes damaged."))
1561 prout(_("No torpedoes left."))
1564 # First, get torpedo count
1567 if scanner.token == "IHALPHA":
1570 elif scanner.token == "IHEOL" or not scanner.waiting():
1571 prout(_("%d torpedoes left.") % game.torps)
1573 proutn(_("Number of torpedoes to fire- "))
1574 continue # Go back around to get a number
1575 else: # key == "IHREAL"
1577 if n <= 0: # abort command
1582 prout(_("Maximum of %d torpedoes per burst.") % MAXBURST)
1585 scanner.chew() # User requested more torps than available
1586 continue # Go back around
1587 break # All is good, go to next stage
1591 key = scanner.nexttok()
1592 if i == 0 and key == "IHEOL":
1593 break # no coordinate waiting, we will try prompting
1594 if i == 1 and key == "IHEOL":
1595 # direct all torpedoes at one target
1597 target.append(target[0])
1598 tcourse.append(tcourse[0])
1601 scanner.push(scanner.token)
1602 target.append(scanner.getcoord())
1603 if target[-1] is None:
1605 tcourse.append(targetcheck(target[-1]))
1606 if tcourse[-1] is None:
1609 if len(target) == 0:
1610 # prompt for each one
1612 proutn(_("Target sector for torpedo number %d- ") % (i+1))
1614 target.append(scanner.getcoord())
1615 if target[-1] is None:
1617 tcourse.append(targetcheck(target[-1]))
1618 if tcourse[-1] is None:
1621 # Loop for moving <n> torpedoes
1623 if game.condition != "docked":
1625 dispersion = (randreal()+randreal())*0.5 -0.5
1626 if math.fabs(dispersion) >= 0.47:
1628 dispersion *= randreal(1.2, 2.2)
1630 prouts(_("***TORPEDO NUMBER %d MISFIRES") % (i+1))
1632 prouts(_("***TORPEDO MISFIRES."))
1635 prout(_(" Remainder of burst aborted."))
1637 prout(_("***Photon tubes damaged by misfire."))
1638 game.damage[DPHOTON] = game.damfac * randreal(1.0, 3.0)
1640 if game.shldup or game.condition == "docked":
1641 dispersion *= 1.0 + 0.0001*game.shield
1642 torpedo(game.sector, tcourse[i], dispersion, number=i, nburst=n)
1643 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
1645 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)<=0:
1649 "Check for phasers overheating."
1651 checkburn = (rpow-1500.0)*0.00038
1652 if withprob(checkburn):
1653 prout(_("Weapons officer Sulu- \"Phasers overheated, sir.\""))
1654 game.damage[DPHASER] = game.damfac* randreal(1.0, 2.0) * (1.0+checkburn)
1656 def checkshctrl(rpow):
1657 "Check shield control."
1660 prout(_("Shields lowered."))
1662 # Something bad has happened
1663 prouts(_("***RED ALERT! RED ALERT!"))
1665 hit = rpow*game.shield/game.inshld
1666 game.energy -= rpow+hit*0.8
1667 game.shield -= hit*0.2
1668 if game.energy <= 0.0:
1669 prouts(_("Sulu- \"Captain! Shield malf***********************\""))
1674 prouts(_("Sulu- \"Captain! Shield malfunction! Phaser fire contained!\""))
1676 prout(_("Lt. Uhura- \"Sir, all decks reporting damage.\""))
1677 icas = randrange(int(hit*0.012))
1682 prout(_("McCoy to bridge- \"Severe radiation burns, Jim."))
1683 prout(_(" %d casualties so far.\"") % icas)
1685 game.state.crew -= icas
1687 prout(_("Phaser energy dispersed by shields."))
1688 prout(_("Enemy unaffected."))
1693 "Register a phaser hit on Klingons and Romulans."
1700 dustfac = randreal(0.9, 1.0)
1701 hit = wham*math.pow(dustfac, game.enemies[kk].kdist)
1702 kpini = game.enemies[kk].power
1703 kp = math.fabs(kpini)
1704 if PHASEFAC*hit < kp:
1706 if game.enemies[kk].power < 0:
1707 game.enemies[kk].power -= -kp
1709 game.enemies[kk].power -= kp
1710 kpow = game.enemies[kk].power
1711 w = game.enemies[kk].location
1713 if not damaged(DSRSENS):
1715 proutn(_("%d unit hit on ") % int(hit))
1717 proutn(_("Very small hit on "))
1718 ienm = game.quad[w.i][w.j]
1721 proutn(crmena(False, ienm, "sector", w))
1725 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1729 kk -= 1 # don't do the increment
1731 else: # decide whether or not to emasculate klingon
1732 if kpow > 0 and withprob(0.9) and kpow <= randreal(0.4, 0.8)*kpini:
1733 prout(_("***Mr. Spock- \"Captain, the vessel at Sector %s")%w)
1734 prout(_(" has just lost its firepower.\""))
1735 game.enemies[kk].power = -kpow
1740 "Fire phasers at bad guys."
1744 irec = 0 # Cheating inhibitor
1753 # SR sensors and Computer are needed for automode
1754 if damaged(DSRSENS) or damaged(DCOMPTR):
1756 if game.condition == "docked":
1757 prout(_("Phasers can't be fired through base shields."))
1760 if damaged(DPHASER):
1761 prout(_("Phaser control damaged."))
1765 if damaged(DSHCTRL):
1766 prout(_("High speed shield control damaged."))
1769 if game.energy <= 200.0:
1770 prout(_("Insufficient energy to activate high-speed shield control."))
1773 prout(_("Weapons Officer Sulu- \"High-speed shield control enabled, sir.\""))
1775 # Original code so convoluted, I re-did it all
1776 # (That was Tom Almy talking about the C code, I think -- ESR)
1777 while automode == "NOTSET":
1778 key = scanner.nexttok()
1779 if key == "IHALPHA":
1780 if scanner.sees("manual"):
1781 if len(game.enemies)==0:
1782 prout(_("There is no enemy present to select."))
1785 automode = "AUTOMATIC"
1788 key = scanner.nexttok()
1789 elif scanner.sees("automatic"):
1790 if (not itarg) and len(game.enemies) != 0:
1791 automode = "FORCEMAN"
1793 if len(game.enemies)==0:
1794 prout(_("Energy will be expended into space."))
1795 automode = "AUTOMATIC"
1796 key = scanner.nexttok()
1797 elif scanner.sees("no"):
1802 elif key == "IHREAL":
1803 if len(game.enemies)==0:
1804 prout(_("Energy will be expended into space."))
1805 automode = "AUTOMATIC"
1807 automode = "FORCEMAN"
1809 automode = "AUTOMATIC"
1812 if len(game.enemies)==0:
1813 prout(_("Energy will be expended into space."))
1814 automode = "AUTOMATIC"
1816 automode = "FORCEMAN"
1818 proutn(_("Manual or automatic? "))
1823 if automode == "AUTOMATIC":
1824 if key == "IHALPHA" and scanner.sees("no"):
1826 key = scanner.nexttok()
1827 if key != "IHREAL" and len(game.enemies) != 0:
1828 prout(_("Phasers locked on target. Energy available: %.2f")%avail)
1833 for i in range(len(game.enemies)):
1834 irec += math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))*randreal(1.01, 1.06) + 1.0
1836 proutn(_("%d units required. ") % irec)
1838 proutn(_("Units to fire= "))
1839 key = scanner.nexttok()
1844 proutn(_("Energy available= %.2f") % avail)
1847 if not rpow > avail:
1853 key = scanner.nexttok()
1854 if key == "IHALPHA" and scanner.sees("no"):
1857 game.energy -= 200 # Go and do it!
1858 if checkshctrl(rpow):
1863 if len(game.enemies):
1866 for i in range(len(game.enemies)):
1870 hits[i] = math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))
1871 over = randreal(1.01, 1.06) * hits[i]
1873 powrem -= hits[i] + over
1874 if powrem <= 0 and temp < hits[i]:
1883 if extra > 0 and not game.alldone:
1885 proutn(_("*** Tholian web absorbs "))
1886 if len(game.enemies)>0:
1887 proutn(_("excess "))
1888 prout(_("phaser energy."))
1890 prout(_("%d expended on empty space.") % int(extra))
1891 elif automode == "FORCEMAN":
1894 if damaged(DCOMPTR):
1895 prout(_("Battle computer damaged, manual fire only."))
1898 prouts(_("---WORKING---"))
1900 prout(_("Short-range-sensors-damaged"))
1901 prout(_("Insufficient-data-for-automatic-phaser-fire"))
1902 prout(_("Manual-fire-must-be-used"))
1904 elif automode == "MANUAL":
1906 for k in range(len(game.enemies)):
1907 aim = game.enemies[k].location
1908 ienm = game.quad[aim.i][aim.j]
1910 proutn(_("Energy available= %.2f") % (avail-0.006))
1914 if damaged(DSRSENS) and \
1915 not game.sector.distance(aim)<2**0.5 and ienm in ('C', 'S'):
1916 prout(cramen(ienm) + _(" can't be located without short range scan."))
1919 hits[k] = 0 # prevent overflow -- thanks to Alexei Voitenko
1924 if itarg and k > kz:
1925 irec = (abs(game.enemies[k].power)/(PHASEFAC*math.pow(0.9, game.enemies[k].kdist))) * randreal(1.01, 1.06) + 1.0
1928 if not damaged(DCOMPTR):
1933 proutn(_("units to fire at %s- ") % crmena(False, ienm, "sector", aim))
1934 key = scanner.nexttok()
1935 if key == "IHALPHA" and scanner.sees("no"):
1937 key = scanner.nexttok()
1939 if key == "IHALPHA":
1943 if k == 1: # Let me say I'm baffled by this
1946 if scanner.real < 0:
1950 hits[k] = scanner.real
1951 rpow += scanner.real
1952 # If total requested is too much, inform and start over
1954 prout(_("Available energy exceeded -- try again."))
1957 key = scanner.nexttok() # scan for next value
1960 # zero energy -- abort
1963 if key == "IHALPHA" and scanner.sees("no"):
1968 game.energy -= 200.0
1969 if checkshctrl(rpow):
1973 # Say shield raised or malfunction, if necessary
1980 prout(_("Sulu- \"Sir, the high-speed shield control has malfunctioned . . ."))
1981 prouts(_(" CLICK CLICK POP . . ."))
1982 prout(_(" No response, sir!"))
1985 prout(_("Shields raised."))
1992 game.ididit = False # Nothing if we fail
1995 # Make sure there is room in the brig */
1996 if game.brigfree == 0:
1997 prout(_("Security reports the brig is already full."))
2001 prout(_("Uhura- \"We have no subspace radio communication, sir.\""))
2004 if damaged(DTRANSP):
2005 prout(_("Scotty- \"Transporter damaged, sir.\""))
2008 # find out if there are any at all
2010 prout(_("Uhura- \"Getting no response, sir.\""))
2013 # if there is more than one Klingon, find out which one */
2014 # Cruddy, just takes one at random. Should ask the captain.
2015 # Nah, just select the weakest one since it is most likely to
2016 # surrender (Tom Almy mod)
2017 klingons = [e for e in game.enemies if e.type == 'K']
2018 weakest = sorted(klingons, key=lambda e: e.power)
2019 Time = 0.05 # This action will take some time
2020 game.ididit = True # So any others can strike back
2022 # check out that Klingon
2023 # The algorithm isn't that great and could use some more
2024 # intelligent design
2025 # x = 300 + 25*skill;
2026 x = game.energy / (weakest.power * len(klingons))
2027 x *= 2.5; # would originally have been equivalent of 1.4,
2028 # but we want command to work more often, more humanely */
2029 #prout(_("Prob = %d (%.4f)\n", i, x))
2030 # x = 100; // For testing, of course!
2031 if x > randreal(100):
2032 # guess what, he surrendered!!! */
2033 prout(_("Klingon captain at %s surrenders.") % weakest.location)
2036 prout(_("%d Klingons commit suicide rather than be taken captive.") % 200 - i)
2038 prout(_("%d Klingons die because there is no room for them in the brig.") % i-brigfree)
2041 prout(_("%d captives taken") % i)
2042 deadkl(weakest.location, weakest.type, game.sector)
2043 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)<=0:
2047 # big surprise, he refuses to surrender */
2048 prout(_("Fat chance, captain!"))
2050 # Code from events.c begins here.
2052 # This isn't a real event queue a la BSD Trek yet -- you can only have one
2053 # event of each type active at any given time. Mostly these means we can
2054 # only have one FDISTR/FENSLV/FREPRO sequence going at any given time
2055 # BSD Trek, from which we swiped the idea, can have up to 5.
2057 def unschedule(evtype):
2058 "Remove an event from the schedule."
2059 game.future[evtype].date = FOREVER
2060 return game.future[evtype]
2062 def is_scheduled(evtype):
2063 "Is an event of specified type scheduled."
2064 return game.future[evtype].date != FOREVER
2066 def scheduled(evtype):
2067 "When will this event happen?"
2068 return game.future[evtype].date
2070 def schedule(evtype, offset):
2071 "Schedule an event of specified type."
2072 game.future[evtype].date = game.state.date + offset
2073 return game.future[evtype]
2075 def postpone(evtype, offset):
2076 "Postpone a scheduled event."
2077 game.future[evtype].date += offset
2080 "Rest period is interrupted by event."
2083 proutn(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
2085 game.resting = False
2091 "Run through the event queue looking for things to do."
2093 fintim = game.state.date + game.optime
2102 def tractorbeam(yank):
2103 "Tractor-beaming cases merge here."
2105 game.optime = (10.0/(7.5*7.5))*yank # 7.5 is yank rate (warp 7.5)
2107 prout("***" + crmshp() + _(" caught in long range tractor beam--"))
2108 # If Kirk & Co. screwing around on planet, handle
2109 atover(True) # atover(true) is Grab
2112 if game.icraft: # Caught in Galileo?
2115 # Check to see if shuttle is aboard
2116 if game.iscraft == "offship":
2119 prout(_("Galileo, left on the planet surface, is captured"))
2120 prout(_("by aliens and made into a flying McDonald's."))
2121 game.damage[DSHUTTL] = -10
2122 game.iscraft = "removed"
2124 prout(_("Galileo, left on the planet surface, is well hidden."))
2126 game.quadrant = game.state.kscmdr
2128 game.quadrant = game.state.kcmdr[i]
2129 game.sector = randplace(QUADSIZE)
2130 prout(crmshp() + _(" is pulled to Quadrant %s, Sector %s") \
2131 % (game.quadrant, game.sector))
2133 prout(_("(Remainder of rest/repair period cancelled.)"))
2134 game.resting = False
2136 if not damaged(DSHIELD) and game.shield > 0:
2137 doshield(shraise=True) # raise shields
2138 game.shldchg = False
2140 prout(_("(Shields not currently useable.)"))
2142 # Adjust finish time to time of tractor beaming?
2143 # fintim = game.state.date+game.optime
2144 attack(torps_ok=False)
2145 if not game.state.kcmdr:
2148 schedule(FTBEAM, game.optime+expran(1.5*game.intime/len(game.state.kcmdr)))
2151 "Code merges here for any commander destroying a starbase."
2152 # Not perfect, but will have to do
2153 # Handle case where base is in same quadrant as starship
2154 if game.battle == game.quadrant:
2155 game.state.chart[game.battle.i][game.battle.j].starbase = False
2156 game.quad[game.base.i][game.base.j] = '.'
2157 game.base.invalidate()
2160 prout(_("Spock- \"Captain, I believe the starbase has been destroyed.\""))
2161 elif game.state.baseq and communicating():
2162 # Get word via subspace radio
2165 prout(_("Lt. Uhura- \"Captain, Starfleet Command reports that"))
2166 proutn(_(" the starbase in Quadrant %s has been destroyed by") % game.battle)
2168 prout(_("the Klingon Super-Commander"))
2170 prout(_("a Klingon Commander"))
2171 game.state.chart[game.battle.i][game.battle.j].starbase = False
2172 # Remove Starbase from galaxy
2173 game.state.galaxy[game.battle.i][game.battle.j].starbase = False
2174 game.state.baseq = [x for x in game.state.baseq if x != game.battle]
2176 # reinstate a commander's base attack
2180 game.battle.invalidate()
2182 prout("=== EVENTS from %.2f to %.2f:" % (game.state.date, fintim))
2183 for i in range(1, NEVENTS):
2184 if i == FSNOVA: proutn("=== Supernova ")
2185 elif i == FTBEAM: proutn("=== T Beam ")
2186 elif i == FSNAP: proutn("=== Snapshot ")
2187 elif i == FBATTAK: proutn("=== Base Attack ")
2188 elif i == FCDBAS: proutn("=== Base Destroy ")
2189 elif i == FSCMOVE: proutn("=== SC Move ")
2190 elif i == FSCDBAS: proutn("=== SC Base Destroy ")
2191 elif i == FDSPROB: proutn("=== Probe Move ")
2192 elif i == FDISTR: proutn("=== Distress Call ")
2193 elif i == FENSLV: proutn("=== Enslavement ")
2194 elif i == FREPRO: proutn("=== Klingon Build ")
2196 prout("%.2f" % (scheduled(i)))
2199 radio_was_broken = damaged(DRADIO)
2202 # Select earliest extraneous event, evcode==0 if no events
2207 for l in range(1, NEVENTS):
2208 if game.future[l].date < datemin:
2211 prout("== Event %d fires" % evcode)
2212 datemin = game.future[l].date
2213 xtime = datemin-game.state.date
2214 game.state.date = datemin
2215 # Decrement Federation resources and recompute remaining time
2216 game.state.remres -= (game.state.remkl+4*len(game.state.kcmdr))*xtime
2218 if game.state.remtime <= 0:
2221 # Any crew left alive?
2222 if game.state.crew <= 0:
2225 # Is life support adequate?
2226 if damaged(DLIFSUP) and game.condition != "docked":
2227 if game.lsupres < xtime and game.damage[DLIFSUP] > game.lsupres:
2230 game.lsupres -= xtime
2231 if game.damage[DLIFSUP] <= xtime:
2232 game.lsupres = game.inlsr
2235 if game.condition == "docked":
2237 # Don't fix Deathray here
2238 for l in range(NDEVICES):
2239 if game.damage[l] > 0.0 and l != DDRAY:
2240 if game.damage[l]-repair > 0.0:
2241 game.damage[l] -= repair
2243 game.damage[l] = 0.0
2244 # If radio repaired, update star chart and attack reports
2245 if radio_was_broken and not damaged(DRADIO):
2246 prout(_("Lt. Uhura- \"Captain, the sub-space radio is working and"))
2247 prout(_(" surveillance reports are coming in."))
2249 if not game.iseenit:
2253 prout(_(" The star chart is now up to date.\""))
2255 # Cause extraneous event EVCODE to occur
2256 game.optime -= xtime
2257 if evcode == FSNOVA: # Supernova
2260 schedule(FSNOVA, expran(0.5*game.intime))
2261 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2263 elif evcode == FSPY: # Check with spy to see if SC should tractor beam
2264 if game.state.nscrem == 0 or \
2265 ictbeam or istract or \
2266 game.condition == "docked" or game.isatb == 1 or game.iscate:
2268 if game.ientesc or \
2269 (game.energy<2000 and game.torps<4 and game.shield < 1250) or \
2270 (damaged(DPHASER) and (damaged(DPHOTON) or game.torps<4)) or \
2271 (damaged(DSHIELD) and \
2272 (game.energy < 2500 or damaged(DPHASER)) and \
2273 (game.torps < 5 or damaged(DPHOTON))):
2275 istract = ictbeam = True
2276 tractorbeam((game.state.kscmdr-game.quadrant).distance())
2279 elif evcode == FTBEAM: # Tractor beam
2280 if not game.state.kcmdr:
2283 i = randrange(len(game.state.kcmdr))
2284 yank = (game.state.kcmdr[i]-game.quadrant).distance()
2285 if istract or game.condition == "docked" or yank == 0:
2286 # Drats! Have to reschedule
2288 game.optime + expran(1.5*game.intime/len(game.state.kcmdr)))
2292 elif evcode == FSNAP: # Snapshot of the universe (for time warp)
2293 game.snapsht = copy.deepcopy(game.state)
2294 game.state.snap = True
2295 schedule(FSNAP, expran(0.5 * game.intime))
2296 elif evcode == FBATTAK: # Commander attacks starbase
2297 if not game.state.kcmdr or not game.state.baseq:
2302 ibq = None # Force battle location to persist past loop
2304 for ibq in game.state.baseq:
2305 for cmdr in game.state.kcmdr:
2306 if ibq == cmdr and ibq != game.quadrant and ibq != game.state.kscmdr:
2308 # no match found -- try later
2309 schedule(FBATTAK, expran(0.3*game.intime))
2314 # commander + starbase combination found -- launch attack
2316 schedule(FCDBAS, randreal(1.0, 4.0))
2317 if game.isatb: # extra time if SC already attacking
2318 postpone(FCDBAS, scheduled(FSCDBAS)-game.state.date)
2319 game.future[FBATTAK].date = game.future[FCDBAS].date + expran(0.3*game.intime)
2320 game.iseenit = False
2321 if not communicating():
2322 continue # No warning :-(
2326 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") % game.battle)
2327 prout(_(" reports that it is under attack and that it can"))
2328 prout(_(" hold out only until stardate %d.\"") % (int(scheduled(FCDBAS))))
2331 elif evcode == FSCDBAS: # Supercommander destroys base
2334 if not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].starbase:
2335 continue # WAS RETURN!
2337 game.battle = game.state.kscmdr
2339 elif evcode == FCDBAS: # Commander succeeds in destroying base
2340 if evcode == FCDBAS:
2342 if not game.state.baseq() \
2343 or not game.state.galaxy[game.battle.i][game.battle.j].starbase:
2344 game.battle.invalidate()
2346 # find the lucky pair
2347 for cmdr in game.state.kcmdr:
2348 if cmdr == game.battle:
2351 # No action to take after all
2354 elif evcode == FSCMOVE: # Supercommander moves
2355 schedule(FSCMOVE, 0.2777)
2356 if not game.ientesc and not istract and game.isatb != 1 and \
2357 (not game.iscate or not game.justin):
2359 elif evcode == FDSPROB: # Move deep space probe
2360 schedule(FDSPROB, 0.01)
2361 if not game.probe.nexttok():
2362 if not game.probe.quadrant().valid_quadrant() or \
2363 game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j].supernova:
2364 # Left galaxy or ran into supernova
2368 proutn(_("Lt. Uhura- \"The deep space probe "))
2369 if not game.probe.quadrant().valid_quadrant():
2370 prout(_("has left the galaxy.\""))
2372 prout(_("is no longer transmitting.\""))
2378 prout(_("Lt. Uhura- \"The deep space probe is now in Quadrant %s.\"") % game.probe.quadrant())
2379 pquad = game.probe.quadrant()
2380 pdest = game.state.galaxy[pquad.i][pquad.j]
2382 game.state.chart[pquad.i][pquad.j].klingons = pdest.klingons
2383 game.state.chart[pquad.i][pquad.j].starbase = pdest.starbase
2384 game.state.chart[pquad.i][pquad.j].stars = pdest.stars
2385 pdest.charted = True
2386 game.probe.moves -= 1 # One less to travel
2387 if game.probe.arrived() and game.isarmed and pdest.stars:
2388 supernova(game.probe) # fire in the hole!
2390 if game.state.galaxy[pquad.i][pquad.j].supernova:
2392 elif evcode == FDISTR: # inhabited system issues distress call
2394 # try a whole bunch of times to find something suitable
2395 for i in range(100):
2396 # need a quadrant which is not the current one,
2397 # which has some stars which are inhabited and
2398 # not already under attack, which is not
2399 # supernova'ed, and which has some Klingons in it
2400 w = randplace(GALSIZE)
2401 q = game.state.galaxy[w.i][w.j]
2402 if not (game.quadrant == w or q.planet is None or \
2403 not q.planet.inhabited or \
2404 q.supernova or q.status!="secure" or q.klingons<=0):
2407 # can't seem to find one; ignore this call
2409 prout("=== Couldn't find location for distress event.")
2411 # got one!! Schedule its enslavement
2412 ev = schedule(FENSLV, expran(game.intime))
2414 q.status = "distressed"
2415 # tell the captain about it if we can
2417 prout(_("Uhura- Captain, %s in Quadrant %s reports it is under attack") \
2418 % (q.planet, repr(w)))
2419 prout(_("by a Klingon invasion fleet."))
2422 elif evcode == FENSLV: # starsystem is enslaved
2423 ev = unschedule(FENSLV)
2424 # see if current distress call still active
2425 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2429 q.status = "enslaved"
2431 # play stork and schedule the first baby
2432 ev2 = schedule(FREPRO, expran(2.0 * game.intime))
2433 ev2.quadrant = ev.quadrant
2435 # report the disaster if we can
2437 prout(_("Uhura- We've lost contact with starsystem %s") % \
2439 prout(_("in Quadrant %s.\n") % ev.quadrant)
2440 elif evcode == FREPRO: # Klingon reproduces
2441 # If we ever switch to a real event queue, we'll need to
2442 # explicitly retrieve and restore the x and y.
2443 ev = schedule(FREPRO, expran(1.0 * game.intime))
2444 # see if current distress call still active
2445 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2449 if game.state.remkl >= MAXKLGAME:
2450 continue # full right now
2451 # reproduce one Klingon
2454 if game.klhere >= MAXKLQUAD:
2456 # this quadrant not ok, pick an adjacent one
2457 for m.i in range(w.i - 1, w.i + 2):
2458 for m.j in range(w.j - 1, w.j + 2):
2459 if not m.valid_quadrant():
2461 q = game.state.galaxy[m.i][m.j]
2462 # check for this quad ok (not full & no snova)
2463 if q.klingons >= MAXKLQUAD or q.supernova:
2466 # search for eligible quadrant failed
2471 game.state.remkl += 1
2473 if game.quadrant == w:
2475 game.enemies.append(newkling())
2476 # recompute time left
2479 if game.quadrant == w:
2480 prout(_("Spock- sensors indicate the Klingons have"))
2481 prout(_("launched a warship from %s.") % q.planet)
2483 prout(_("Uhura- Starfleet reports increased Klingon activity"))
2484 if q.planet != None:
2485 proutn(_("near %s ") % q.planet)
2486 prout(_("in Quadrant %s.") % w)
2492 key = scanner.nexttok()
2495 proutn(_("How long? "))
2500 origTime = delay = scanner.real
2503 if delay >= game.state.remtime or len(game.enemies) != 0:
2504 proutn(_("Are you sure? "))
2507 # Alternate resting periods (events) with attacks
2511 game.resting = False
2512 if not game.resting:
2513 prout(_("%d stardates left.") % int(game.state.remtime))
2515 temp = game.optime = delay
2516 if len(game.enemies):
2517 rtime = randreal(1.0, 2.0)
2521 if game.optime < delay:
2522 attack(torps_ok=False)
2530 # Repair Deathray if long rest at starbase
2531 if origTime-delay >= 9.99 and game.condition == "docked":
2532 game.damage[DDRAY] = 0.0
2533 # leave if quadrant supernovas
2534 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2536 game.resting = False
2541 ncourse = (0.0, 10.5, 12.0, 1.5, 9.0, 0.0, 3.0, 7.5, 6.0, 4.5)
2542 newc = Coord(); neighbor = Coord(); bump = Coord(0, 0)
2544 # Wow! We've supernova'ed
2545 supernova(game.quadrant)
2547 # handle initial nova
2548 game.quad[nov.i][nov.j] = '.'
2549 prout(crmena(False, '*', "sector", nov) + _(" novas."))
2550 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2551 game.state.starkl += 1
2552 # Set up queue to recursively trigger adjacent stars
2558 for offset.i in range(-1, 1+1):
2559 for offset.j in range(-1, 1+1):
2560 if offset.j == 0 and offset.i == 0:
2562 neighbor = start + offset
2563 if not neighbor.valid_sector():
2565 iquad = game.quad[neighbor.i][neighbor.j]
2566 # Empty space ends reaction
2567 if iquad in ('.', '?', ' ', 'T', '#'):
2569 elif iquad == '*': # Affect another star
2571 # This star supernovas
2572 supernova(game.quadrant)
2575 hits.append(neighbor)
2576 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2577 game.state.starkl += 1
2578 proutn(crmena(True, '*', "sector", neighbor))
2580 game.quad[neighbor.i][neighbor.j] = '.'
2582 elif iquad in ('P', '@'): # Destroy planet
2583 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
2585 game.state.nplankl += 1
2587 game.state.nworldkl += 1
2588 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2589 game.iplnet.pclass = "destroyed"
2591 game.plnet.invalidate()
2595 game.quad[neighbor.i][neighbor.j] = '.'
2596 elif iquad == 'B': # Destroy base
2597 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
2598 game.state.baseq = [x for x in game.state.baseq if x!= game.quadrant]
2599 game.base.invalidate()
2600 game.state.basekl += 1
2602 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2603 game.quad[neighbor.i][neighbor.j] = '.'
2604 elif iquad in ('E', 'F'): # Buffet ship
2605 prout(_("***Starship buffeted by nova."))
2607 if game.shield >= 2000.0:
2608 game.shield -= 2000.0
2610 diff = 2000.0 - game.shield
2614 prout(_("***Shields knocked out."))
2615 game.damage[DSHIELD] += 0.005*game.damfac*randreal()*diff
2617 game.energy -= 2000.0
2618 if game.energy <= 0:
2621 # add in course nova contributes to kicking starship
2622 bump += (game.sector-hits[-1]).sgn()
2623 elif iquad == 'K': # kill klingon
2624 deadkl(neighbor, iquad, neighbor)
2625 elif iquad in ('C','S','R'): # Damage/destroy big enemies
2627 for ll in range(len(game.enemies)):
2628 if game.enemies[ll].location == neighbor:
2629 target = game.enemies[ll]
2631 if target is not None:
2632 target.power -= 800.0 # If firepower is lost, die
2633 if target.power <= 0.0:
2634 deadkl(neighbor, iquad, neighbor)
2635 continue # neighbor loop
2636 # Else enemy gets flung by the blast wave
2637 newc = neighbor + neighbor - hits[-1]
2638 proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged"))
2639 if not newc.valid_sector():
2640 # can't leave quadrant
2643 iquad1 = game.quad[newc.i][newc.j]
2645 proutn(_(", blasted into ") + crmena(False, ' ', "sector", newc))
2647 deadkl(neighbor, iquad, newc)
2650 # can't move into something else
2653 proutn(_(", buffeted to Sector %s") % newc)
2654 game.quad[neighbor.i][neighbor.j] = '.'
2655 game.quad[newc.i][newc.j] = iquad
2657 # Starship affected by nova -- kick it away.
2659 direc = ncourse[3*(bump.i+1)+bump.j+2]
2664 scourse = course(bearing=direc, distance=dist)
2665 game.optime = scourse.time(w=4)
2667 prout(_("Force of nova displaces starship."))
2668 imove(scourse, noattack=True)
2669 game.optime = scourse.time(w=4)
2673 "Star goes supernova."
2678 # Scheduled supernova -- select star at random.
2681 for nq.i in range(GALSIZE):
2682 for nq.j in range(GALSIZE):
2683 nstars += game.state.galaxy[nq.i][nq.j].stars
2685 return # nothing to supernova exists
2686 num = randrange(nstars) + 1
2687 for nq.i in range(GALSIZE):
2688 for nq.j in range(GALSIZE):
2689 num -= game.state.galaxy[nq.i][nq.j].stars
2695 proutn("=== Super nova here?")
2698 if not nq == game.quadrant or game.justin:
2699 # it isn't here, or we just entered (treat as enroute)
2702 prout(_("Message from Starfleet Command Stardate %.2f") % game.state.date)
2703 prout(_(" Supernova in Quadrant %s; caution advised.") % nq)
2706 # we are in the quadrant!
2707 num = randrange(game.state.galaxy[nq.i][nq.j].stars) + 1
2708 for ns.i in range(QUADSIZE):
2709 for ns.j in range(QUADSIZE):
2710 if game.quad[ns.i][ns.j]=='*':
2717 prouts(_("***RED ALERT! RED ALERT!"))
2719 prout(_("***Incipient supernova detected at Sector %s") % ns)
2720 if (ns.i-game.sector.i)**2 + (ns.j-game.sector.j)**2 <= 2.1:
2721 proutn(_("Emergency override attempts t"))
2722 prouts("***************")
2726 # destroy any Klingons in supernovaed quadrant
2727 kldead = game.state.galaxy[nq.i][nq.j].klingons
2728 game.state.galaxy[nq.i][nq.j].klingons = 0
2729 if nq == game.state.kscmdr:
2730 # did in the Supercommander!
2731 game.state.nscrem = game.state.kscmdr.i = game.state.kscmdr.j = game.isatb = 0
2735 survivors = filter(lambda w: w != nq, game.state.kcmdr)
2736 comkills = len(game.state.kcmdr) - len(survivors)
2737 game.state.kcmdr = survivors
2739 if not game.state.kcmdr:
2741 game.state.remkl -= kldead
2742 # destroy Romulans and planets in supernovaed quadrant
2743 nrmdead = game.state.galaxy[nq.i][nq.j].romulans
2744 game.state.galaxy[nq.i][nq.j].romulans = 0
2745 game.state.nromrem -= nrmdead
2747 for loop in range(game.inplan):
2748 if game.state.planets[loop].quadrant == nq:
2749 game.state.planets[loop].pclass = "destroyed"
2751 # Destroy any base in supernovaed quadrant
2752 game.state.baseq = [x for x in game.state.baseq if x != nq]
2753 # If starship caused supernova, tally up destruction
2755 game.state.starkl += game.state.galaxy[nq.i][nq.j].stars
2756 game.state.basekl += game.state.galaxy[nq.i][nq.j].starbase
2757 game.state.nplankl += npdead
2758 # mark supernova in galaxy and in star chart
2759 if game.quadrant == nq or communicating():
2760 game.state.galaxy[nq.i][nq.j].supernova = True
2761 # If supernova destroys last Klingons give special message
2762 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0 and not nq == game.quadrant:
2765 prout(_("Lucky you!"))
2766 proutn(_("A supernova in %s has just destroyed the last Klingons.") % nq)
2769 # if some Klingons remain, continue or die in supernova
2774 # Code from finish.c ends here.
2777 "Self-destruct maneuver. Finish with a BANG!"
2779 if damaged(DCOMPTR):
2780 prout(_("Computer damaged; cannot execute destruct sequence."))
2782 prouts(_("---WORKING---")); skip(1)
2783 prouts(_("SELF-DESTRUCT-SEQUENCE-ACTIVATED")); skip(1)
2784 prouts(" 10"); skip(1)
2785 prouts(" 9"); skip(1)
2786 prouts(" 8"); skip(1)
2787 prouts(" 7"); skip(1)
2788 prouts(" 6"); skip(1)
2790 prout(_("ENTER-CORRECT-PASSWORD-TO-CONTINUE-"))
2792 prout(_("SELF-DESTRUCT-SEQUENCE-OTHERWISE-"))
2794 prout(_("SELF-DESTRUCT-SEQUENCE-WILL-BE-ABORTED"))
2797 if game.passwd != scanner.token:
2798 prouts(_("PASSWORD-REJECTED;"))
2800 prouts(_("CONTINUITY-EFFECTED"))
2803 prouts(_("PASSWORD-ACCEPTED")); skip(1)
2804 prouts(" 5"); skip(1)
2805 prouts(" 4"); skip(1)
2806 prouts(" 3"); skip(1)
2807 prouts(" 2"); skip(1)
2808 prouts(" 1"); skip(1)
2810 prouts(_("GOODBYE-CRUEL-WORLD"))
2818 prouts(_("********* Entropy of %s maximized *********") % crmshp())
2822 if len(game.enemies) != 0:
2823 whammo = 25.0 * game.energy
2824 for l in range(len(game.enemies)):
2825 if game.enemies[l].power*game.enemies[l].kdist <= whammo:
2826 deadkl(game.enemies[l].location, game.quad[game.enemies[l].location.i][game.enemies[l].location.j], game.enemies[l].location)
2830 "Compute our rate of kils over time."
2831 elapsed = game.state.date - game.indate
2832 if elapsed == 0: # Avoid divide-by-zero error if calculated on turn 0
2835 starting = (game.inkling + game.incom + game.inscom)
2836 remaining = (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)
2837 return (starting - remaining)/elapsed
2841 badpt = 5.0*game.state.starkl + \
2843 10.0*game.state.nplankl + \
2844 300*game.state.nworldkl + \
2846 100.0*game.state.basekl +\
2848 if game.ship == 'F':
2850 elif game.ship is None:
2855 # end the game, with appropriate notfications
2859 prout(_("It is stardate %.1f.") % game.state.date)
2861 if ifin == FWON: # Game has been won
2862 if game.state.nromrem != 0:
2863 prout(_("The remaining %d Romulans surrender to Starfleet Command.") %
2866 prout(_("You have smashed the Klingon invasion fleet and saved"))
2867 prout(_("the Federation."))
2868 if game.alive and game.brigcapacity-game.brigfree > 0:
2869 game.kcaptured += game.brigcapacity-game.brigfree
2870 prout(_("The %d captured Klingons are transferred to Star Fleet Command.") % (game.brigcapacity-game.brigfree))
2875 badpt = 0.0 # Close enough!
2876 # killsPerDate >= RateMax
2877 if game.state.date-game.indate < 5.0 or \
2878 killrate() >= 0.1*game.skill*(game.skill+1.0) + 0.1 + 0.008*badpt:
2880 prout(_("In fact, you have done so well that Starfleet Command"))
2881 if game.skill == SKILL_NOVICE:
2882 prout(_("promotes you one step in rank from \"Novice\" to \"Fair\"."))
2883 elif game.skill == SKILL_FAIR:
2884 prout(_("promotes you one step in rank from \"Fair\" to \"Good\"."))
2885 elif game.skill == SKILL_GOOD:
2886 prout(_("promotes you one step in rank from \"Good\" to \"Expert\"."))
2887 elif game.skill == SKILL_EXPERT:
2888 prout(_("promotes you to Commodore Emeritus."))
2890 prout(_("Now that you think you're really good, try playing"))
2891 prout(_("the \"Emeritus\" game. It will splatter your ego."))
2892 elif game.skill == SKILL_EMERITUS:
2894 proutn(_("Computer- "))
2895 prouts(_("ERROR-ERROR-ERROR-ERROR"))
2897 prouts(_(" YOUR-SKILL-HAS-EXCEEDED-THE-CAPACITY-OF-THIS-PROGRAM"))
2899 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2901 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2903 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2905 prouts(_(" THIS-PROGRAM-MUST?- MUST ? - SUR? ? -? VI"))
2907 prout(_("Now you can retire and write your own Star Trek game!"))
2909 elif game.skill >= SKILL_EXPERT:
2910 if game.thawed and not game.idebug:
2911 prout(_("You cannot get a citation, so..."))
2913 proutn(_("Do you want your Commodore Emeritus Citation printed? "))
2917 # Only grant long life if alive (original didn't!)
2919 prout(_("LIVE LONG AND PROSPER."))
2924 elif ifin == FDEPLETE: # Federation Resources Depleted
2925 prout(_("Your time has run out and the Federation has been"))
2926 prout(_("conquered. Your starship is now Klingon property,"))
2927 prout(_("and you are put on trial as a war criminal. On the"))
2928 proutn(_("basis of your record, you are "))
2929 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)*3.0 > (game.inkling + game.incom + game.inscom):
2930 prout(_("acquitted."))
2932 prout(_("LIVE LONG AND PROSPER."))
2934 prout(_("found guilty and"))
2935 prout(_("sentenced to death by slow torture."))
2939 elif ifin == FLIFESUP:
2940 prout(_("Your life support reserves have run out, and"))
2941 prout(_("you die of thirst, starvation, and asphyxiation."))
2942 prout(_("Your starship is a derelict in space."))
2944 prout(_("Your energy supply is exhausted."))
2946 prout(_("Your starship is a derelict in space."))
2947 elif ifin == FBATTLE:
2948 prout(_("The %s has been destroyed in battle.") % crmshp())
2950 prout(_("Dulce et decorum est pro patria mori."))
2952 prout(_("You have made three attempts to cross the negative energy"))
2953 prout(_("barrier which surrounds the galaxy."))
2955 prout(_("Your navigation is abominable."))
2958 prout(_("Your starship has been destroyed by a nova."))
2959 prout(_("That was a great shot."))
2961 elif ifin == FSNOVAED:
2962 prout(_("The %s has been fried by a supernova.") % crmshp())
2963 prout(_("...Not even cinders remain..."))
2964 elif ifin == FABANDN:
2965 prout(_("You have been captured by the Klingons. If you still"))
2966 prout(_("had a starbase to be returned to, you would have been"))
2967 prout(_("repatriated and given another chance. Since you have"))
2968 prout(_("no starbases, you will be mercilessly tortured to death."))
2969 elif ifin == FDILITHIUM:
2970 prout(_("Your starship is now an expanding cloud of subatomic particles"))
2971 elif ifin == FMATERIALIZE:
2972 prout(_("Starbase was unable to re-materialize your starship."))
2973 prout(_("Sic transit gloria mundi"))
2974 elif ifin == FPHASER:
2975 prout(_("The %s has been cremated by its own phasers.") % crmshp())
2977 prout(_("You and your landing party have been"))
2978 prout(_("converted to energy, disipating through space."))
2979 elif ifin == FMINING:
2980 prout(_("You are left with your landing party on"))
2981 prout(_("a wild jungle planet inhabited by primitive cannibals."))
2983 prout(_("They are very fond of \"Captain Kirk\" soup."))
2985 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
2986 elif ifin == FDPLANET:
2987 prout(_("You and your mining party perish."))
2989 prout(_("That was a great shot."))
2992 prout(_("The Galileo is instantly annihilated by the supernova."))
2993 prout(_("You and your mining party are atomized."))
2995 prout(_("Mr. Spock takes command of the %s and") % crmshp())
2996 prout(_("joins the Romulans, wreaking terror on the Federation."))
2997 elif ifin == FPNOVA:
2998 prout(_("You and your mining party are atomized."))
3000 prout(_("Mr. Spock takes command of the %s and") % crmshp())
3001 prout(_("joins the Romulans, wreaking terror on the Federation."))
3002 elif ifin == FSTRACTOR:
3003 prout(_("The shuttle craft Galileo is also caught,"))
3004 prout(_("and breaks up under the strain."))
3006 prout(_("Your debris is scattered for millions of miles."))
3007 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
3009 prout(_("The mutants attack and kill Spock."))
3010 prout(_("Your ship is captured by Klingons, and"))
3011 prout(_("your crew is put on display in a Klingon zoo."))
3012 elif ifin == FTRIBBLE:
3013 prout(_("Tribbles consume all remaining water,"))
3014 prout(_("food, and oxygen on your ship."))
3016 prout(_("You die of thirst, starvation, and asphyxiation."))
3017 prout(_("Your starship is a derelict in space."))
3019 prout(_("Your ship is drawn to the center of the black hole."))
3020 prout(_("You are crushed into extremely dense matter."))
3022 prout(_("Your last crew member has died."))
3023 if game.ship == 'F':
3025 elif game.ship == 'E':
3028 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0:
3029 goodies = game.state.remres/game.inresor
3030 baddies = (game.state.remkl + 2.0*len(game.state.kcmdr))/(game.inkling+2.0*game.incom)
3031 if goodies/baddies >= randreal(1.0, 1.5):
3032 prout(_("As a result of your actions, a treaty with the Klingon"))
3033 prout(_("Empire has been signed. The terms of the treaty are"))
3034 if goodies/baddies >= randreal(3.0):
3035 prout(_("favorable to the Federation."))
3037 prout(_("Congratulations!"))
3039 prout(_("highly unfavorable to the Federation."))
3041 prout(_("The Federation will be destroyed."))
3043 prout(_("Since you took the last Klingon with you, you are a"))
3044 prout(_("martyr and a hero. Someday maybe they'll erect a"))
3045 prout(_("statue in your memory. Rest in peace, and try not"))
3046 prout(_("to think about pigeons."))
3051 "Compute player's score."
3052 timused = game.state.date - game.indate
3053 if (timused == 0 or (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0) and timused < 5.0:
3055 game.perdate = killrate()
3056 ithperd = 500*game.perdate + 0.5
3059 iwon = 100*game.skill
3060 if game.ship == 'E':
3062 elif game.ship == 'F':
3066 game.score = 10*(game.inkling - game.state.remkl) \
3067 + 50*(game.incom - len(game.state.kcmdr)) \
3069 + 20*(game.inrom - game.state.nromrem) \
3070 + 200*(game.inscom - game.state.nscrem) \
3071 - game.state.nromrem \
3072 + 3 * game.kcaptured \
3077 prout(_("Your score --"))
3078 if game.inrom - game.state.nromrem:
3079 prout(_("%6d Romulans destroyed %5d") %
3080 (game.inrom - game.state.nromrem, 20*(game.inrom - game.state.nromrem)))
3081 if game.state.nromrem and game.gamewon:
3082 prout(_("%6d Romulans captured %5d") %
3083 (game.state.nromrem, game.state.nromrem))
3084 if game.inkling - game.state.remkl:
3085 prout(_("%6d ordinary Klingons destroyed %5d") %
3086 (game.inkling - game.state.remkl, 10*(game.inkling - game.state.remkl)))
3087 if game.incom - len(game.state.kcmdr):
3088 prout(_("%6d Klingon commanders destroyed %5d") %
3089 (game.incom - len(game.state.kcmdr), 50*(game.incom - len(game.state.kcmdr))))
3091 prout(_("%d Klingons captured %5d") %
3092 (game.kcaptured, 3 * game.kcaptured))
3093 if game.inscom - game.state.nscrem:
3094 prout(_("%6d Super-Commander destroyed %5d") %
3095 (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem)))
3097 prout(_("%6.2f Klingons per stardate %5d") %
3098 (game.perdate, ithperd))
3099 if game.state.starkl:
3100 prout(_("%6d stars destroyed by your action %5d") %
3101 (game.state.starkl, -5*game.state.starkl))
3102 if game.state.nplankl:
3103 prout(_("%6d planets destroyed by your action %5d") %
3104 (game.state.nplankl, -10*game.state.nplankl))
3105 if (game.options & OPTION_WORLDS) and game.state.nworldkl:
3106 prout(_("%6d inhabited planets destroyed by your action %5d") %
3107 (game.state.nworldkl, -300*game.state.nworldkl))
3108 if game.state.basekl:
3109 prout(_("%6d bases destroyed by your action %5d") %
3110 (game.state.basekl, -100*game.state.basekl))
3112 prout(_("%6d calls for help from starbase %5d") %
3113 (game.nhelp, -45*game.nhelp))
3115 prout(_("%6d casualties incurred %5d") %
3116 (game.casual, -game.casual))
3118 prout(_("%6d crew abandoned in space %5d") %
3119 (game.abandoned, -3*game.abandoned))
3121 prout(_("%6d ship(s) lost or destroyed %5d") %
3122 (klship, -100*klship))
3124 prout(_("Penalty for getting yourself killed -200"))
3126 proutn(_("Bonus for winning "))
3127 if game.skill == SKILL_NOVICE: proutn(_("Novice game "))
3128 elif game.skill == SKILL_FAIR: proutn(_("Fair game "))
3129 elif game.skill == SKILL_GOOD: proutn(_("Good game "))
3130 elif game.skill == SKILL_EXPERT: proutn(_("Expert game "))
3131 elif game.skill == SKILL_EMERITUS: proutn(_("Emeritus game"))
3132 prout(" %5d" % iwon)
3134 prout(_("TOTAL SCORE %5d") % game.score)
3137 "Emit winner's commemmorative plaque."
3140 proutn(_("File or device name for your plaque: "))
3143 fp = open(winner, "w")
3146 prout(_("Invalid name."))
3148 proutn(_("Enter name to go on plaque (up to 30 characters): "))
3150 # The 38 below must be 64 for 132-column paper
3151 nskip = 38 - len(winner)/2
3152 fp.write("\n\n\n\n")
3153 # --------DRAW ENTERPRISE PICTURE.
3154 fp.write(" EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n" )
3155 fp.write(" EEE E : : : E\n" )
3156 fp.write(" EE EEE E : : NCC-1701 : E\n")
3157 fp.write("EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEE : : : E\n")
3158 fp.write(" E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n")
3159 fp.write(" EEEEEEEEE EEEEEEEEEEEEE E E\n")
3160 fp.write(" EEEEEEE EEEEE E E E E\n")
3161 fp.write(" EEE E E E E\n")
3162 fp.write(" E E E E\n")
3163 fp.write(" EEEEEEEEEEEEE E E\n")
3164 fp.write(" EEE : EEEEEEE EEEEEEEE\n")
3165 fp.write(" :E : EEEE E\n")
3166 fp.write(" .-E -:----- E\n")
3167 fp.write(" :E : E\n")
3168 fp.write(" EE : EEEEEEEE\n")
3169 fp.write(" EEEEEEEEEEEEEEEEEEEEEEE\n")
3171 fp.write(_(" U. S. S. ENTERPRISE\n"))
3172 fp.write("\n\n\n\n")
3173 fp.write(_(" For demonstrating outstanding ability as a starship captain\n"))
3175 fp.write(_(" Starfleet Command bestows to you\n"))
3177 fp.write("%*s%s\n\n" % (nskip, "", winner))
3178 fp.write(_(" the rank of\n\n"))
3179 fp.write(_(" \"Commodore Emeritus\"\n\n"))
3181 if game.skill == SKILL_EXPERT:
3182 fp.write(_(" Expert level\n\n"))
3183 elif game.skill == SKILL_EMERITUS:
3184 fp.write(_("Emeritus level\n\n"))
3186 fp.write(_(" Cheat level\n\n"))
3187 timestring = time.ctime()
3188 fp.write(_(" This day of %.6s %.4s, %.8s\n\n") %
3189 (timestring+4, timestring+20, timestring+11))
3190 fp.write(_(" Your score: %d\n\n") % game.score)
3191 fp.write(_(" Klingons per stardate: %.2f\n") % game.perdate)
3194 # Code from io.c begins here
3196 rows = linecount = 0 # for paging
3199 fullscreen_window = None
3200 srscan_window = None # Short range scan
3201 report_window = None # Report legends for status window
3202 status_window = None # The status window itself
3203 lrscan_window = None # Long range scan
3204 message_window = None # Main window for scrolling text
3205 prompt_window = None # Prompt window at bottom of display
3210 # for some recent versions of python2, the following enables UTF8
3211 # for the older ones we probably need to set C locale, and python3
3212 # has no problems at all
3213 if sys.version_info[0] < 3:
3214 locale.setlocale(locale.LC_ALL, "")
3215 gettext.bindtextdomain("sst", "/usr/local/share/locale")
3216 gettext.textdomain("sst")
3217 if not (game.options & OPTION_CURSES):
3218 ln_env = os.getenv("LINES")
3224 stdscr = curses.initscr()
3228 if game.options & OPTION_COLOR:
3229 curses.start_color()
3230 curses.use_default_colors()
3231 curses.init_pair(curses.COLOR_BLACK, curses.COLOR_BLACK, -1)
3232 curses.init_pair(curses.COLOR_GREEN, curses.COLOR_GREEN, -1)
3233 curses.init_pair(curses.COLOR_RED, curses.COLOR_RED, -1)
3234 curses.init_pair(curses.COLOR_CYAN, curses.COLOR_CYAN, -1)
3235 curses.init_pair(curses.COLOR_WHITE, curses.COLOR_WHITE, -1)
3236 curses.init_pair(curses.COLOR_MAGENTA, curses.COLOR_MAGENTA, -1)
3237 curses.init_pair(curses.COLOR_BLUE, curses.COLOR_BLUE, -1)
3238 curses.init_pair(curses.COLOR_YELLOW, curses.COLOR_YELLOW, -1)
3239 global fullscreen_window, srscan_window, report_window, status_window
3240 global lrscan_window, message_window, prompt_window
3241 (rows, _columns) = stdscr.getmaxyx()
3242 fullscreen_window = stdscr
3243 srscan_window = curses.newwin(12, 25, 0, 0)
3244 report_window = curses.newwin(11, 0, 1, 25)
3245 status_window = curses.newwin(10, 0, 1, 39)
3246 lrscan_window = curses.newwin(5, 0, 0, 64)
3247 message_window = curses.newwin(0, 0, 12, 0)
3248 prompt_window = curses.newwin(1, 0, rows-2, 0)
3249 message_window.scrollok(True)
3250 setwnd(fullscreen_window)
3254 if game.options & OPTION_CURSES:
3255 stdscr.keypad(False)
3261 "Wait for user action -- OK to do nothing if on a TTY"
3262 if game.options & OPTION_CURSES:
3267 prouts(_("[ANNOUNCEMENT ARRIVING...]"))
3271 if game.skill > SKILL_FAIR:
3272 prompt = _("[CONTINUE?]")
3274 prompt = _("[PRESS ENTER TO CONTINUE]")
3276 if game.options & OPTION_CURSES:
3278 setwnd(prompt_window)
3279 prompt_window.clear()
3280 prompt_window.addstr(prompt)
3281 prompt_window.getstr()
3282 prompt_window.clear()
3283 prompt_window.refresh()
3284 setwnd(message_window)
3287 sys.stdout.write('\n')
3291 sys.stdout.write('\n' * rows)
3295 "Skip i lines. Pause game if this would cause a scrolling event."
3296 for _dummy in range(i):
3297 if game.options & OPTION_CURSES:
3298 (y, _x) = curwnd.getyx()
3301 except curses.error:
3306 if rows and linecount >= rows:
3309 sys.stdout.write('\n')
3311 def proutn(proutntline):
3312 "Utter a line with no following line feed."
3313 if game.options & OPTION_CURSES:
3314 (y, x) = curwnd.getyx()
3315 (my, _mx) = curwnd.getmaxyx()
3316 if curwnd == message_window and y >= my - 2:
3319 # Uncomment this to debug curses problems
3321 logfp.write("#curses: at %s proutn(%s)\n" % ((y, x), repr(proutntline)))
3322 curwnd.addstr(proutntline)
3325 sys.stdout.write(proutntline)
3328 def prout(proutline):
3332 def prouts(proutsline):
3334 for c in proutsline:
3335 if not replayfp or replayfp.closed: # Don't slow down replays
3338 if game.options & OPTION_CURSES:
3342 if not replayfp or replayfp.closed:
3346 "Get a line of input."
3347 if game.options & OPTION_CURSES:
3348 linein = curwnd.getstr() + "\n"
3351 if replayfp and not replayfp.closed:
3353 linein = replayfp.readline()
3356 prout("*** Replay finished")
3359 elif linein[0] != "#":
3362 linein = eval(input()) + "\n"
3368 "Change windows -- OK for this to be a no-op in tty mode."
3370 if game.options & OPTION_CURSES:
3371 # Uncomment this to debug curses problems
3373 if wnd == fullscreen_window:
3374 legend = "fullscreen"
3375 elif wnd == srscan_window:
3377 elif wnd == report_window:
3379 elif wnd == status_window:
3381 elif wnd == lrscan_window:
3383 elif wnd == message_window:
3385 elif wnd == prompt_window:
3389 logfp.write("#curses: setwnd(%s)\n" % legend)
3391 # Some curses implementations get confused when you try this.
3393 curses.curs_set(wnd in (fullscreen_window, message_window, prompt_window))
3394 except curses.error:
3398 "Clear to end of line -- can be a no-op in tty mode"
3399 if game.options & OPTION_CURSES:
3404 "Clear screen -- can be a no-op in tty mode."
3406 if game.options & OPTION_CURSES:
3412 def textcolor(color=DEFAULT):
3413 if game.options & OPTION_COLOR:
3414 if color == DEFAULT:
3416 elif color == BLACK:
3417 curwnd.attron(curses.color_pair(curses.COLOR_BLACK))
3419 curwnd.attron(curses.color_pair(curses.COLOR_BLUE))
3420 elif color == GREEN:
3421 curwnd.attron(curses.color_pair(curses.COLOR_GREEN))
3423 curwnd.attron(curses.color_pair(curses.COLOR_CYAN))
3425 curwnd.attron(curses.color_pair(curses.COLOR_RED))
3426 elif color == MAGENTA:
3427 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA))
3428 elif color == BROWN:
3429 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW))
3430 elif color == LIGHTGRAY:
3431 curwnd.attron(curses.color_pair(curses.COLOR_WHITE))
3432 elif color == DARKGRAY:
3433 curwnd.attron(curses.color_pair(curses.COLOR_BLACK) | curses.A_BOLD)
3434 elif color == LIGHTBLUE:
3435 curwnd.attron(curses.color_pair(curses.COLOR_BLUE) | curses.A_BOLD)
3436 elif color == LIGHTGREEN:
3437 curwnd.attron(curses.color_pair(curses.COLOR_GREEN) | curses.A_BOLD)
3438 elif color == LIGHTCYAN:
3439 curwnd.attron(curses.color_pair(curses.COLOR_CYAN) | curses.A_BOLD)
3440 elif color == LIGHTRED:
3441 curwnd.attron(curses.color_pair(curses.COLOR_RED) | curses.A_BOLD)
3442 elif color == LIGHTMAGENTA:
3443 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA) | curses.A_BOLD)
3444 elif color == YELLOW:
3445 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW) | curses.A_BOLD)
3446 elif color == WHITE:
3447 curwnd.attron(curses.color_pair(curses.COLOR_WHITE) | curses.A_BOLD)
3450 if game.options & OPTION_COLOR:
3451 curwnd.attron(curses.A_REVERSE)
3454 # Things past this point have policy implications.
3458 "Hook to be called after moving to redraw maps."
3459 if game.options & OPTION_CURSES:
3462 setwnd(srscan_window)
3466 setwnd(status_window)
3467 status_window.clear()
3468 status_window.move(0, 0)
3469 setwnd(report_window)
3470 report_window.clear()
3471 report_window.move(0, 0)
3473 setwnd(lrscan_window)
3474 lrscan_window.clear()
3475 lrscan_window.move(0, 0)
3476 lrscan(silent=False)
3478 def put_srscan_sym(w, sym):
3479 "Emit symbol for short-range scan."
3480 srscan_window.move(w.i+1, w.j*2+2)
3481 srscan_window.addch(sym)
3482 srscan_window.refresh()
3485 "Enemy fall down, go boom."
3486 if game.options & OPTION_CURSES:
3488 setwnd(srscan_window)
3489 srscan_window.attron(curses.A_REVERSE)
3490 put_srscan_sym(w, game.quad[w.i][w.j])
3494 srscan_window.attroff(curses.A_REVERSE)
3495 put_srscan_sym(w, game.quad[w.i][w.j])
3496 curses.delay_output(500)
3497 setwnd(message_window)
3500 "Sound and visual effects for teleportation."
3501 if game.options & OPTION_CURSES:
3503 setwnd(message_window)
3505 prouts(" . . . . . ")
3506 if game.options & OPTION_CURSES:
3507 #curses.delay_output(1000)
3511 def tracktorpedo(w, step, i, n, iquad):
3512 "Torpedo-track animation."
3513 if not game.options & OPTION_CURSES:
3517 proutn(_("Track for torpedo number %d- ") % (i+1))
3520 proutn(_("Torpedo track- "))
3521 elif step==4 or step==9:
3525 if not damaged(DSRSENS) or game.condition=="docked":
3526 if i != 0 and step == 1:
3529 if (iquad=='.') or (iquad==' '):
3530 put_srscan_sym(w, '+')
3534 put_srscan_sym(w, iquad)
3536 curwnd.attron(curses.A_REVERSE)
3537 put_srscan_sym(w, iquad)
3541 curwnd.attroff(curses.A_REVERSE)
3542 put_srscan_sym(w, iquad)
3547 "Display the current galaxy chart."
3548 if game.options & OPTION_CURSES:
3549 setwnd(message_window)
3550 message_window.clear()
3552 if game.options & OPTION_TTY:
3557 def prstat(txt, data):
3559 if game.options & OPTION_CURSES:
3561 setwnd(status_window)
3563 proutn(" " * (NSYM - len(txt)))
3566 if game.options & OPTION_CURSES:
3567 setwnd(report_window)
3569 # Code from moving.c begins here
3571 def imove(icourse=None, noattack=False):
3572 "Movement execution for warp, impulse, supernova, and tractor-beam events."
3575 def newquadrant(noattack):
3576 # Leaving quadrant -- allow final enemy attack
3577 # Don't do it if being pushed by Nova
3578 if len(game.enemies) != 0 and not noattack:
3580 for enemy in game.enemies:
3581 finald = (w - enemy.location).distance()
3582 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3583 # Stas Sergeev added the condition
3584 # that attacks only happen if Klingons
3585 # are present and your skill is good.
3586 if game.skill > SKILL_GOOD and game.klhere > 0 and not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3587 attack(torps_ok=False)
3590 # check for edge of galaxy
3596 if icourse.final.i < 0:
3597 icourse.final.i = -icourse.final.i
3599 if icourse.final.j < 0:
3600 icourse.final.j = -icourse.final.j
3602 if icourse.final.i >= GALSIZE*QUADSIZE:
3603 icourse.final.i = (GALSIZE*QUADSIZE*2) - icourse.final.i
3605 if icourse.final.j >= GALSIZE*QUADSIZE:
3606 icourse.final.j = (GALSIZE*QUADSIZE*2) - icourse.final.j
3614 if game.nkinks == 3:
3615 # Three strikes -- you're out!
3619 prout(_("YOU HAVE ATTEMPTED TO CROSS THE NEGATIVE ENERGY BARRIER"))
3620 prout(_("AT THE EDGE OF THE GALAXY. THE THIRD TIME YOU TRY THIS,"))
3621 prout(_("YOU WILL BE DESTROYED."))
3622 # Compute final position in new quadrant
3623 if trbeam: # Don't bother if we are to be beamed
3625 game.quadrant = icourse.final.quadrant()
3626 game.sector = icourse.final.sector()
3628 prout(_("Entering Quadrant %s.") % game.quadrant)
3629 game.quad[game.sector.i][game.sector.j] = game.ship
3631 if game.skill>SKILL_NOVICE:
3632 attack(torps_ok=False)
3634 def check_collision(h):
3635 iquad = game.quad[h.i][h.j]
3637 # object encountered in flight path
3638 stopegy = 50.0*icourse.distance/game.optime
3639 if iquad in ('T', 'K', 'C', 'S', 'R', '?'):
3640 for enemy in game.enemies:
3641 if enemy.location == game.sector:
3642 collision(rammed=False, enemy=enemy)
3644 # This should not happen
3645 prout(_("Which way did he go?"))
3649 prouts(_("***RED ALERT! RED ALERT!"))
3651 proutn("***" + crmshp())
3652 proutn(_(" pulled into black hole at Sector %s") % h)
3653 # Getting pulled into a black hole was certain
3654 # death in Almy's original. Stas Sergeev added a
3655 # possibility that you'll get timewarped instead.
3657 for m in range(NDEVICES):
3658 if game.damage[m]>0:
3660 probf=math.pow(1.4,(game.energy+game.shield)/5000.0-1.0)*math.pow(1.3,1.0/(n+1)-1.0)
3661 if (game.options & OPTION_BLKHOLE) and withprob(1-probf):
3671 prout(_(" encounters Tholian web at %s;") % h)
3673 prout(_(" blocked by object at %s;") % h)
3674 proutn(_("Emergency stop required "))
3675 prout(_("%2d units of energy.") % int(stopegy))
3676 game.energy -= stopegy
3677 if game.energy <= 0:
3684 prout(_("Helmsman Sulu- \"Leaving standard orbit.\""))
3685 game.inorbit = False
3686 # If tractor beam is to occur, don't move full distance
3687 if game.state.date+game.optime >= scheduled(FTBEAM):
3689 game.condition = "red"
3690 icourse.distance = icourse.distance*(scheduled(FTBEAM)-game.state.date)/game.optime + 0.1
3691 game.optime = scheduled(FTBEAM) - game.state.date + 1e-5
3693 game.quad[game.sector.i][game.sector.j] = '.'
3694 for _m in range(icourse.moves):
3696 w = icourse.sector()
3697 if icourse.origin.quadrant() != icourse.location.quadrant():
3698 newquadrant(noattack)
3700 elif check_collision(w):
3701 print("Collision detected")
3705 # We're in destination quadrant -- compute new average enemy distances
3706 game.quad[game.sector.i][game.sector.j] = game.ship
3708 for enemy in game.enemies:
3709 finald = (w-enemy.location).distance()
3710 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3711 enemy.kdist = finald
3713 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3714 attack(torps_ok=False)
3715 for enemy in game.enemies:
3716 enemy.kavgd = enemy.kdist
3719 setwnd(message_window)
3723 "Dock our ship at a starbase."
3725 if game.condition == "docked" and verbose:
3726 prout(_("Already docked."))
3729 prout(_("You must first leave standard orbit."))
3731 if not game.base.is_valid() or abs(game.sector.i-game.base.i) > 1 or abs(game.sector.j-game.base.j) > 1:
3732 prout(crmshp() + _(" not adjacent to base."))
3734 game.condition = "docked"
3738 if game.energy < game.inenrg:
3739 game.energy = game.inenrg
3740 game.shield = game.inshld
3741 game.torps = game.intorps
3742 game.lsupres = game.inlsr
3743 game.state.crew = FULLCREW
3744 if game.brigcapacity-game.brigfree > 0:
3745 prout(_("%d captured Klingons transferred to base") % (game.brigcapacity-game.brigfree))
3746 game.kcaptured += game.brigcapacity-game.brigfree
3747 game.brigfree = game.brigcapacity
3748 if not damaged(DRADIO) and \
3749 ((is_scheduled(FCDBAS) or game.isatb == 1) and not game.iseenit):
3750 # get attack report from base
3751 prout(_("Lt. Uhura- \"Captain, an important message from the starbase:\""))
3755 def cartesian(loc1=None, loc2=None):
3757 return game.quadrant * QUADSIZE + game.sector
3759 return game.quadrant * QUADSIZE + loc1
3761 return loc1 * QUADSIZE + loc2
3763 def getcourse(isprobe):
3764 "Get a course and distance from the user."
3766 dquad = copy.copy(game.quadrant)
3767 navmode = "unspecified"
3771 if game.landed and not isprobe:
3772 prout(_("Dummy! You can't leave standard orbit until you"))
3773 proutn(_("are back aboard the ship."))
3776 while navmode == "unspecified":
3777 if damaged(DNAVSYS):
3779 prout(_("Computer damaged; manual navigation only"))
3781 prout(_("Computer damaged; manual movement only"))
3786 key = scanner.nexttok()
3788 proutn(_("Manual or automatic- "))
3791 elif key == "IHALPHA":
3792 if scanner.sees("manual"):
3794 key = scanner.nexttok()
3796 elif scanner.sees("automatic"):
3797 navmode = "automatic"
3798 key = scanner.nexttok()
3806 prout(_("(Manual navigation assumed.)"))
3808 prout(_("(Manual movement assumed.)"))
3812 if navmode == "automatic":
3813 while key == "IHEOL":
3815 proutn(_("Target quadrant or quadrant§or- "))
3817 proutn(_("Destination sector or quadrant§or- "))
3820 key = scanner.nexttok()
3824 xi = int(round(scanner.real))-1
3825 key = scanner.nexttok()
3829 xj = int(round(scanner.real))-1
3830 key = scanner.nexttok()
3832 # both quadrant and sector specified
3833 xk = int(round(scanner.real))-1
3834 key = scanner.nexttok()
3838 xl = int(round(scanner.real))-1
3844 # only one pair of numbers was specified
3846 # only quadrant specified -- go to center of dest quad
3849 dsect.j = dsect.i = 4 # preserves 1-origin behavior
3851 # only sector specified
3855 if not dquad.valid_quadrant() or not dsect.valid_sector():
3862 prout(_("Helmsman Sulu- \"Course locked in for Sector %s.\"") % dsect)
3864 prout(_("Ensign Chekov- \"Course laid in, Captain.\""))
3865 # the actual deltas get computed here
3866 delta.j = dquad.j-game.quadrant.j + (dsect.j-game.sector.j)/(QUADSIZE*1.0)
3867 delta.i = game.quadrant.i-dquad.i + (game.sector.i-dsect.i)/(QUADSIZE*1.0)
3869 while key == "IHEOL":
3870 proutn(_("X and Y displacements- "))
3873 key = scanner.nexttok()
3878 delta.j = scanner.real
3879 key = scanner.nexttok()
3883 delta.i = scanner.real
3884 # Check for zero movement
3885 if delta.i == 0 and delta.j == 0:
3888 if itemp == "verbose" and not isprobe:
3890 prout(_("Helmsman Sulu- \"Aye, Sir.\""))
3892 return course(bearing=delta.bearing(), distance=delta.distance())
3895 def __init__(self, bearing, distance, origin=None):
3896 self.distance = distance
3897 self.bearing = bearing
3899 self.origin = cartesian(game.quadrant, game.sector)
3901 self.origin = origin
3902 # The bearing() code we inherited from FORTRAN is actually computing
3903 # clockface directions!
3904 if self.bearing < 0.0:
3905 self.bearing += 12.0
3906 self.angle = ((15.0 - self.bearing) * 0.5235988)
3907 self.increment = Coord(-math.sin(self.angle), math.cos(self.angle))
3908 bigger = max(abs(self.increment.i), abs(self.increment.j))
3909 self.increment /= bigger
3910 self.moves = int(round(10*self.distance*bigger))
3912 self.final = (self.location + self.moves*self.increment).roundtogrid()
3913 self.location = self.origin
3914 self.nextlocation = None
3916 self.location = self.origin
3919 return self.location.roundtogrid() == self.final
3921 "Next step on course."
3923 self.nextlocation = self.location + self.increment
3924 samequad = (self.location.quadrant() == self.nextlocation.quadrant())
3925 self.location = self.nextlocation
3928 return self.location.quadrant()
3930 return self.location.sector()
3932 return self.distance*(w**3)*(game.shldup+1)
3934 return 10.0*self.distance/w**2
3937 "Move under impulse power."
3939 if damaged(DIMPULS):
3942 prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
3944 if game.energy > 30.0:
3946 icourse = getcourse(isprobe=False)
3949 power = 20.0 + 100.0*icourse.distance
3952 if power >= game.energy:
3953 # Insufficient power for trip
3955 prout(_("First Officer Spock- \"Captain, the impulse engines"))
3956 prout(_("require 20.0 units to engage, plus 100.0 units per"))
3957 if game.energy > 30:
3958 proutn(_("quadrant. We can go, therefore, a maximum of %d") %
3959 int(0.01 * (game.energy-20.0)-0.05))
3960 prout(_(" quadrants.\""))
3962 prout(_("quadrant. They are, therefore, useless.\""))
3965 # Make sure enough time is left for the trip
3966 game.optime = icourse.distance/0.095
3967 if game.optime >= game.state.remtime:
3968 prout(_("First Officer Spock- \"Captain, our speed under impulse"))
3969 prout(_("power is only 0.95 sectors per stardate. Are you sure"))
3970 proutn(_("we dare spend the time?\" "))
3973 # Activate impulse engines and pay the cost
3974 imove(icourse, noattack=False)
3978 power = 20.0 + 100.0*icourse.distance
3979 game.energy -= power
3980 game.optime = icourse.distance/0.095
3981 if game.energy <= 0:
3985 def warp(wcourse, involuntary):
3986 "ove under warp drive."
3987 blooey = False; twarp = False
3988 if not involuntary: # Not WARPX entry
3990 if game.damage[DWARPEN] > 10.0:
3993 prout(_("Engineer Scott- \"The warp engines are damaged, Sir.\""))
3995 if damaged(DWARPEN) and game.warpfac > 4.0:
3998 prout(_("Engineer Scott- \"Sorry, Captain. Until this damage"))
3999 prout(_(" is repaired, I can only give you warp 4.\""))
4001 # Read in course and distance
4004 wcourse = getcourse(isprobe=False)
4007 # Make sure starship has enough energy for the trip
4008 # Note: this formula is slightly different from the C version,
4009 # and lets you skate a bit closer to the edge.
4010 if wcourse.power(game.warpfac) >= game.energy:
4011 # Insufficient power for trip
4014 prout(_("Engineering to bridge--"))
4015 if not game.shldup or 0.5*wcourse.power(game.warpfac) > game.energy:
4016 iwarp = (game.energy/(wcourse.distance+0.05)) ** 0.333333333
4018 prout(_("We can't do it, Captain. We don't have enough energy."))
4020 proutn(_("We don't have enough energy, but we could do it at warp %d") % iwarp)
4023 prout(_("if you'll lower the shields."))
4027 prout(_("We haven't the energy to go that far with the shields up."))
4029 # Make sure enough time is left for the trip
4030 game.optime = wcourse.time(game.warpfac)
4031 if game.optime >= 0.8*game.state.remtime:
4033 prout(_("First Officer Spock- \"Captain, I compute that such"))
4034 proutn(_(" a trip would require approximately %2.0f") %
4035 (100.0*game.optime/game.state.remtime))
4036 prout(_(" percent of our"))
4037 proutn(_(" remaining time. Are you sure this is wise?\" "))
4043 if game.warpfac > 6.0:
4044 # Decide if engine damage will occur
4045 # ESR: Seems wrong. Probability of damage goes *down* with distance?
4046 prob = wcourse.distance*(6.0-game.warpfac)**2/66.666666666
4047 if prob > randreal():
4049 wcourse.distance = randreal(wcourse.distance)
4050 # Decide if time warp will occur
4051 if 0.5*wcourse.distance*math.pow(7.0,game.warpfac-10.0) > randreal():
4053 if game.idebug and game.warpfac==10 and not twarp:
4055 proutn("=== Force time warp? ")
4059 # If time warp or engine damage, check path
4060 # If it is obstructed, don't do warp or damage
4061 look = wcourse.moves
4065 w = wcourse.sector()
4066 if not w.valid_sector():
4068 if game.quad[w.i][w.j] != '.':
4072 # Activate Warp Engines and pay the cost
4073 imove(wcourse, noattack=False)
4076 game.energy -= wcourse.power(game.warpfac)
4077 if game.energy <= 0:
4079 game.optime = wcourse.time(game.warpfac)
4083 game.damage[DWARPEN] = game.damfac * randreal(1.0, 4.0)
4085 prout(_("Engineering to bridge--"))
4086 prout(_(" Scott here. The warp engines are damaged."))
4087 prout(_(" We'll have to reduce speed to warp 4."))
4092 "Change the warp factor."
4094 key=scanner.nexttok()
4098 proutn(_("Warp factor- "))
4102 if game.damage[DWARPEN] > 10.0:
4103 prout(_("Warp engines inoperative."))
4105 if damaged(DWARPEN) and scanner.real > 4.0:
4106 prout(_("Engineer Scott- \"I'm doing my best, Captain,"))
4107 prout(_(" but right now we can only go warp 4.\""))
4109 if scanner.real > 10.0:
4110 prout(_("Helmsman Sulu- \"Our top speed is warp 10, Captain.\""))
4112 if scanner.real < 1.0:
4113 prout(_("Helmsman Sulu- \"We can't go below warp 1, Captain.\""))
4115 oldfac = game.warpfac
4116 game.warpfac = scanner.real
4117 if game.warpfac <= oldfac or game.warpfac <= 6.0:
4118 prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\"") %
4121 if game.warpfac < 8.00:
4122 prout(_("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\""))
4124 if game.warpfac == 10.0:
4125 prout(_("Engineer Scott- \"Aye, Captain, we'll try it.\""))
4127 prout(_("Engineer Scott- \"Aye, Captain, but our engines may not take it.\""))
4131 "Cope with being tossed out of quadrant by supernova or yanked by beam."
4133 # is captain on planet?
4135 if damaged(DTRANSP):
4138 prout(_("Scotty rushes to the transporter controls."))
4140 prout(_("But with the shields up it's hopeless."))
4142 prouts(_("His desperate attempt to rescue you . . ."))
4147 prout(_("SUCCEEDS!"))
4150 proutn(_("The crystals mined were "))
4158 # Check to see if captain in shuttle craft
4163 # Inform captain of attempt to reach safety
4167 prouts(_("***RED ALERT! RED ALERT!"))
4169 proutn(_("The %s has stopped in a quadrant containing") % crmshp())
4170 prouts(_(" a supernova."))
4172 prout(_("***Emergency automatic override attempts to hurl ")+crmshp())
4173 prout(_("safely out of quadrant."))
4174 if not damaged(DRADIO):
4175 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
4176 # Try to use warp engines
4177 if damaged(DWARPEN):
4179 prout(_("Warp engines damaged."))
4182 game.warpfac = randreal(6.0, 8.0)
4183 prout(_("Warp factor set to %d") % int(game.warpfac))
4184 power = 0.75*game.energy
4185 dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1))
4186 dist = max(dist, randreal(math.sqrt(2)))
4187 bugout = course(bearing=randreal(12), distance=dist) # How dumb!
4188 game.optime = bugout.time(game.warpfac)
4190 game.inorbit = False
4191 warp(bugout, involuntary=True)
4193 # This is bad news, we didn't leave quadrant.
4197 prout(_("Insufficient energy to leave quadrant."))
4200 # Repeat if another snova
4201 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
4203 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
4204 finish(FWON) # Snova killed remaining enemy.
4207 "Let's do the time warp again."
4208 prout(_("***TIME WARP ENTERED."))
4209 if game.state.snap and withprob(0.5):
4211 prout(_("You are traveling backwards in time %d stardates.") %
4212 int(game.state.date-game.snapsht.date))
4213 game.state = game.snapsht
4214 game.state.snap = False
4215 if len(game.state.kcmdr):
4216 schedule(FTBEAM, expran(game.intime/len(game.state.kcmdr)))
4217 schedule(FBATTAK, expran(0.3*game.intime))
4218 schedule(FSNOVA, expran(0.5*game.intime))
4219 # next snapshot will be sooner
4220 schedule(FSNAP, expran(0.25*game.state.remtime))
4222 if game.state.nscrem:
4223 schedule(FSCMOVE, 0.2777)
4227 game.battle.invalidate()
4228 # Make sure Galileo is consistant -- Snapshot may have been taken
4229 # when on planet, which would give us two Galileos!
4231 for l in range(game.inplan):
4232 if game.state.planets[l].known == "shuttle_down":
4234 if game.iscraft == "onship" and game.ship=='E':
4235 prout(_("Chekov- \"Security reports the Galileo has disappeared, Sir!"))
4236 game.iscraft = "offship"
4237 # Likewise, if in the original time the Galileo was abandoned, but
4238 # was on ship earlier, it would have vanished -- let's restore it.
4239 if game.iscraft == "offship" and not gotit and game.damage[DSHUTTL] >= 0.0:
4240 prout(_("Chekov- \"Security reports the Galileo has reappeared in the dock!\""))
4241 game.iscraft = "onship"
4242 # There used to be code to do the actual reconstrction here,
4243 # but the starchart is now part of the snapshotted galaxy state.
4244 prout(_("Spock has reconstructed a correct star chart from memory"))
4246 # Go forward in time
4247 game.optime = expran(0.5*game.intime)
4248 prout(_("You are traveling forward in time %d stardates.") % int(game.optime))
4249 # cheat to make sure no tractor beams occur during time warp
4250 postpone(FTBEAM, game.optime)
4251 game.damage[DRADIO] += game.optime
4253 events() # Stas Sergeev added this -- do pending events
4256 "Launch deep-space probe."
4257 # New code to launch a deep space probe
4258 if game.nprobes == 0:
4261 if game.ship == 'E':
4262 prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\""))
4264 prout(_("Ye Faerie Queene has no deep space probes."))
4269 prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\""))
4271 if is_scheduled(FDSPROB):
4274 if damaged(DRADIO) and game.condition != "docked":
4275 prout(_("Spock- \"Records show the previous probe has not yet"))
4276 prout(_(" reached its destination.\""))
4278 prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""))
4280 key = scanner.nexttok()
4282 if game.nprobes == 1:
4283 prout(_("1 probe left."))
4285 prout(_("%d probes left") % game.nprobes)
4286 proutn(_("Are you sure you want to fire a probe? "))
4289 game.isarmed = False
4290 if key == "IHALPHA" and scanner.token == "armed":
4292 key = scanner.nexttok()
4293 elif key == "IHEOL":
4294 proutn(_("Arm NOVAMAX warhead? "))
4296 elif key == "IHREAL": # first element of course
4297 scanner.push(scanner.token)
4299 game.probe = getcourse(isprobe=True)
4303 schedule(FDSPROB, 0.01) # Time to move one sector
4304 prout(_("Ensign Chekov- \"The deep space probe is launched, Captain.\""))
4309 "Yell for help from nearest starbase."
4310 # There's more than one way to move in this game!
4312 # Test for conditions which prevent calling for help
4313 if game.condition == "docked":
4314 prout(_("Lt. Uhura- \"But Captain, we're already docked.\""))
4317 prout(_("Subspace radio damaged."))
4319 if not game.state.baseq:
4320 prout(_("Lt. Uhura- \"Captain, I'm not getting any response from Starbase.\""))
4323 prout(_("You must be aboard the %s.") % crmshp())
4325 # OK -- call for help from nearest starbase
4328 # There's one in this quadrant
4329 ddist = (game.base - game.sector).distance()
4331 ibq = None # Force base-quadrant game to persist past loop
4333 for ibq in game.state.baseq:
4334 xdist = QUADSIZE * (ibq - game.quadrant).distance()
4338 prout(_("No starbases remain. You are alone in a hostile galaxy."))
4340 # Since starbase not in quadrant, set up new quadrant
4343 # dematerialize starship
4344 game.quad[game.sector.i][game.sector.j]='.'
4345 proutn(_("Starbase in Quadrant %s responds--%s dematerializes") \
4346 % (game.quadrant, crmshp()))
4347 game.sector.invalidate()
4348 for m in range(1, 5+1):
4349 w = game.base.scatter()
4350 if w.valid_sector() and game.quad[w.i][w.j]=='.':
4351 # found one -- finish up
4354 if not game.sector.is_valid():
4355 prout(_("You have been lost in space..."))
4356 finish(FMATERIALIZE)
4358 # Give starbase three chances to rematerialize starship
4359 probf = math.pow((1.0 - math.pow(0.98,ddist)), 0.33333333)
4360 for m in range(1, 3+1):
4361 if m == 1: proutn(_("1st"))
4362 elif m == 2: proutn(_("2nd"))
4363 elif m == 3: proutn(_("3rd"))
4364 proutn(_(" attempt to re-materialize ") + crmshp())
4365 game.quad[game.sector.i][game.sector.j]=('-','o','O')[m-1]
4368 if randreal() > probf:
4372 curses.delay_output(500)
4374 game.quad[game.sector.i][game.sector.j]='?'
4377 setwnd(message_window)
4378 finish(FMATERIALIZE)
4380 game.quad[game.sector.i][game.sector.j]=game.ship
4382 prout(_("succeeds."))
4386 prout(_("Lt. Uhura- \"Captain, we made it!\""))
4391 if game.condition=="docked":
4393 prout(_("You cannot abandon Ye Faerie Queene."))
4396 # Must take shuttle craft to exit
4397 if game.damage[DSHUTTL]==-1:
4398 prout(_("Ye Faerie Queene has no shuttle craft."))
4400 if game.damage[DSHUTTL]<0:
4401 prout(_("Shuttle craft now serving Big Macs."))
4403 if game.damage[DSHUTTL]>0:
4404 prout(_("Shuttle craft damaged."))
4407 prout(_("You must be aboard the ship."))
4409 if game.iscraft != "onship":
4410 prout(_("Shuttle craft not currently available."))
4412 # Emit abandon ship messages
4414 prouts(_("***ABANDON SHIP! ABANDON SHIP!"))
4416 prouts(_("***ALL HANDS ABANDON SHIP!"))
4418 prout(_("Captain and crew escape in shuttle craft."))
4419 if not game.state.baseq:
4420 # Oops! no place to go...
4423 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
4425 if not (game.options & OPTION_WORLDS) and not damaged(DTRANSP):
4426 prout(_("Remainder of ship's complement beam down"))
4427 prout(_("to nearest habitable planet."))
4428 elif q.planet != None and not damaged(DTRANSP):
4429 prout(_("Remainder of ship's complement beam down to %s.") %
4432 prout(_("Entire crew of %d left to die in outer space.") %
4434 game.casual += game.state.crew
4435 game.abandoned += game.state.crew
4436 # If at least one base left, give 'em the Faerie Queene
4438 game.icrystl = False # crystals are lost
4439 game.nprobes = 0 # No probes
4440 prout(_("You are captured by Klingons and released to"))
4441 prout(_("the Federation in a prisoner-of-war exchange."))
4442 nb = randrange(len(game.state.baseq))
4443 # Set up quadrant and position FQ adjacient to base
4444 if not game.quadrant == game.state.baseq[nb]:
4445 game.quadrant = game.state.baseq[nb]
4446 game.sector.i = game.sector.j = 5
4449 # position next to base by trial and error
4450 game.quad[game.sector.i][game.sector.j] = '.'
4452 for l in range(QUADSIZE):
4453 game.sector = game.base.scatter()
4454 if game.sector.valid_sector() and \
4455 game.quad[game.sector.i][game.sector.j] == '.':
4458 break # found a spot
4459 game.sector.i=QUADSIZE/2
4460 game.sector.j=QUADSIZE/2
4462 # Get new commission
4463 game.quad[game.sector.i][game.sector.j] = game.ship = 'F'
4464 game.state.crew = FULLCREW
4465 prout(_("Starfleet puts you in command of another ship,"))
4466 prout(_("the Faerie Queene, which is antiquated but,"))
4467 prout(_("still useable."))
4469 prout(_("The dilithium crystals have been moved."))
4471 game.iscraft = "offship" # Galileo disappears
4473 game.condition="docked"
4474 for l in range(NDEVICES):
4475 game.damage[l] = 0.0
4476 game.damage[DSHUTTL] = -1
4477 game.energy = game.inenrg = 3000.0
4478 game.shield = game.inshld = 1250.0
4479 game.torps = game.intorps = 6
4480 game.lsupres=game.inlsr=3.0
4483 game.brigfree = game.brigcapacity = 300
4486 # Code from planets.c begins here.
4489 "Abort a lengthy operation if an event interrupts it."
4492 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.justin:
4497 "Report on (uninhabited) planets in the galaxy."
4501 prout(_("Spock- \"Planet report follows, Captain.\""))
4503 for i in range(game.inplan):
4504 if game.state.planets[i].pclass == "destroyed":
4506 if (game.state.planets[i].known != "unknown" \
4507 and not game.state.planets[i].inhabited) \
4510 if game.idebug and game.state.planets[i].known=="unknown":
4511 proutn("(Unknown) ")
4512 proutn(_("Quadrant %s") % game.state.planets[i].quadrant)
4513 proutn(_(" class "))
4514 proutn(game.state.planets[i].pclass)
4516 if game.state.planets[i].crystals != "present":
4518 prout(_("dilithium crystals present."))
4519 if game.state.planets[i].known=="shuttle_down":
4520 prout(_(" Shuttle Craft Galileo on surface."))
4522 prout(_("No information available."))
4525 "Enter standard orbit."
4529 prout(_("Already in standard orbit."))
4531 if damaged(DWARPEN) and damaged(DIMPULS):
4532 prout(_("Both warp and impulse engines damaged."))
4534 if not game.plnet.is_valid():
4535 prout("There is no planet in this sector.")
4537 if abs(game.sector.i-game.plnet.i)>1 or abs(game.sector.j-game.plnet.j)>1:
4538 prout(crmshp() + _(" not adjacent to planet."))
4541 game.optime = randreal(0.02, 0.05)
4542 prout(_("Helmsman Sulu- \"Entering standard orbit, Sir.\""))
4546 game.height = randreal(1400, 8600)
4547 prout(_("Sulu- \"Entered orbit at altitude %.2f kilometers.\"") % game.height)
4552 "Examine planets in this quadrant."
4553 if damaged(DSRSENS):
4554 if game.options & OPTION_TTY:
4555 prout(_("Short range sensors damaged."))
4557 if game.iplnet is None:
4558 if game.options & OPTION_TTY:
4559 prout(_("Spock- \"No planet in this quadrant, Captain.\""))
4561 if game.iplnet.known == "unknown":
4562 prout(_("Spock- \"Sensor scan for Quadrant %s-") % game.quadrant)
4564 prout(_(" Planet at Sector %s is of class %s.") %
4565 (game.plnet, game.iplnet.pclass))
4566 if game.iplnet.known=="shuttle_down":
4567 prout(_(" Sensors show Galileo still on surface."))
4568 proutn(_(" Readings indicate"))
4569 if game.iplnet.crystals != "present":
4571 prout(_(" dilithium crystals present.\""))
4572 if game.iplnet.known == "unknown":
4573 game.iplnet.known = "known"
4574 elif game.iplnet.inhabited:
4575 prout(_("Spock- \"The inhabited planet %s ") % game.iplnet.name)
4576 prout(_(" is located at Sector %s, Captain.\"") % game.plnet)
4579 "Use the transporter."
4583 if damaged(DTRANSP):
4584 prout(_("Transporter damaged."))
4585 if not damaged(DSHUTTL) and (game.iplnet.known=="shuttle_down" or game.iscraft == "onship"):
4587 proutn(_("Spock- \"May I suggest the shuttle craft, Sir?\" "))
4591 if not game.inorbit:
4592 prout(crmshp() + _(" not in standard orbit."))
4595 prout(_("Impossible to transport through shields."))
4597 if game.iplnet.known=="unknown":
4598 prout(_("Spock- \"Captain, we have no information on this planet"))
4599 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4600 prout(_(" you may not go down.\""))
4602 if not game.landed and game.iplnet.crystals=="absent":
4603 prout(_("Spock- \"Captain, I fail to see the logic in"))
4604 prout(_(" exploring a planet with no dilithium crystals."))
4605 proutn(_(" Are you sure this is wise?\" "))
4609 if not (game.options & OPTION_PLAIN):
4610 nrgneed = 50 * game.skill + game.height / 100.0
4611 if nrgneed > game.energy:
4612 prout(_("Engineering to bridge--"))
4613 prout(_(" Captain, we don't have enough energy for transportation."))
4615 if not game.landed and nrgneed * 2 > game.energy:
4616 prout(_("Engineering to bridge--"))
4617 prout(_(" Captain, we have enough energy only to transport you down to"))
4618 prout(_(" the planet, but there wouldn't be an energy for the trip back."))
4619 if game.iplnet.known == "shuttle_down":
4620 prout(_(" Although the Galileo shuttle craft may still be on a surface."))
4621 proutn(_(" Are you sure this is wise?\" "))
4626 # Coming from planet
4627 if game.iplnet.known=="shuttle_down":
4628 proutn(_("Spock- \"Wouldn't you rather take the Galileo?\" "))
4632 prout(_("Your crew hides the Galileo to prevent capture by aliens."))
4633 prout(_("Landing party assembled, ready to beam up."))
4635 prout(_("Kirk whips out communicator..."))
4636 prouts(_("BEEP BEEP BEEP"))
4638 prout(_("\"Kirk to enterprise- Lock on coordinates...energize.\""))
4641 prout(_("Scotty- \"Transporter room ready, Sir.\""))
4643 prout(_("Kirk and landing party prepare to beam down to planet surface."))
4645 prout(_("Kirk- \"Energize.\""))
4648 prouts("WWHOOOIIIIIRRRRREEEE.E.E. . . . . . .")
4650 if not withprob(0.98):
4651 prouts("BOOOIIIOOOIIOOOOIIIOIING . . .")
4653 prout(_("Scotty- \"Oh my God! I've lost them.\""))
4656 prouts(". . . . . . .E.E.EEEERRRRRIIIIIOOOHWW")
4657 game.landed = not game.landed
4658 game.energy -= nrgneed
4660 prout(_("Transport complete."))
4661 if game.landed and game.iplnet.known=="shuttle_down":
4662 prout(_("The shuttle craft Galileo is here!"))
4663 if not game.landed and game.imine:
4670 "Strip-mine a world for dilithium."
4674 prout(_("Mining party not on planet."))
4676 if game.iplnet.crystals == "mined":
4677 prout(_("This planet has already been strip-mined for dilithium."))
4679 elif game.iplnet.crystals == "absent":
4680 prout(_("No dilithium crystals on this planet."))
4683 prout(_("You've already mined enough crystals for this trip."))
4685 if game.icrystl and game.cryprob == 0.05:
4686 prout(_("With all those fresh crystals aboard the ") + crmshp())
4687 prout(_("there's no reason to mine more at this time."))
4689 game.optime = randreal(0.1, 0.3)*(ord(game.iplnet.pclass)-ord("L"))
4692 prout(_("Mining operation complete."))
4693 game.iplnet.crystals = "mined"
4694 game.imine = game.ididit = True
4697 "Use dilithium crystals."
4701 if not game.icrystl:
4702 prout(_("No dilithium crystals available."))
4704 if game.energy >= 1000:
4705 prout(_("Spock- \"Captain, Starfleet Regulations prohibit such an operation"))
4706 prout(_(" except when Condition Yellow exists."))
4708 prout(_("Spock- \"Captain, I must warn you that loading"))
4709 prout(_(" raw dilithium crystals into the ship's power"))
4710 prout(_(" system may risk a severe explosion."))
4711 proutn(_(" Are you sure this is wise?\" "))
4716 prout(_("Engineering Officer Scott- \"(GULP) Aye Sir."))
4717 prout(_(" Mr. Spock and I will try it.\""))
4719 prout(_("Spock- \"Crystals in place, Sir."))
4720 prout(_(" Ready to activate circuit.\""))
4722 prouts(_("Scotty- \"Keep your fingers crossed, Sir!\""))
4724 if withprob(game.cryprob):
4725 prouts(_(" \"Activating now! - - No good! It's***"))
4727 prouts(_("***RED ALERT! RED A*L********************************"))
4730 prouts(_("****************** KA-BOOM!!!! *******************"))
4734 game.energy += randreal(5000.0, 5500.0)
4735 prouts(_(" \"Activating now! - - "))
4736 prout(_("The instruments"))
4737 prout(_(" are going crazy, but I think it's"))
4738 prout(_(" going to work!! Congratulations, Sir!\""))
4743 "Use shuttlecraft for planetary jaunt."
4746 if damaged(DSHUTTL):
4747 if game.damage[DSHUTTL] == -1.0:
4748 if game.inorbit and game.iplnet.known == "shuttle_down":
4749 prout(_("Ye Faerie Queene has no shuttle craft bay to dock it at."))
4751 prout(_("Ye Faerie Queene had no shuttle craft."))
4752 elif game.damage[DSHUTTL] > 0:
4753 prout(_("The Galileo is damaged."))
4754 else: # game.damage[DSHUTTL] < 0
4755 prout(_("Shuttle craft is now serving Big Macs."))
4757 if not game.inorbit:
4758 prout(crmshp() + _(" not in standard orbit."))
4760 if (game.iplnet.known != "shuttle_down") and game.iscraft != "onship":
4761 prout(_("Shuttle craft not currently available."))
4763 if not game.landed and game.iplnet.known=="shuttle_down":
4764 prout(_("You will have to beam down to retrieve the shuttle craft."))
4766 if game.shldup or game.condition == "docked":
4767 prout(_("Shuttle craft cannot pass through shields."))
4769 if game.iplnet.known=="unknown":
4770 prout(_("Spock- \"Captain, we have no information on this planet"))
4771 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4772 prout(_(" you may not fly down.\""))
4774 game.optime = 3.0e-5*game.height
4775 if game.optime >= 0.8*game.state.remtime:
4776 prout(_("First Officer Spock- \"Captain, I compute that such"))
4777 proutn(_(" a maneuver would require approximately %2d%% of our") % \
4778 int(100*game.optime/game.state.remtime))
4779 prout(_("remaining time."))
4780 proutn(_("Are you sure this is wise?\" "))
4786 if game.iscraft == "onship":
4788 if not damaged(DTRANSP):
4789 proutn(_("Spock- \"Would you rather use the transporter?\" "))
4793 proutn(_("Shuttle crew"))
4795 proutn(_("Rescue party"))
4796 prout(_(" boards Galileo and swoops toward planet surface."))
4797 game.iscraft = "offship"
4801 game.iplnet.known="shuttle_down"
4802 prout(_("Trip complete."))
4805 # Ready to go back to ship
4806 prout(_("You and your mining party board the"))
4807 prout(_("shuttle craft for the trip back to the Enterprise."))
4809 prouts(_("The short hop begins . . ."))
4811 game.iplnet.known="known"
4817 game.iscraft = "onship"
4823 prout(_("Trip complete."))
4826 # Kirk on ship and so is Galileo
4827 prout(_("Mining party assembles in the hangar deck,"))
4828 prout(_("ready to board the shuttle craft \"Galileo\"."))
4830 prouts(_("The hangar doors open; the trip begins."))
4833 game.iscraft = "offship"
4836 game.iplnet.known = "shuttle_down"
4839 prout(_("Trip complete."))
4843 "Use the big zapper."
4847 if game.ship != 'E':
4848 prout(_("Ye Faerie Queene has no death ray."))
4850 if len(game.enemies)==0:
4851 prout(_("Sulu- \"But Sir, there are no enemies in this quadrant.\""))
4854 prout(_("Death Ray is damaged."))
4856 prout(_("Spock- \"Captain, the 'Experimental Death Ray'"))
4857 prout(_(" is highly unpredictible. Considering the alternatives,"))
4858 proutn(_(" are you sure this is wise?\" "))
4861 prout(_("Spock- \"Acknowledged.\""))
4864 prouts(_("WHOOEE ... WHOOEE ... WHOOEE ... WHOOEE"))
4866 prout(_("Crew scrambles in emergency preparation."))
4867 prout(_("Spock and Scotty ready the death ray and"))
4868 prout(_("prepare to channel all ship's power to the device."))
4870 prout(_("Spock- \"Preparations complete, sir.\""))
4871 prout(_("Kirk- \"Engage!\""))
4873 prouts(_("WHIRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"))
4876 if game.options & OPTION_PLAIN:
4880 prouts(_("Sulu- \"Captain! It's working!\""))
4882 while len(game.enemies) > 0:
4883 deadkl(game.enemies[1].location, game.quad[game.enemies[1].location.i][game.enemies[1].location.j],game.enemies[1].location)
4884 prout(_("Ensign Chekov- \"Congratulations, Captain!\""))
4885 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
4887 if (game.options & OPTION_PLAIN) == 0:
4888 prout(_("Spock- \"Captain, I believe the `Experimental Death Ray'"))
4890 prout(_(" is still operational.\""))
4892 prout(_(" has been rendered nonfunctional.\""))
4893 game.damage[DDRAY] = 39.95
4895 r = randreal() # Pick failure method
4897 prouts(_("Sulu- \"Captain! It's working!\""))
4899 prouts(_("***RED ALERT! RED ALERT!"))
4901 prout(_("***MATTER-ANTIMATTER IMPLOSION IMMINENT!"))
4903 prouts(_("***RED ALERT! RED A*L********************************"))
4906 prouts(_("****************** KA-BOOM!!!! *******************"))
4911 prouts(_("Sulu- \"Captain! Yagabandaghangrapl, brachriigringlanbla!\""))
4913 prout(_("Lt. Uhura- \"Graaeek! Graaeek!\""))
4915 prout(_("Spock- \"Fascinating! . . . All humans aboard"))
4916 prout(_(" have apparently been transformed into strange mutations."))
4917 prout(_(" Vulcans do not seem to be affected."))
4919 prout(_("Kirk- \"Raauch! Raauch!\""))
4923 prouts(_("Sulu- \"Captain! It's --WHAT?!?!\""))
4925 proutn(_("Spock- \"I believe the word is"))
4926 prouts(_(" *ASTONISHING*"))
4927 prout(_(" Mr. Sulu."))
4928 for i in range(QUADSIZE):
4929 for j in range(QUADSIZE):
4930 if game.quad[i][j] == '.':
4931 game.quad[i][j] = '?'
4932 prout(_(" Captain, our quadrant is now infested with"))
4933 prouts(_(" - - - - - - *THINGS*."))
4935 prout(_(" I have no logical explanation.\""))
4937 prouts(_("Sulu- \"Captain! The Death Ray is creating tribbles!\""))
4939 prout(_("Scotty- \"There are so many tribbles down here"))
4940 prout(_(" in Engineering, we can't move for 'em, Captain.\""))
4944 # Code from reports.c begins here
4946 def attackreport(curt):
4947 "eport status of bases under attack."
4949 if is_scheduled(FCDBAS):
4950 prout(_("Starbase in Quadrant %s is currently under Commander attack.") % game.battle)
4951 prout(_("It can hold out until Stardate %d.") % int(scheduled(FCDBAS)))
4952 elif game.isatb == 1:
4953 prout(_("Starbase in Quadrant %s is under Super-commander attack.") % game.state.kscmdr)
4954 prout(_("It can hold out until Stardate %d.") % int(scheduled(FSCDBAS)))
4956 prout(_("No Starbase is currently under attack."))
4958 if is_scheduled(FCDBAS):
4959 proutn(_("Base in %s attacked by C. Alive until %.1f") % (game.battle, scheduled(FCDBAS)))
4961 proutn(_("Base in %s attacked by S. Alive until %.1f") % (game.state.kscmdr, scheduled(FSCDBAS)))
4965 # report on general game status
4967 s1 = (game.thawed and _("thawed ")) or ""
4968 s2 = {1:"short", 2:"medium", 4:"long"}[game.length]
4969 s3 = (None, _("novice"), _("fair"),
4970 _("good"), _("expert"), _("emeritus"))[game.skill]
4971 prout(_("You %s a %s%s %s game.") % ((_("were playing"), _("are playing"))[game.alldone], s1, s2, s3))
4972 if game.skill>SKILL_GOOD and game.thawed and not game.alldone:
4973 prout(_("No plaque is allowed."))
4975 prout(_("This is tournament game %d.") % game.tourn)
4976 prout(_("Your secret password is \"%s\"") % game.passwd)
4977 proutn(_("%d of %d Klingons have been killed") % (((game.inkling + game.incom + game.inscom) - (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)),
4978 (game.inkling + game.incom + game.inscom)))
4979 if game.incom - len(game.state.kcmdr):
4980 prout(_(", including %d Commander%s.") % (game.incom - len(game.state.kcmdr), (_("s"), "")[(game.incom - len(game.state.kcmdr))==1]))
4981 elif game.inkling - game.state.remkl + (game.inscom - game.state.nscrem) > 0:
4982 prout(_(", but no Commanders."))
4985 if game.skill > SKILL_FAIR:
4986 prout(_("The Super Commander has %sbeen destroyed.") % ("", _("not "))[game.state.nscrem])
4987 if len(game.state.baseq) != game.inbase:
4989 if game.inbase-len(game.state.baseq)==1:
4990 proutn(_("has been 1 base"))
4992 proutn(_("have been %d bases") % (game.inbase-len(game.state.baseq)))
4993 prout(_(" destroyed, %d remaining.") % len(game.state.baseq))
4995 prout(_("There are %d bases.") % game.inbase)
4996 if communicating() or game.iseenit:
4997 # Don't report this if not seen and
4998 # either the radio is dead or not at base!
5002 prout(_("%d casualt%s suffered so far.") % (game.casual, ("y", "ies")[game.casual!=1]))
5003 if game.brigcapacity != game.brigfree:
5004 embriggened = brigcapacity-brigfree
5005 if embriggened == 1:
5006 prout(_("1 Klingon in brig"))
5008 prout(_("%d Klingons in brig.") % embriggened)
5009 if game.kcaptured == 0:
5011 elif game.kcaptured == 1:
5012 prout(_("1 captured Klingon turned in to Starfleet."))
5014 prout(_("%d captured Klingons turned in to Star Fleet.") % game.kcaptured)
5016 prout(_("There were %d call%s for help.") % (game.nhelp, ("" , _("s"))[game.nhelp!=1]))
5017 if game.ship == 'E':
5018 proutn(_("You have "))
5020 proutn("%d" % (game.nprobes))
5023 proutn(_(" deep space probe"))
5027 if communicating() and is_scheduled(FDSPROB):
5029 proutn(_("An armed deep space probe is in "))
5031 proutn(_("A deep space probe is in "))
5032 prout("Quadrant %s." % game.probe.quadrant())
5034 if game.cryprob <= .05:
5035 prout(_("Dilithium crystals aboard ship... not yet used."))
5039 while game.cryprob > ai:
5042 prout(_("Dilithium crystals have been used %d time%s.") % \
5043 (i, (_("s"), "")[i==1]))
5047 "Long-range sensor scan."
5048 if damaged(DLRSENS):
5049 # Now allow base's sensors if docked
5050 if game.condition != "docked":
5052 prout(_("LONG-RANGE SENSORS DAMAGED."))
5055 prout(_("Starbase's long-range scan"))
5057 prout(_("Long-range scan"))
5058 for x in range(game.quadrant.i-1, game.quadrant.i+2):
5061 for y in range(game.quadrant.j-1, game.quadrant.j+2):
5062 if not Coord(x, y).valid_quadrant():
5066 if not damaged(DRADIO):
5067 game.state.galaxy[x][y].charted = True
5068 game.state.chart[x][y].klingons = game.state.galaxy[x][y].klingons
5069 game.state.chart[x][y].starbase = game.state.galaxy[x][y].starbase
5070 game.state.chart[x][y].stars = game.state.galaxy[x][y].stars
5071 if not silent and game.state.galaxy[x][y].supernova:
5074 proutn(" %3d" % (game.state.chart[x][y].klingons*100 + game.state.chart[x][y].starbase * 10 + game.state.chart[x][y].stars))
5082 for i in range(NDEVICES):
5085 prout(_("\tDEVICE\t\t\t-REPAIR TIMES-"))
5086 prout(_("\t\t\tIN FLIGHT\t\tDOCKED"))
5088 prout(" %-26s\t%8.2f\t\t%8.2f" % (device[i],
5089 game.damage[i]+0.05,
5090 DOCKFAC*game.damage[i]+0.005))
5092 prout(_("All devices functional."))
5095 "Update the chart in the Enterprise's computer from galaxy data."
5096 game.lastchart = game.state.date
5097 for i in range(GALSIZE):
5098 for j in range(GALSIZE):
5099 if game.state.galaxy[i][j].charted:
5100 game.state.chart[i][j].klingons = game.state.galaxy[i][j].klingons
5101 game.state.chart[i][j].starbase = game.state.galaxy[i][j].starbase
5102 game.state.chart[i][j].stars = game.state.galaxy[i][j].stars
5105 "Display the star chart."
5107 if (game.options & OPTION_AUTOSCAN):
5109 if not damaged(DRADIO):
5111 if game.lastchart < game.state.date and game.condition == "docked":
5112 prout(_("Spock- \"I revised the Star Chart from the starbase's records.\""))
5114 prout(_(" STAR CHART FOR THE KNOWN GALAXY"))
5115 if game.state.date > game.lastchart:
5116 prout(_("(Last surveillance update %d stardates ago).") % ((int)(game.state.date-game.lastchart)))
5117 prout(" 1 2 3 4 5 6 7 8")
5118 for i in range(GALSIZE):
5119 proutn("%d |" % (i+1))
5120 for j in range(GALSIZE):
5121 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5125 if game.state.galaxy[i][j].supernova:
5127 elif not game.state.galaxy[i][j].charted and game.state.galaxy[i][j].starbase:
5129 elif game.state.galaxy[i][j].charted:
5130 show = "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars)
5134 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5142 def sectscan(goodScan, i, j):
5143 "Light up an individual dot in a sector."
5144 if goodScan or (abs(i-game.sector.i)<= 1 and abs(j-game.sector.j) <= 1):
5145 if game.quad[i][j] in ('E', 'F'):
5146 textcolor({"green":GREEN,
5150 "dead":BROWN}[game.condition])
5152 textcolor({'?':LIGHTMAGENTA,
5158 }.get(game.quad[i][j], DEFAULT))
5159 proutn("%c " % game.quad[i][j])
5165 "Emit status report lines"
5166 if not req or req == 1:
5167 prstat(_("Stardate"), _("%.1f, Time Left %.2f") \
5168 % (game.state.date, game.state.remtime))
5169 if not req or req == 2:
5170 if game.condition != "docked":
5172 prstat(_("Condition"), _("%s, %i DAMAGES") % \
5173 (game.condition.upper(), sum([x > 0 for x in game.damage])))
5174 if not req or req == 3:
5175 prstat(_("Position"), "%s , %s" % (game.quadrant, game.sector))
5176 if not req or req == 4:
5177 if damaged(DLIFSUP):
5178 if game.condition == "docked":
5179 s = _("DAMAGED, Base provides")
5181 s = _("DAMAGED, reserves=%4.2f") % game.lsupres
5184 prstat(_("Life Support"), s)
5185 if not req or req == 5:
5186 prstat(_("Warp Factor"), "%.1f" % game.warpfac)
5187 if not req or req == 6:
5189 if game.icrystl and (game.options & OPTION_SHOWME):
5190 extra = _(" (have crystals)")
5191 prstat(_("Energy"), "%.2f%s" % (game.energy, extra))
5192 if not req or req == 7:
5193 prstat(_("Torpedoes"), "%d" % (game.torps))
5194 if not req or req == 8:
5195 if damaged(DSHIELD):
5201 data = _(" %d%% %.1f units") \
5202 % (int((100.0*game.shield)/game.inshld + 0.5), game.shield)
5203 prstat(_("Shields"), s+data)
5204 if not req or req == 9:
5205 prstat(_("Klingons Left"), "%d" \
5206 % (game.state.remkl+len(game.state.kcmdr)+game.state.nscrem))
5207 if not req or req == 10:
5208 if game.options & OPTION_WORLDS:
5209 plnet = game.state.galaxy[game.quadrant.i][game.quadrant.j].planet
5210 if plnet and plnet.inhabited:
5211 prstat(_("Major system"), plnet.name)
5213 prout(_("Sector is uninhabited"))
5214 elif not req or req == 11:
5215 attackreport(not req)
5218 "Request specified status data, a historical relic from slow TTYs."
5219 requests = ("da","co","po","ls","wa","en","to","sh","kl","sy", "ti")
5220 while scanner.nexttok() == "IHEOL":
5221 proutn(_("Information desired? "))
5223 if scanner.token in requests:
5224 status(requests.index(scanner.token))
5226 prout(_("UNRECOGNIZED REQUEST. Legal requests are:"))
5227 prout((" date, condition, position, lsupport, warpfactor,"))
5228 prout((" energy, torpedoes, shields, klingons, system, time."))
5233 if damaged(DSRSENS):
5234 # Allow base's sensors if docked
5235 if game.condition != "docked":
5236 prout(_(" S.R. SENSORS DAMAGED!"))
5239 prout(_(" [Using Base's sensors]"))
5241 prout(_(" Short-range scan"))
5242 if goodScan and not damaged(DRADIO):
5243 game.state.chart[game.quadrant.i][game.quadrant.j].klingons = game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons
5244 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase
5245 game.state.chart[game.quadrant.i][game.quadrant.j].stars = game.state.galaxy[game.quadrant.i][game.quadrant.j].stars
5246 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
5247 prout(" 1 2 3 4 5 6 7 8 9 10")
5248 if game.condition != "docked":
5250 for i in range(QUADSIZE):
5251 proutn("%2d " % (i+1))
5252 for j in range(QUADSIZE):
5253 sectscan(goodScan, i, j)
5257 "Use computer to get estimated time of arrival for a warp jump."
5258 w1 = Coord(); w2 = Coord()
5260 if damaged(DCOMPTR):
5261 prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR."))
5264 if scanner.nexttok() != "IHREAL":
5267 proutn(_("Destination quadrant and/or sector? "))
5268 if scanner.nexttok()!="IHREAL":
5271 w1.j = int(scanner.real-0.5)
5272 if scanner.nexttok() != "IHREAL":
5275 w1.i = int(scanner.real-0.5)
5276 if scanner.nexttok() == "IHREAL":
5277 w2.j = int(scanner.real-0.5)
5278 if scanner.nexttok() != "IHREAL":
5281 w2.i = int(scanner.real-0.5)
5283 if game.quadrant.j>w1.i:
5287 if game.quadrant.i>w1.j:
5291 if not w1.valid_quadrant() or not w2.valid_sector():
5294 dist = math.sqrt((w1.j-game.quadrant.j+(w2.j-game.sector.j)/(QUADSIZE*1.0))**2+
5295 (w1.i-game.quadrant.i+(w2.i-game.sector.i)/(QUADSIZE*1.0))**2)
5298 prout(_("Answer \"no\" if you don't know the value:"))
5301 proutn(_("Time or arrival date? "))
5302 if scanner.nexttok()=="IHREAL":
5303 ttime = scanner.real
5304 if ttime > game.state.date:
5305 ttime -= game.state.date # Actually a star date
5306 twarp=(math.floor(math.sqrt((10.0*dist)/ttime)*10.0)+1.0)/10.0
5307 if ttime <= 1e-10 or twarp > 10:
5308 prout(_("We'll never make it, sir."))
5315 proutn(_("Warp factor? "))
5316 if scanner.nexttok()== "IHREAL":
5318 twarp = scanner.real
5319 if twarp<1.0 or twarp > 10.0:
5323 prout(_("Captain, certainly you can give me one of these."))
5326 ttime = (10.0*dist)/twarp**2
5327 tpower = dist*twarp*twarp*twarp*(game.shldup+1)
5328 if tpower >= game.energy:
5329 prout(_("Insufficient energy, sir."))
5330 if not game.shldup or tpower > game.energy*2.0:
5333 proutn(_("New warp factor to try? "))
5334 if scanner.nexttok() == "IHREAL":
5336 twarp = scanner.real
5337 if twarp<1.0 or twarp > 10.0:
5345 prout(_("But if you lower your shields,"))
5346 proutn(_("remaining"))
5349 proutn(_("Remaining"))
5350 prout(_(" energy will be %.2f.") % (game.energy-tpower))
5352 prout(_("And we will arrive at stardate %.2f.") % (game.state.date+ttime))
5354 prout(_("Any warp speed is adequate."))
5356 prout(_("Minimum warp needed is %.2f,") % (twarp))
5357 prout(_("and we will arrive at stardate %.2f.") % (game.state.date+ttime))
5358 if game.state.remtime < ttime:
5359 prout(_("Unfortunately, the Federation will be destroyed by then."))
5361 prout(_("You'll be taking risks at that speed, Captain"))
5362 if (game.isatb==1 and game.state.kscmdr == w1 and \
5363 scheduled(FSCDBAS)< ttime+game.state.date) or \
5364 (scheduled(FCDBAS)<ttime+game.state.date and game.battle == w1):
5365 prout(_("The starbase there will be destroyed by then."))
5366 proutn(_("New warp factor to try? "))
5367 if scanner.nexttok() == "IHREAL":
5369 twarp = scanner.real
5370 if twarp<1.0 or twarp > 10.0:
5378 # Code from setup.c begins here
5381 "Issue a historically correct banner."
5383 prout(_("-SUPER- STAR TREK"))
5385 # From the FORTRAN original
5386 # prout(_("Latest update-21 Sept 78"))
5392 scanner.push("emsave.trk")
5393 key = scanner.nexttok()
5395 proutn(_("File name: "))
5396 key = scanner.nexttok()
5397 if key != "IHALPHA":
5400 if '.' not in scanner.token:
5401 scanner.token += ".trk"
5403 fp = open(scanner.token, "wb")
5405 prout(_("Can't freeze game as file %s") % scanner.token)
5407 pickle.dump(game, fp)
5412 "Retrieve saved game."
5415 key = scanner.nexttok()
5417 proutn(_("File name: "))
5418 key = scanner.nexttok()
5419 if key != "IHALPHA":
5422 if '.' not in scanner.token:
5423 scanner.token += ".trk"
5425 fp = open(scanner.token, "rb")
5427 prout(_("Can't thaw game in %s") % scanner.token)
5429 game = pickle.load(fp)
5434 # I used <http://www.memory-alpha.org> to find planets
5435 # with references in ST:TOS. Earth and the Alpha Centauri
5436 # Colony have been omitted.
5438 # Some planets marked Class G and P here will be displayed as class M
5439 # because of the way planets are generated. This is a known bug.
5442 _("Andoria (Fesoan)"), # several episodes
5443 _("Tellar Prime (Miracht)"), # TOS: "Journey to Babel"
5444 _("Vulcan (T'Khasi)"), # many episodes
5445 _("Medusa"), # TOS: "Is There in Truth No Beauty?"
5446 _("Argelius II (Nelphia)"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5447 _("Ardana"), # TOS: "The Cloud Minders"
5448 _("Catulla (Cendo-Prae)"), # TOS: "The Way to Eden"
5449 _("Gideon"), # TOS: "The Mark of Gideon"
5450 _("Aldebaran III"), # TOS: "The Deadly Years"
5451 _("Alpha Majoris I"), # TOS: "Wolf in the Fold"
5452 _("Altair IV"), # TOS: "Amok Time
5453 _("Ariannus"), # TOS: "Let That Be Your Last Battlefield"
5454 _("Benecia"), # TOS: "The Conscience of the King"
5455 _("Beta Niobe I (Sarpeidon)"), # TOS: "All Our Yesterdays"
5456 _("Alpha Carinae II"), # TOS: "The Ultimate Computer"
5457 _("Capella IV (Kohath)"), # TOS: "Friday's Child" (Class G)
5458 _("Daran V"), # TOS: "For the World is Hollow and I Have Touched the Sky"
5459 _("Deneb II"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5460 _("Eminiar VII"), # TOS: "A Taste of Armageddon"
5461 _("Gamma Canaris IV"), # TOS: "Metamorphosis"
5462 _("Gamma Tranguli VI (Vaalel)"), # TOS: "The Apple"
5463 _("Ingraham B"), # TOS: "Operation: Annihilate"
5464 _("Janus IV"), # TOS: "The Devil in the Dark"
5465 _("Makus III"), # TOS: "The Galileo Seven"
5466 _("Marcos XII"), # TOS: "And the Children Shall Lead",
5467 _("Omega IV"), # TOS: "The Omega Glory"
5468 _("Regulus V"), # TOS: "Amok Time
5469 _("Deneva"), # TOS: "Operation -- Annihilate!"
5470 # Worlds from BSD Trek
5471 _("Rigel II"), # TOS: "Shore Leave" ("III" in BSD)
5472 _("Beta III"), # TOS: "The Return of the Archons"
5473 _("Triacus"), # TOS: "And the Children Shall Lead",
5474 _("Exo III"), # TOS: "What Are Little Girls Made Of?" (Class P)
5476 # _("Hansen's Planet"), # TOS: "The Galileo Seven"
5477 # _("Taurus IV"), # TOS: "The Galileo Seven" (class G)
5478 # _("Antos IV (Doraphane)"), # TOS: "Whom Gods Destroy", "Who Mourns for Adonais?"
5479 # _("Izar"), # TOS: "Whom Gods Destroy"
5480 # _("Tiburon"), # TOS: "The Way to Eden"
5481 # _("Merak II"), # TOS: "The Cloud Minders"
5482 # _("Coridan (Desotriana)"), # TOS: "Journey to Babel"
5483 # _("Iotia"), # TOS: "A Piece of the Action"
5487 _("S. R. Sensors"), \
5488 _("L. R. Sensors"), \
5490 _("Photon Tubes"), \
5491 _("Life Support"), \
5492 _("Warp Engines"), \
5493 _("Impulse Engines"), \
5495 _("Subspace Radio"), \
5496 _("Shuttle Craft"), \
5498 _("Navigation System"), \
5500 _("Shield Control"), \
5506 "Prepare to play, set up cosmos."
5508 # Decide how many of everything
5510 return # frozen game
5511 # Prepare the Enterprise
5512 game.alldone = game.gamewon = game.shldchg = game.shldup = False
5514 game.state.crew = FULLCREW
5515 game.energy = game.inenrg = 5000.0
5516 game.shield = game.inshld = 2500.0
5519 game.quadrant = randplace(GALSIZE)
5520 game.sector = randplace(QUADSIZE)
5521 game.torps = game.intorps = 10
5522 game.nprobes = randrange(2, 5)
5524 for i in range(NDEVICES):
5525 game.damage[i] = 0.0
5526 # Set up assorted game parameters
5527 game.battle = Coord()
5528 game.state.date = game.indate = 100.0 * randreal(20, 51)
5529 game.nkinks = game.nhelp = game.casual = game.abandoned = 0
5530 game.iscate = game.resting = game.imine = game.icrystl = game.icraft = False
5531 game.isatb = game.state.nplankl = 0
5532 game.state.starkl = game.state.basekl = game.state.nworldkl = 0
5533 game.iscraft = "onship"
5538 game.state.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
5540 game.state.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
5542 game.state.planets = [] # Planet information
5543 game.state.baseq = [] # Base quadrant coordinates
5544 game.state.kcmdr = [] # Commander quadrant coordinates
5545 game.statekscmdr = Coord() # Supercommander quadrant coordinates
5547 # Starchart is functional but we've never seen it
5548 game.lastchart = FOREVER
5549 # Put stars in the galaxy
5551 for i in range(GALSIZE):
5552 for j in range(GALSIZE):
5553 # Can't have more stars per quadrant than fit in one decimal digit,
5554 # if we do the chart representation will break.
5555 k = randrange(1, min(10, QUADSIZE**2/10))
5557 game.state.galaxy[i][j].stars = k
5558 # Locate star bases in galaxy
5560 prout("=== Allocating %d bases" % game.inbase)
5561 for i in range(game.inbase):
5564 w = randplace(GALSIZE)
5565 if not game.state.galaxy[w.i][w.j].starbase:
5568 # C version: for (j = i-1; j > 0; j--)
5569 # so it did them in the opposite order.
5570 for j in range(1, i):
5571 # Improved placement algorithm to spread out bases
5572 distq = (w - game.state.baseq[j]).distance()
5573 if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75):
5576 prout("=== Abandoning base #%d at %s" % (i, w))
5578 elif distq < 6.0 * (BASEMAX+1-game.inbase):
5580 prout("=== Saving base #%d, close to #%d" % (i, j))
5584 prout("=== Placing base #%d in quadrant %s" % (i, w))
5585 game.state.baseq.append(w)
5586 game.state.galaxy[w.i][w.j].starbase = game.state.chart[w.i][w.j].starbase = True
5587 # Position ordinary Klingon Battle Cruisers
5589 klumper = 0.25*game.skill*(9.0-game.length)+1.0
5590 if klumper > MAXKLQUAD:
5594 klump = (1.0 - r*r)*klumper
5599 w = randplace(GALSIZE)
5600 if not game.state.galaxy[w.i][w.j].supernova and \
5601 game.state.galaxy[w.i][w.j].klingons + klump <= MAXKLQUAD:
5603 game.state.galaxy[w.i][w.j].klingons += int(klump)
5606 # Position Klingon Commander Ships
5607 for i in range(game.incom):
5609 w = randplace(GALSIZE)
5610 if not welcoming(w) or w in game.state.kcmdr:
5612 if (game.state.galaxy[w.i][w.j].klingons or withprob(0.25)):
5614 game.state.galaxy[w.i][w.j].klingons += 1
5615 game.state.kcmdr.append(w)
5616 # Locate planets in galaxy
5617 for i in range(game.inplan):
5619 w = randplace(GALSIZE)
5620 if game.state.galaxy[w.i][w.j].planet is None:
5624 new.crystals = "absent"
5625 if (game.options & OPTION_WORLDS) and i < NINHAB:
5626 new.pclass = "M" # All inhabited planets are class M
5627 new.crystals = "absent"
5629 new.name = systnames[i]
5630 new.inhabited = True
5632 new.pclass = ("M", "N", "O")[randrange(0, 3)]
5634 new.crystals = "present"
5635 new.known = "unknown"
5636 new.inhabited = False
5637 game.state.galaxy[w.i][w.j].planet = new
5638 game.state.planets.append(new)
5640 for i in range(game.state.nromrem):
5641 w = randplace(GALSIZE)
5642 game.state.galaxy[w.i][w.j].romulans += 1
5643 # Place the Super-Commander if needed
5644 if game.state.nscrem > 0:
5646 w = randplace(GALSIZE)
5649 game.state.kscmdr = w
5650 game.state.galaxy[w.i][w.j].klingons += 1
5651 # Initialize times for extraneous events
5652 schedule(FSNOVA, expran(0.5 * game.intime))
5653 schedule(FTBEAM, expran(1.5 * (game.intime / len(game.state.kcmdr))))
5654 schedule(FSNAP, randreal(1.0, 2.0)) # Force an early snapshot
5655 schedule(FBATTAK, expran(0.3*game.intime))
5657 if game.state.nscrem:
5658 schedule(FSCMOVE, 0.2777)
5663 if (game.options & OPTION_WORLDS) and game.skill >= SKILL_GOOD:
5664 schedule(FDISTR, expran(1.0 + game.intime))
5669 # Place thing (in tournament game, we don't want one!)
5670 # New in SST2K: never place the Thing near a starbase.
5671 # This makes sense and avoids a special case in the old code.
5673 if game.tourn is None:
5675 thing = randplace(GALSIZE)
5676 if thing not in game.state.baseq:
5679 game.state.snap = False
5680 if game.skill == SKILL_NOVICE:
5681 prout(_("It is stardate %d. The Federation is being attacked by") % int(game.state.date))
5682 prout(_("a deadly Klingon invasion force. As captain of the United"))
5683 prout(_("Starship U.S.S. Enterprise, it is your mission to seek out"))
5684 prout(_("and destroy this invasion force of %d battle cruisers.") % ((game.inkling + game.incom + game.inscom)))
5685 prout(_("You have an initial allotment of %d stardates to complete") % int(game.intime))
5686 prout(_("your mission. As you proceed you may be given more time."))
5688 prout(_("You will have %d supporting starbases.") % (game.inbase))
5689 proutn(_("Starbase locations- "))
5691 prout(_("Stardate %d.") % int(game.state.date))
5693 prout(_("%d Klingons.") % (game.inkling + game.incom + game.inscom))
5694 prout(_("An unknown number of Romulans."))
5695 if game.state.nscrem:
5696 prout(_("And one (GULP) Super-Commander."))
5697 prout(_("%d stardates.") % int(game.intime))
5698 proutn(_("%d starbases in ") % game.inbase)
5699 for i in range(game.inbase):
5700 proutn(repr(game.state.baseq[i]))
5703 proutn(_("The Enterprise is currently in Quadrant %s") % game.quadrant)
5704 proutn(_(" Sector %s") % game.sector)
5706 prout(_("Good Luck!"))
5707 if game.state.nscrem:
5708 prout(_(" YOU'LL NEED IT."))
5711 setwnd(message_window)
5713 if len(game.enemies) - (thing == game.quadrant) - (game.tholian != None):
5715 if game.neutz: # bad luck to start in a Romulan Neutral Zone
5716 attack(torps_ok=False)
5719 "Choose your game type."
5721 game.tourn = game.length = 0
5723 game.skill = SKILL_NONE
5725 # if not scanner.inqueue: # Can start with command line options
5726 proutn(_("Would you like a regular, tournament, or saved game? "))
5728 if scanner.sees("tournament"):
5729 while scanner.nexttok() == "IHEOL":
5730 proutn(_("Type in tournament number-"))
5731 if scanner.real == 0:
5733 continue # We don't want a blank entry
5734 game.tourn = int(round(scanner.real))
5735 random.seed(scanner.real)
5737 logfp.write("# random.seed(%d)\n" % scanner.real)
5739 if scanner.sees("saved") or scanner.sees("frozen"):
5743 if game.passwd is None:
5745 if not game.alldone:
5746 game.thawed = True # No plaque if not finished
5750 if scanner.sees("regular"):
5752 proutn(_("What is \"%s\"? ") % scanner.token)
5754 while game.length==0 or game.skill==SKILL_NONE:
5755 if scanner.nexttok() == "IHALPHA":
5756 if scanner.sees("short"):
5758 elif scanner.sees("medium"):
5760 elif scanner.sees("long"):
5762 elif scanner.sees("novice"):
5763 game.skill = SKILL_NOVICE
5764 elif scanner.sees("fair"):
5765 game.skill = SKILL_FAIR
5766 elif scanner.sees("good"):
5767 game.skill = SKILL_GOOD
5768 elif scanner.sees("expert"):
5769 game.skill = SKILL_EXPERT
5770 elif scanner.sees("emeritus"):
5771 game.skill = SKILL_EMERITUS
5773 proutn(_("What is \""))
5774 proutn(scanner.token)
5779 proutn(_("Would you like a Short, Medium, or Long game? "))
5780 elif game.skill == SKILL_NONE:
5781 proutn(_("Are you a Novice, Fair, Good, Expert, or Emeritus player? "))
5782 # Choose game options -- added by ESR for SST2K
5783 if scanner.nexttok() != "IHALPHA":
5785 proutn(_("Choose your game style (plain, almy, fancy or just press enter): "))
5787 if scanner.sees("plain"):
5788 # Approximates the UT FORTRAN version.
5789 game.options &=~ (OPTION_THOLIAN | OPTION_PLANETS | OPTION_THINGY | OPTION_PROBE | OPTION_RAMMING | OPTION_MVBADDY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS | OPTION_COLOR | OPTION_CAPTURE)
5790 game.options |= OPTION_PLAIN
5791 elif scanner.sees("almy"):
5792 # Approximates Tom Almy's version.
5793 game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS | OPTION_COLOR)
5794 game.options |= OPTION_ALMY
5795 elif scanner.sees("fancy") or scanner.sees("\n"):
5797 elif len(scanner.token):
5798 proutn(_("What is \"%s\"?") % scanner.token)
5800 if game.passwd == "debug":
5802 prout("=== Debug mode enabled.")
5803 # Use parameters to generate initial values of things
5804 game.damfac = 0.5 * game.skill
5805 game.inbase = randrange(BASEMIN, BASEMAX+1)
5807 if game.options & OPTION_PLANETS:
5808 game.inplan += randrange(MAXUNINHAB/2, MAXUNINHAB+1)
5809 if game.options & OPTION_WORLDS:
5810 game.inplan += int(NINHAB)
5811 game.state.nromrem = game.inrom = randrange(2 *game.skill)
5812 game.state.nscrem = game.inscom = (game.skill > SKILL_FAIR)
5813 game.state.remtime = 7.0 * game.length
5814 game.intime = game.state.remtime
5815 game.state.remkl = game.inkling = 2.0*game.intime*((game.skill+1 - 2*randreal())*game.skill*0.1+.15)
5816 game.incom = min(MINCMDR, int(game.skill + 0.0625*game.inkling*randreal()))
5817 game.state.remres = (game.inkling+4*game.incom)*game.intime
5818 game.inresor = game.state.remres
5819 if game.inkling > 50:
5823 def dropin(iquad=None):
5824 "Drop a feature on a random dot in the current quadrant."
5826 w = randplace(QUADSIZE)
5827 if game.quad[w.i][w.j] == '.':
5829 if iquad is not None:
5830 game.quad[w.i][w.j] = iquad
5834 "Update our alert status."
5835 game.condition = "green"
5836 if game.energy < 1000.0:
5837 game.condition = "yellow"
5838 if game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons or game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans:
5839 game.condition = "red"
5841 game.condition="dead"
5844 "Drop new Klingon into current quadrant."
5845 return Enemy('K', loc=dropin(), power=randreal(300,450)+25.0*game.skill)
5848 "Sort enemies by distance so 'nearest' is meaningful."
5849 game.enemies.sort(key=lambda x: x.kdist)
5852 "Set up a new state of quadrant, for when we enter or re-enter it."
5855 game.neutz = game.inorbit = game.landed = False
5856 game.ientesc = game.iseenit = False
5857 # Create a blank quadrant
5858 game.quad = fill2d(QUADSIZE, lambda i, j: '.')
5860 # Attempt to escape Super-commander, so tbeam back!
5863 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
5864 # cope with supernova
5867 game.klhere = q.klingons
5868 game.irhere = q.romulans
5870 game.quad[game.sector.i][game.sector.j] = game.ship
5873 # Position ordinary Klingons
5874 for _i in range(game.klhere):
5876 # If we need a commander, promote a Klingon
5877 for cmdr in game.state.kcmdr:
5878 if cmdr == game.quadrant:
5879 e = game.enemies[game.klhere-1]
5880 game.quad[e.location.i][e.location.j] = 'C'
5881 e.power = randreal(950,1350) + 50.0*game.skill
5883 # If we need a super-commander, promote a Klingon
5884 if game.quadrant == game.state.kscmdr:
5886 game.quad[e.location.i][e.location.j] = 'S'
5887 e.power = randreal(1175.0, 1575.0) + 125.0*game.skill
5888 game.iscate = (game.state.remkl > 1)
5889 # Put in Romulans if needed
5890 for _i in range(q.romulans):
5891 Enemy('R', loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill)
5892 # If quadrant needs a starbase, put it in
5894 game.base = dropin('B')
5895 # If quadrant needs a planet, put it in
5897 game.iplnet = q.planet
5898 if not q.planet.inhabited:
5899 game.plnet = dropin('P')
5901 game.plnet = dropin('@')
5902 # Check for condition
5905 if game.irhere > 0 and game.klhere == 0:
5907 if not damaged(DRADIO):
5909 prout(_("LT. Uhura- \"Captain, an urgent message."))
5910 prout(_(" I'll put it on audio.\" CLICK"))
5912 prout(_("INTRUDER! YOU HAVE VIOLATED THE ROMULAN NEUTRAL ZONE."))
5913 prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!"))
5914 # Put in THING if needed
5915 if thing == game.quadrant:
5916 Enemy(etype='?', loc=dropin(),
5917 power=randreal(6000,6500.0)+250.0*game.skill)
5918 if not damaged(DSRSENS):
5920 prout(_("Mr. Spock- \"Captain, this is most unusual."))
5921 prout(_(" Please examine your short-range scan.\""))
5922 # Decide if quadrant needs a Tholian; lighten up if skill is low
5923 if game.options & OPTION_THOLIAN:
5924 if (game.skill < SKILL_GOOD and withprob(0.02)) or \
5925 (game.skill == SKILL_GOOD and withprob(0.05)) or \
5926 (game.skill > SKILL_GOOD and withprob(0.08)):
5929 w.i = withprob(0.5) * (QUADSIZE-1)
5930 w.j = withprob(0.5) * (QUADSIZE-1)
5931 if game.quad[w.i][w.j] == '.':
5933 game.tholian = Enemy(etype='T', loc=w,
5934 power=randrange(100, 500) + 25.0*game.skill)
5935 # Reserve unoccupied corners
5936 if game.quad[0][0]=='.':
5937 game.quad[0][0] = 'X'
5938 if game.quad[0][QUADSIZE-1]=='.':
5939 game.quad[0][QUADSIZE-1] = 'X'
5940 if game.quad[QUADSIZE-1][0]=='.':
5941 game.quad[QUADSIZE-1][0] = 'X'
5942 if game.quad[QUADSIZE-1][QUADSIZE-1]=='.':
5943 game.quad[QUADSIZE-1][QUADSIZE-1] = 'X'
5945 # And finally the stars
5946 for _i in range(q.stars):
5948 # Put in a few black holes
5949 for _i in range(1, 3+1):
5952 # Take out X's in corners if Tholian present
5954 if game.quad[0][0]=='X':
5955 game.quad[0][0] = '.'
5956 if game.quad[0][QUADSIZE-1]=='X':
5957 game.quad[0][QUADSIZE-1] = '.'
5958 if game.quad[QUADSIZE-1][0]=='X':
5959 game.quad[QUADSIZE-1][0] = '.'
5960 if game.quad[QUADSIZE-1][QUADSIZE-1]=='X':
5961 game.quad[QUADSIZE-1][QUADSIZE-1] = '.'
5964 "Set the self-destruct password."
5965 if game.options & OPTION_PLAIN:
5968 proutn(_("Please type in a secret password- "))
5970 game.passwd = scanner.token
5971 if game.passwd != None:
5975 game.passwd += chr(ord('a')+randrange(26))
5976 game.passwd += chr(ord('a')+randrange(26))
5977 game.passwd += chr(ord('a')+randrange(26))
5979 # Code from sst.c begins here
5982 ("SRSCAN", OPTION_TTY),
5983 ("STATUS", OPTION_TTY),
5984 ("REQUEST", OPTION_TTY),
5985 ("LRSCAN", OPTION_TTY),
5997 ("SENSORS", OPTION_PLANETS),
5998 ("ORBIT", OPTION_PLANETS),
5999 ("TRANSPORT", OPTION_PLANETS),
6000 ("MINE", OPTION_PLANETS),
6001 ("CRYSTALS", OPTION_PLANETS),
6002 ("SHUTTLE", OPTION_PLANETS),
6003 ("PLANETS", OPTION_PLANETS),
6008 ("PROBE", OPTION_PROBE),
6010 ("FREEZE", 0), # Synonym for SAVE
6014 ("CAPTURE", OPTION_CAPTURE),
6017 ("SOS", 0), # Synonym for MAYDAY
6018 ("CALL", 0), # Synonym for MAYDAY
6026 "Generate a list of legal commands."
6027 prout(_("LEGAL COMMANDS ARE:"))
6029 for (key, opt) in commands:
6030 if not opt or (opt & game.options):
6031 proutn("%-12s " % key)
6033 if emitted % 5 == 4:
6038 "Browse on-line help."
6039 key = scanner.nexttok()
6042 setwnd(prompt_window)
6043 proutn(_("Help on what command? "))
6044 key = scanner.nexttok()
6045 setwnd(message_window)
6048 cmds = [x[0] for x in commands]
6049 if scanner.token.upper() in cmds or scanner.token.upper() == "ABBREV":
6056 cmd = scanner.token.upper()
6057 for directory in docpath:
6059 fp = open(os.path.join(directory, "sst.doc"), "r")
6064 prout(_("Spock- \"Captain, that information is missing from the"))
6065 prout(_(" computer. You need to find sst.doc and put it somewhere"))
6066 proutn(_(" in these directories: %s") % ":".join(docpath))
6068 # This used to continue: "You need to find SST.DOC and put
6069 # it in the current directory."
6072 linebuf = fp.readline()
6074 prout(_("Spock- \"Captain, there is no information on that command.\""))
6077 if linebuf[0] == '%' and linebuf[1] == '%' and linebuf[2] == ' ':
6078 linebuf = linebuf[3:].strip()
6079 if cmd.upper() == linebuf:
6082 prout(_("Spock- \"Captain, I've found the following information:\""))
6085 linebuf = fp.readline()
6086 if "******" in linebuf:
6092 "Command-interpretation loop."
6093 while True: # command loop
6095 while True: # get a command
6097 game.optime = game.justin = False
6099 setwnd(prompt_window)
6102 if scanner.nexttok() == "IHEOL":
6103 if game.options & OPTION_CURSES:
6106 elif scanner.token == "":
6110 setwnd(message_window)
6112 abandon_passed = False
6113 cmd = "" # Force cmd to persist after loop
6114 opt = 0 # Force opt to persist after loop
6115 for (cmd, opt) in commands:
6116 # commands after ABANDON cannot be abbreviated
6117 if cmd == "ABANDON":
6118 abandon_passed = True
6119 if cmd == scanner.token.upper() or (not abandon_passed \
6120 and cmd.startswith(scanner.token.upper())):
6125 elif opt and not (opt & game.options):
6129 if cmd == "SRSCAN": # srscan
6131 elif cmd == "STATUS": # status
6133 elif cmd == "REQUEST": # status request
6135 elif cmd == "LRSCAN": # long range scan
6136 lrscan(silent=False)
6137 elif cmd == "PHASERS": # phasers
6141 elif cmd in ("TORPEDO", "PHOTONS"): # photon torpedos
6145 elif cmd == "MOVE": # move under warp
6146 warp(wcourse=None, involuntary=False)
6147 elif cmd == "SHIELDS": # shields
6148 doshield(shraise=False)
6151 game.shldchg = False
6152 elif cmd == "DOCK": # dock at starbase
6155 attack(torps_ok=False)
6156 elif cmd == "DAMAGES": # damage reports
6158 elif cmd == "CHART": # chart
6160 elif cmd == "IMPULSE": # impulse
6162 elif cmd == "REST": # rest
6166 elif cmd == "WARP": # warp
6168 elif cmd == "SENSORS": # sensors
6170 elif cmd == "ORBIT": # orbit
6174 elif cmd == "TRANSPORT": # transport "beam"
6176 elif cmd == "MINE": # mine
6180 elif cmd == "CRYSTALS": # crystals
6184 elif cmd == "SHUTTLE": # shuttle
6188 elif cmd == "PLANETS": # Planet list
6190 elif cmd == "REPORT": # Game Report
6192 elif cmd == "COMPUTER": # use COMPUTER!
6194 elif cmd == "COMMANDS":
6196 elif cmd == "EMEXIT": # Emergency exit
6197 clrscr() # Hide screen
6198 freeze(True) # forced save
6199 raise SystemExit(1) # And quick exit
6200 elif cmd == "PROBE":
6201 probe() # Launch probe
6204 elif cmd == "ABANDON": # Abandon Ship
6206 elif cmd == "DESTRUCT": # Self Destruct
6208 elif cmd == "SAVE": # Save Game
6211 if game.skill > SKILL_GOOD:
6212 prout(_("WARNING--Saved games produce no plaques!"))
6213 elif cmd == "DEATHRAY": # Try a desparation measure
6217 elif cmd == "CAPTURE":
6219 elif cmd == "DEBUGCMD": # What do we want for debug???
6221 elif cmd == "MAYDAY": # Call for help
6226 game.alldone = True # quit the game
6229 elif cmd == "SCORE":
6230 score() # see current score
6233 break # Game has ended
6234 if game.optime != 0.0:
6237 break # Events did us in
6238 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6241 if hitme and not game.justin:
6242 attack(torps_ok=True)
6245 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6256 "Emit the name of an enemy or feature."
6257 if ch == 'R': s = _("Romulan")
6258 elif ch == 'K': s = _("Klingon")
6259 elif ch == 'C': s = _("Commander")
6260 elif ch == 'S': s = _("Super-commander")
6261 elif ch == '*': s = _("Star")
6262 elif ch == 'P': s = _("Planet")
6263 elif ch == 'B': s = _("Starbase")
6264 elif ch == ' ': s = _("Black hole")
6265 elif ch == 'T': s = _("Tholian")
6266 elif ch == '#': s = _("Tholian web")
6267 elif ch == '?': s = _("Stranger")
6268 elif ch == '@': s = _("Inhabited World")
6269 else: s = "Unknown??"
6272 def crmena(loud, enemy, loctype, w):
6273 "Emit the name of an enemy and his location."
6277 buf += cramen(enemy) + _(" at ")
6278 if loctype == "quadrant":
6279 buf += _("Quadrant ")
6280 elif loctype == "sector":
6282 return buf + repr(w)
6285 "Emit our ship name."
6286 return{'E':_("Enterprise"),'F':_("Faerie Queene")}.get(game.ship,"Ship???")
6289 "Emit a line of stars"
6290 prouts("******************************************************")
6294 return -avrage*math.log(1e-7 + randreal())
6296 def randplace(size):
6297 "Choose a random location."
6299 w.i = randrange(size)
6300 w.j = randrange(size)
6310 # Get a token from the user
6313 # Fill the token quue if nothing here
6314 while not self.inqueue:
6316 if curwnd==prompt_window:
6318 setwnd(message_window)
6325 self.inqueue = sline.lstrip().split() + ["\n"]
6326 # From here on in it's all looking at the queue
6327 self.token = self.inqueue.pop(0)
6328 if self.token == "\n":
6332 self.real = float(self.token)
6333 self.type = "IHREAL"
6338 self.token = self.token.lower()
6339 self.type = "IHALPHA"
6342 def append(self, tok):
6343 self.inqueue.append(tok)
6344 def push(self, tok):
6345 self.inqueue.insert(0, tok)
6349 # Demand input for next scan
6351 self.real = self.token = None
6353 # compares s to item and returns true if it matches to the length of s
6354 return s.startswith(self.token)
6356 # Round token value to nearest integer
6357 return int(round(self.real))
6361 if self.type != "IHREAL":
6366 if self.type != "IHREAL":
6372 return "<sstcanner: token=%s, type=%s, queue=%s>" % (self.token, self.type, self.inqueue)
6375 "Yes-or-no confirmation."
6379 if scanner.token == 'y':
6381 if scanner.token == 'n':
6384 proutn(_("Please answer with \"y\" or \"n\": "))
6387 "Complain about unparseable input."
6390 prout(_("Beg your pardon, Captain?"))
6393 "Access to the internals for debugging."
6394 proutn("Reset levels? ")
6396 if game.energy < game.inenrg:
6397 game.energy = game.inenrg
6398 game.shield = game.inshld
6399 game.torps = game.intorps
6400 game.lsupres = game.inlsr
6401 proutn("Reset damage? ")
6403 for i in range(NDEVICES):
6404 if game.damage[i] > 0.0:
6405 game.damage[i] = 0.0
6406 proutn("Toggle debug flag? ")
6408 game.idebug = not game.idebug
6410 prout("Debug output ON")
6412 prout("Debug output OFF")
6413 proutn("Cause selective damage? ")
6415 for i in range(NDEVICES):
6416 proutn("Kill %s?" % device[i])
6418 key = scanner.nexttok()
6419 if key == "IHALPHA" and scanner.sees("y"):
6420 game.damage[i] = 10.0
6421 proutn("Examine/change events? ")
6426 FSNOVA: "Supernova ",
6429 FBATTAK: "Base Attack ",
6430 FCDBAS: "Base Destroy ",
6431 FSCMOVE: "SC Move ",
6432 FSCDBAS: "SC Base Destroy ",
6433 FDSPROB: "Probe Move ",
6434 FDISTR: "Distress Call ",
6435 FENSLV: "Enslavement ",
6436 FREPRO: "Klingon Build ",
6438 for i in range(1, NEVENTS):
6441 proutn("%.2f" % (scheduled(i)-game.state.date))
6442 if i == FENSLV or i == FREPRO:
6444 proutn(" in %s" % ev.quadrant)
6449 key = scanner.nexttok()
6453 elif key == "IHREAL":
6454 ev = schedule(i, scanner.real)
6455 if i == FENSLV or i == FREPRO:
6457 proutn("In quadrant- ")
6458 key = scanner.nexttok()
6459 # "IHEOL" says to leave coordinates as they are
6462 prout("Event %d canceled, no x coordinate." % (i))
6465 w.i = int(round(scanner.real))
6466 key = scanner.nexttok()
6468 prout("Event %d canceled, no y coordinate." % (i))
6471 w.j = int(round(scanner.real))
6474 proutn("Induce supernova here? ")
6476 game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova = True
6479 if __name__ == '__main__':
6481 #global line, thing, game
6485 game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY)
6486 if os.getenv("TERM"):
6487 game.options |= OPTION_CURSES
6489 game.options |= OPTION_TTY
6490 seed = int(time.time())
6491 (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:txV")
6493 for (switch, val) in options:
6496 replayfp = open(val, "r")
6498 sys.stderr.write("sst: can't open replay file %s\n" % val)
6501 line = replayfp.readline().strip()
6502 (leader, __, seed) = line.split()
6504 sys.stderr.write("sst2k: seed set to %s\n" % seed)
6505 line = replayfp.readline().strip()
6506 arguments += line.split()[2:]
6509 sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
6511 game.options |= OPTION_TTY
6512 game.options &=~ OPTION_CURSES
6513 elif switch == '-s':
6515 elif switch == '-t':
6516 game.options |= OPTION_TTY
6517 game.options &=~ OPTION_CURSES
6518 elif switch == '-x':
6520 elif switch == '-V':
6521 print("SST2K", version)
6524 sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n")
6526 # where to save the input in case of bugs
6527 if "TMPDIR" in os.environ:
6528 tmpdir = os.environ['TMPDIR']
6532 logfp = open(os.path.join(tmpdir, "sst-input.log"), "w")
6534 sys.stderr.write("sst: warning, can't open logfile\n")
6537 logfp.write("# seed %s\n" % seed)
6538 logfp.write("# options %s\n" % " ".join(arguments))
6539 logfp.write("# SST2K version %s\n" % version)
6540 logfp.write("# recorded by %s@%s on %s\n" % \
6541 (getpass.getuser(),socket.gethostname(),time.ctime()))
6543 scanner = sstscanner()
6544 for arg in arguments:
6548 while True: # Play a game
6549 setwnd(fullscreen_window)
6555 game.alldone = False
6563 if game.tourn and game.alldone:
6564 proutn(_("Do you want your score recorded?"))
6570 proutn(_("Do you want to play again? "))
6574 prout(_("May the Great Bird of the Galaxy roost upon your home planet."))
6578 except KeyboardInterrupt: