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
46 ALGERON = 2311 # Date of the Treaty of Algeron
67 class TrekError(Exception):
70 class JumpOut(Exception):
74 def __init__(self, x=None, y=None):
77 def valid_quadrant(self):
78 return self.i >= 0 and self.i < GALSIZE and self.j >= 0 and self.j < GALSIZE
79 def valid_sector(self):
80 return self.i >= 0 and self.i < QUADSIZE and self.j >= 0 and self.j < QUADSIZE
82 self.i = self.j = None
84 return self.i != None and self.j != None
85 def __eq__(self, other):
86 return other != None and self.i == other.i and self.j == other.j
87 def __ne__(self, other):
88 return other is None or self.i != other.i or self.j != other.j
89 def __add__(self, other):
90 return Coord(self.i+other.i, self.j+other.j)
91 def __sub__(self, other):
92 return Coord(self.i-other.i, self.j-other.j)
93 def __mul__(self, other):
94 return Coord(self.i*other, self.j*other)
95 def __rmul__(self, other):
96 return Coord(self.i*other, self.j*other)
97 def __div__(self, other):
98 return Coord(self.i/other, self.j/other)
99 def __mod__(self, other):
100 return Coord(self.i % other, self.j % other)
101 def __rdiv__(self, other):
102 return Coord(self.i/other, self.j/other)
103 def roundtogrid(self):
104 return Coord(int(round(self.i)), int(round(self.j)))
105 def distance(self, other=None):
108 return math.sqrt((self.i - other.i)**2 + (self.j - other.j)**2)
110 return 1.90985*math.atan2(self.j, self.i)
116 s.i = self.i / abs(self.i)
120 s.j = self.j / abs(self.j)
123 #print "Location %s -> %s" % (self, (self / QUADSIZE).roundtogrid())
124 return self.roundtogrid() / QUADSIZE
126 return self.roundtogrid() % QUADSIZE
129 s.i = self.i + randrange(-1, 2)
130 s.j = self.j + randrange(-1, 2)
133 if self.i is None or self.j is None:
135 return "%s - %s" % (self.i+1, self.j+1)
139 "Do not anger the Space Thingy!"
146 return (q.i, q.j) == (self.i, self.j)
150 self.name = None # string-valued if inhabited
151 self.quadrant = Coord() # quadrant located
152 self.pclass = None # could be ""M", "N", "O", or "destroyed"
153 self.crystals = "absent"# could be "mined", "present", "absent"
154 self.known = "unknown" # could be "unknown", "known", "shuttle_down"
155 self.inhabited = False # is it inhabited?
163 self.starbase = False
166 self.supernova = False
168 self.status = "secure" # Could be "secure", "distressed", "enslaved"
173 self.starbase = False
176 return "<%s,%s,%s>" % (self.klingons, self.starbase, self.stars)
178 def fill2d(size, fillfun):
179 "Fill an empty list in 2D."
181 for i in range(size):
183 for j in range(size):
184 lst[i].append(fillfun(i, j))
189 self.snap = False # snapshot taken
190 self.crew = 0 # crew complement
191 self.remkl = 0 # remaining klingons
192 self.nscrem = 0 # remaining super commanders
193 self.starkl = 0 # destroyed stars
194 self.basekl = 0 # destroyed bases
195 self.nromrem = 0 # Romulans remaining
196 self.nplankl = 0 # destroyed uninhabited planets
197 self.nworldkl = 0 # destroyed inhabited planets
198 self.planets = [] # Planet information
199 self.date = 0.0 # stardate
200 self.remres = 0 # remaining resources
201 self.remtime = 0 # remaining time
202 self.baseq = [] # Base quadrant coordinates
203 self.kcmdr = [] # Commander quadrant coordinates
204 self.kscmdr = Coord() # Supercommander quadrant coordinates
206 self.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
208 self.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
212 self.date = None # A real number
213 self.quadrant = None # A coord structure
216 OPTION_ALL = 0xffffffff
217 OPTION_TTY = 0x00000001 # old interface
218 OPTION_CURSES = 0x00000002 # new interface
219 OPTION_IOMODES = 0x00000003 # cover both interfaces
220 OPTION_PLANETS = 0x00000004 # planets and mining
221 OPTION_THOLIAN = 0x00000008 # Tholians and their webs (UT 1979 version)
222 OPTION_THINGY = 0x00000010 # Space Thingy can shoot back (Stas, 2005)
223 OPTION_PROBE = 0x00000020 # deep-space probes (DECUS version, 1980)
224 OPTION_SHOWME = 0x00000040 # bracket Enterprise in chart
225 OPTION_RAMMING = 0x00000080 # enemies may ram Enterprise (Almy)
226 OPTION_MVBADDY = 0x00000100 # more enemies can move (Almy)
227 OPTION_BLKHOLE = 0x00000200 # black hole may timewarp you (Stas, 2005)
228 OPTION_BASE = 0x00000400 # bases have good shields (Stas, 2005)
229 OPTION_WORLDS = 0x00000800 # logic for inhabited worlds (ESR, 2006)
230 OPTION_AUTOSCAN = 0x00001000 # automatic LRSCAN before CHART (ESR, 2006)
231 OPTION_CAPTURE = 0x00002000 # Enable BSD-Trek capture (Almy, 2013).
232 OPTION_CLOAK = 0x80004000 # Enable BSD-Trek capture (Almy, 2013).
233 OPTION_PLAIN = 0x01000000 # user chose plain game
234 OPTION_ALMY = 0x02000000 # user chose Almy variant
235 OPTION_COLOR = 0x04000000 # enable color display (ESR, 2010)
255 NDEVICES = 17 # Number of devices
265 return (game.damage[dev] != 0.0)
267 return not damaged(DRADIO) or game.condition=="docked"
269 # Define future events
270 FSPY = 0 # Spy event happens always (no future[] entry)
271 # can cause SC to tractor beam Enterprise
272 FSNOVA = 1 # Supernova
273 FTBEAM = 2 # Commander tractor beams Enterprise
274 FSNAP = 3 # Snapshot for time warp
275 FBATTAK = 4 # Commander attacks base
276 FCDBAS = 5 # Commander destroys base
277 FSCMOVE = 6 # Supercommander moves (might attack base)
278 FSCDBAS = 7 # Supercommander destroys base
279 FDSPROB = 8 # Move deep space probe
280 FDISTR = 9 # Emit distress call from an inhabited world
281 FENSLV = 10 # Inhabited word is enslaved */
282 FREPRO = 11 # Klingons build a ship in an enslaved system
285 # Abstract out the event handling -- underlying data structures will change
286 # when we implement stateful events
287 def findevent(evtype):
288 return game.future[evtype]
291 def __init__(self, etype=None, loc=None, power=None):
293 self.location = Coord()
298 self.power = power # enemy energy level
299 game.enemies.append(self)
301 motion = (loc != self.location)
302 if self.location.i is not None and self.location.j is not None:
305 game.quad[self.location.i][self.location.j] = '#'
307 game.quad[self.location.i][self.location.j] = '.'
309 self.location = copy.copy(loc)
310 game.quad[self.location.i][self.location.j] = self.type
311 self.kdist = self.kavgd = (game.sector - loc).distance()
313 self.location = Coord()
314 self.kdist = self.kavgd = None
315 game.enemies.remove(self)
318 return "<%s,%s.%f>" % (self.type, self.location, self.power) # For debugging
322 self.options = None # Game options
323 self.state = Snapshot() # A snapshot structure
324 self.snapsht = Snapshot() # Last snapshot taken for time-travel purposes
325 self.quad = None # contents of our quadrant
326 self.damage = [0.0] * NDEVICES # damage encountered
327 self.future = [] # future events
331 self.future.append(Event())
332 self.passwd = None # Self Destruct password
334 self.quadrant = None # where we are in the large
335 self.sector = None # where we are in the small
336 self.tholian = None # Tholian enemy object
337 self.base = None # position of base in current quadrant
338 self.battle = None # base coordinates being attacked
339 self.plnet = None # location of planet in quadrant
340 self.gamewon = False # Finished!
341 self.ididit = False # action taken -- allows enemy to attack
342 self.alive = False # we are alive (not killed)
343 self.justin = False # just entered quadrant
344 self.shldup = False # shields are up
345 self.shldchg = False # shield is changing (affects efficiency)
346 self.iscate = False # super commander is here
347 self.ientesc = False # attempted escape from supercommander
348 self.resting = False # rest time
349 self.icraft = False # Kirk in Galileo
350 self.landed = False # party on planet (true), on ship (false)
351 self.alldone = False # game is now finished
352 self.neutz = False # Romulan Neutral Zone
353 self.isarmed = False # probe is armed
354 self.inorbit = False # orbiting a planet
355 self.imine = False # mining
356 self.icrystl = False # dilithium crystals aboard
357 self.iseenit = False # seen base attack report
358 self.thawed = False # thawed game
359 self.condition = None # "green", "yellow", "red", "docked", "dead"
360 self.iscraft = None # "onship", "offship", "removed"
361 self.skill = None # Player skill level
362 self.inkling = 0 # initial number of klingons
363 self.inbase = 0 # initial number of bases
364 self.incom = 0 # initial number of commanders
365 self.inscom = 0 # initial number of commanders
366 self.inrom = 0 # initial number of commanders
367 self.instar = 0 # initial stars
368 self.intorps = 0 # initial/max torpedoes
369 self.torps = 0 # number of torpedoes
370 self.ship = 0 # ship type -- 'E' is Enterprise
371 self.abandoned = 0 # count of crew abandoned in space
372 self.length = 0 # length of game
373 self.klhere = 0 # klingons here
374 self.casual = 0 # causalties
375 self.nhelp = 0 # calls for help
376 self.nkinks = 0 # count of energy-barrier crossings
377 self.iplnet = None # planet # in quadrant
378 self.inplan = 0 # initial planets
379 self.irhere = 0 # Romulans in quadrant
380 self.isatb = 0 # =2 if super commander is attacking base
381 self.tourn = None # tournament number
382 self.nprobes = 0 # number of probes available
383 self.inresor = 0.0 # initial resources
384 self.intime = 0.0 # initial time
385 self.inenrg = 0.0 # initial/max energy
386 self.inshld = 0.0 # initial/max shield
387 self.inlsr = 0.0 # initial life support resources
388 self.indate = 0.0 # initial date
389 self.energy = 0.0 # energy level
390 self.shield = 0.0 # shield level
391 self.warpfac = 0.0 # warp speed
392 self.lsupres = 0.0 # life support reserves
393 self.optime = 0.0 # time taken by current operation
394 self.damfac = 0.0 # damage factor
395 self.lastchart = 0.0 # time star chart was last updated
396 self.cryprob = 0.0 # probability that crystal will work
397 self.probe = None # object holding probe course info
398 self.height = 0.0 # height of orbit around planet
399 self.score = 0.0 # overall score
400 self.perdate = 0.0 # rate of kills
401 self.idebug = False # Debugging instrumentation enabled?
402 self.statekscmdr = None # No SuperCommander coordinates yet.
403 self.brigcapacity = 400 # Enterprise brig capacity
404 self.brigfree = 400 # How many klingons can we put in the brig?
405 self.kcaptured = 0 # Total Klingons captured, for scoring.
406 self.iscloaked = False # Cloaking device on?
407 self.ncviol = 0 # Algreon treaty violations
408 self.isviolreported = False # We have been warned
410 # Stas thinks this should be (C expression):
411 # game.state.remkl + len(game.state.kcmdr) > 0 ?
412 # game.state.remres/(game.state.remkl + 4*len(game.state.kcmdr)) : 99
413 # He says the existing expression is prone to divide-by-zero errors
414 # after killing the last klingon when score is shown -- perhaps also
415 # if the only remaining klingon is SCOM.
416 self.state.remtime = self.state.remres/(self.state.remkl + 4*len(self.state.kcmdr))
443 return random.random() < p
445 def randrange(*args):
446 return random.randrange(*args)
451 v *= args[0] # from [0, args[0])
453 v = args[0] + v*(args[1]-args[0]) # from [args[0], args[1])
456 # Code from ai.c begins here
459 "Would this quadrant welcome another Klingon?"
460 return iq.valid_quadrant() and \
461 not game.state.galaxy[iq.i][iq.j].supernova and \
462 game.state.galaxy[iq.i][iq.j].klingons < MAXKLQUAD
464 def tryexit(enemy, look, irun):
465 "A bad guy attempts to bug out."
467 iq.i = game.quadrant.i+(look.i+(QUADSIZE-1))/QUADSIZE - 1
468 iq.j = game.quadrant.j+(look.j+(QUADSIZE-1))/QUADSIZE - 1
469 if not welcoming(iq):
471 if enemy.type == 'R':
472 return False # Romulans cannot escape!
474 # avoid intruding on another commander's territory
475 if enemy.type == 'C':
476 if iq in game.state.kcmdr:
478 # refuse to leave if currently attacking starbase
479 if game.battle == game.quadrant:
481 # don't leave if over 1000 units of energy
482 if enemy.power > 1000.0:
484 oldloc = copy.copy(enemy.location)
485 # handle local matters related to escape
488 if game.condition != "docked":
490 # Handle global matters related to escape
491 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
492 game.state.galaxy[iq.i][iq.j].klingons += 1
493 if enemy.type == 'S':
497 schedule(FSCMOVE, 0.2777)
499 game.state.kscmdr = iq
501 for cmdr in game.state.kcmdr:
502 if cmdr == game.quadrant:
503 game.state.kcmdr.append(iq)
505 # report move out of quadrant.
506 return [(True, enemy, oldloc, iq)]
508 # The bad-guy movement algorithm:
510 # 1. Enterprise has "force" based on condition of phaser and photon torpedoes.
511 # If both are operating full strength, force is 1000. If both are damaged,
512 # force is -1000. Having shields down subtracts an additional 1000.
514 # 2. Enemy has forces equal to the energy of the attacker plus
515 # 100*(K+R) + 500*(C+S) - 400 for novice through good levels OR
516 # 346*K + 400*R + 500*(C+S) - 400 for expert and emeritus.
518 # Attacker Initial energy levels (nominal):
519 # Klingon Romulan Commander Super-Commander
520 # Novice 400 700 1200
522 # Good 450 800 1300 1750
523 # Expert 475 850 1350 1875
524 # Emeritus 500 900 1400 2000
525 # VARIANCE 75 200 200 200
527 # Enemy vessels only move prior to their attack. In Novice - Good games
528 # only commanders move. In Expert games, all enemy vessels move if there
529 # is a commander present. In Emeritus games all enemy vessels move.
531 # 3. If Enterprise is not docked, an aggressive action is taken if enemy
532 # forces are 1000 greater than Enterprise.
534 # Agressive action on average cuts the distance between the ship and
535 # the enemy to 1/4 the original.
537 # 4. At lower energy advantage, movement units are proportional to the
538 # advantage with a 650 advantage being to hold ground, 800 to move forward
539 # 1, 950 for two, 150 for back 4, etc. Variance of 100.
541 # If docked, is reduced by roughly 1.75*game.skill, generally forcing a
542 # retreat, especially at high skill levels.
544 # 5. Motion is limited to skill level, except for SC hi-tailing it out.
546 def movebaddy(enemy):
547 "Tactical movement for the bad guys."
551 # This should probably be just (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
552 if game.skill >= SKILL_EXPERT:
553 nbaddys = (((game.quadrant in game.state.kcmdr)*2 + (game.state.kscmdr==game.quadrant)*2+game.klhere*1.23+game.irhere*1.5)/2.0)
555 nbaddys = (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
556 old_dist = enemy.kdist
557 mdist = int(old_dist + 0.5) # Nearest integer distance
558 # If SC, check with spy to see if should hi-tail it
559 if enemy.type == 'S' and \
560 (enemy.power <= 500.0 or (game.condition=="docked" and not damaged(DPHOTON))):
564 # decide whether to advance, retreat, or hold position
565 forces = enemy.power+100.0*len(game.enemies)+400*(nbaddys-1)
567 forces += 1000 # Good for enemy if shield is down!
568 if not damaged(DPHASER) or not damaged(DPHOTON):
569 if damaged(DPHASER): # phasers damaged
572 forces -= 0.2*(game.energy - 2500.0)
573 if damaged(DPHOTON): # photon torpedoes damaged
576 forces -= 50.0*game.torps
578 # phasers and photon tubes both out!
581 if forces <= 1000.0 and game.condition != "docked": # Typical situation
582 motion = ((forces + randreal(200))/150.0) - 5.0
584 if forces > 1000.0: # Very strong -- move in for kill
585 motion = (1.0 - randreal())**2 * old_dist + 1.0
586 if game.condition == "docked" and (game.options & OPTION_BASE): # protected by base -- back off !
587 motion -= game.skill*(2.0-randreal()**2)
589 proutn("=== MOTION = %d, FORCES = %1.2f, " % (motion, forces))
590 # don't move if no motion
593 # Limit motion according to skill
594 if abs(motion) > game.skill:
599 # calculate preferred number of steps
600 nsteps = abs(int(motion))
601 if motion > 0 and nsteps > mdist:
602 nsteps = mdist # don't overshoot
603 if nsteps > QUADSIZE:
604 nsteps = QUADSIZE # This shouldn't be necessary
606 nsteps = 1 # This shouldn't be necessary
608 proutn("NSTEPS = %d:" % nsteps)
609 # Compute preferred values of delta X and Y
610 m = game.sector - enemy.location
611 if 2.0 * abs(m.i) < abs(m.j):
613 if 2.0 * abs(m.j) < abs(game.sector.i-enemy.location.i):
615 m = (motion * m).sgn()
616 goto = enemy.location
618 for ll in range(nsteps):
620 proutn(" %d" % (ll+1))
621 # Check if preferred position available
632 attempts = 0 # Settle mysterious hang problem
633 while attempts < 20 and not success:
635 if look.i < 0 or look.i >= QUADSIZE:
637 return tryexit(enemy, look, irun)
638 if krawli == m.i or m.j == 0:
640 look.i = goto.i + krawli
642 elif look.j < 0 or look.j >= QUADSIZE:
644 return tryexit(enemy, look, irun)
645 if krawlj == m.j or m.i == 0:
647 look.j = goto.j + krawlj
649 elif (game.options & OPTION_RAMMING) and game.quad[look.i][look.j] != '.':
650 # See if enemy should ram ship
651 if game.quad[look.i][look.j] == game.ship and \
652 (enemy.type == 'C' or enemy.type == 'S'):
653 collision(rammed=True, enemy=enemy)
655 if krawli != m.i and m.j != 0:
656 look.i = goto.i + krawli
658 elif krawlj != m.j and m.i != 0:
659 look.j = goto.j + krawlj
662 break # we have failed
673 # Enemy moved, but is still in sector
674 return [(False, enemy, old_dist, goto)]
677 "Sequence Klingon tactical movement."
680 # Figure out which Klingon is the commander (or Supercommander)
683 if game.quadrant in game.state.kcmdr:
684 for enemy in game.enemies:
685 if enemy.type == 'C':
686 tacmoves += movebaddy(enemy)
687 if game.state.kscmdr == game.quadrant:
688 for enemy in game.enemies:
689 if enemy.type == 'S':
690 tacmoves += movebaddy(enemy)
692 # If skill level is high, move other Klingons and Romulans too!
693 # Move these last so they can base their actions on what the
695 if game.skill >= SKILL_EXPERT and (game.options & OPTION_MVBADDY):
696 for enemy in game.enemies:
697 if enemy.type in ('K', 'R'):
698 tacmoves += movebaddy(enemy)
701 def movescom(iq, avoid):
702 "Commander movement helper."
703 # Avoid quadrants with bases if we want to avoid Enterprise
704 if not welcoming(iq) or (avoid and iq in game.state.baseq):
706 if game.justin and not game.iscate:
709 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons -= 1
710 game.state.kscmdr = iq
711 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons += 1
712 if game.state.kscmdr == game.quadrant:
713 # SC has scooted, remove him from current quadrant
718 for enemy in game.enemies:
719 if enemy.type == 'S':
722 if game.condition != "docked":
725 # check for a helpful planet
726 for i in range(game.inplan):
727 if game.state.planets[i].quadrant == game.state.kscmdr and \
728 game.state.planets[i].crystals == "present":
730 game.state.planets[i].pclass = "destroyed"
731 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].planet = None
734 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
735 proutn(_(" a planet in Quadrant %s has been destroyed") % game.state.kscmdr)
736 prout(_(" by the Super-commander.\""))
738 return True # looks good!
740 def supercommander():
741 "Move the Super Commander."
748 prout("== SUPERCOMMANDER")
749 # Decide on being active or passive
750 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 \
751 (game.state.date-game.indate) < 3.0)
752 if not game.iscate and avoid:
753 # compute move away from Enterprise
754 idelta = game.state.kscmdr-game.quadrant
755 if idelta.distance() > 2.0:
757 idelta.i = game.state.kscmdr.j-game.quadrant.j
758 idelta.j = game.quadrant.i-game.state.kscmdr.i
760 # compute distances to starbases
761 if not game.state.baseq:
765 sc = game.state.kscmdr
766 for (i, base) in enumerate(game.state.baseq):
767 basetbl.append((i, (base - sc).distance()))
768 if game.state.baseq > 1:
769 basetbl.sort(key=lambda x: x[1])
770 # look for nearest base without a commander, no Enterprise, and
771 # without too many Klingons, and not already under attack.
772 ifindit = iwhichb = 0
773 for (i2, base) in enumerate(game.state.baseq):
774 i = basetbl[i2][0] # bug in original had it not finding nearest
775 if base == game.quadrant or base == game.battle or not welcoming(base):
777 # if there is a commander, and no other base is appropriate,
778 # we will take the one with the commander
779 for cmdr in game.state.kcmdr:
780 if base == cmdr and ifindit != 2:
784 else: # no commander -- use this one
789 return # Nothing suitable -- wait until next time
790 ibq = game.state.baseq[iwhichb]
791 # decide how to move toward base
792 idelta = ibq - game.state.kscmdr
793 # Maximum movement is 1 quadrant in either or both axes
794 idelta = idelta.sgn()
795 # try moving in both x and y directions
796 # there was what looked like a bug in the Almy C code here,
797 # but it might be this translation is just wrong.
798 iq = game.state.kscmdr + idelta
799 if not movescom(iq, avoid):
800 # failed -- try some other maneuvers
801 if idelta.i == 0 or idelta.j == 0:
804 iq.j = game.state.kscmdr.j + 1
805 if not movescom(iq, avoid):
806 iq.j = game.state.kscmdr.j - 1
809 iq.i = game.state.kscmdr.i + 1
810 if not movescom(iq, avoid):
811 iq.i = game.state.kscmdr.i - 1
814 # try moving just in x or y
815 iq.j = game.state.kscmdr.j
816 if not movescom(iq, avoid):
817 iq.j = game.state.kscmdr.j + idelta.j
818 iq.i = game.state.kscmdr.i
821 if len(game.state.baseq) == 0:
824 for ibq in game.state.baseq:
825 if ibq == game.state.kscmdr and game.state.kscmdr == game.battle:
828 return # no, don't attack base!
831 schedule(FSCDBAS, randreal(1.0, 3.0))
832 if is_scheduled(FCDBAS):
833 postpone(FSCDBAS, scheduled(FCDBAS)-game.state.date)
834 if not communicating():
838 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") \
840 prout(_(" reports that it is under attack from the Klingon Super-commander."))
841 proutn(_(" It can survive until stardate %d.\"") \
842 % int(scheduled(FSCDBAS)))
845 prout(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
849 game.optime = 0.0 # actually finished
851 # Check for intelligence report
852 if not game.idebug and \
854 (not communicating()) or \
855 not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].charted):
858 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
859 proutn(_(" the Super-commander is in Quadrant %s,") % game.state.kscmdr)
864 if not game.tholian or game.justin:
867 if game.tholian.location.i == 0 and game.tholian.location.j == 0:
870 elif game.tholian.location.i == 0 and game.tholian.location.j == QUADSIZE-1:
873 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == QUADSIZE-1:
876 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == 0:
880 # something is wrong!
881 game.tholian.move(None)
882 prout("***Internal error: Tholian in a bad spot.")
884 # do nothing if we are blocked
885 if game.quad[tid.i][tid.j] not in ('.', '#'):
887 here = copy.copy(game.tholian.location)
888 delta = (tid - game.tholian.location).sgn()
890 while here.i != tid.i:
892 if game.quad[here.i][here.j] == '.':
893 game.tholian.move(here)
895 while here.j != tid.j:
897 if game.quad[here.i][here.j] == '.':
898 game.tholian.move(here)
899 # check to see if all holes plugged
900 for i in range(QUADSIZE):
901 if game.quad[0][i] != '#' and game.quad[0][i] != 'T':
903 if game.quad[QUADSIZE-1][i] != '#' and game.quad[QUADSIZE-1][i] != 'T':
905 if game.quad[i][0] != '#' and game.quad[i][0] != 'T':
907 if game.quad[i][QUADSIZE-1] != '#' and game.quad[i][QUADSIZE-1] != 'T':
909 # All plugged up -- Tholian splits
910 game.quad[game.tholian.location.i][game.tholian.location.j] = '#'
912 prout(crmena(True, 'T', "sector", game.tholian) + _(" completes web."))
913 game.tholian.move(None)
916 # Code from battle.c begins here
919 "Change cloaking-device status."
921 prout(_("Ye Faerie Queene hath no cloaking device."));
924 key = scanner.nexttok()
931 if scanner.sees("on"):
933 prout(_("The cloaking device has already been switched on."))
936 elif scanner.sees("off"):
937 if not game.iscloaked:
938 prout(_("The cloaking device has already been switched off."))
945 if not game.iscloaked:
946 proutn(_("Switch cloaking device on?"))
951 proutn(_("Switch cloaking device off?"))
958 if action == "CLOFF":
959 if game.irhere and game.state.date >= ALGERON and not game.isviolreported:
960 prout(_("Spock- \"Captain, the Treaty of Algeron is in effect.\n Are you sure this is wise?\""))
963 prout("Engineer Scott- \"Aye, Sir.\"");
964 game.iscloaked = FALSE;
965 if game.irhere and game.state.date >= ALGERON and not game.isviolreported:
966 prout(_("The Romulan ship discovers you are breaking the Treaty of Algeron!"))
968 game.isviolreported = True
970 #if (neutz and game.state.date >= ALGERON) finish(FCLOAK);
975 prout(_("Engineer Scott- \"The cloaking device is damaged, Sir.\""))
978 if game.condition == "docked":
979 prout(_("You cannot cloak while docked."))
981 if game.state.date >= ALGERON and not game.isviolreported:
982 prout(_("Spock- \"Captain, using the cloaking device is be a violation"))
983 prout(_(" of the Treaty of Algeron. Considering the alternatives,"))
984 proutn(" are you sure this is wise?");
987 prout(_("Engineer Scott- \"Cloaking device has engaging, Sir...\""))
989 prout(_("Engineer Scott- \"Cloaking device has engaged, Sir.\""))
990 game.iscloaked = True
992 if game.irhere and game.state.date >= ALGERON and not game.isviolreported:
993 prout(_("The Romulan ship discovers you are breaking the Treaty of Algeron!"))
995 game.isviolreported = True
997 def doshield(shraise):
998 "Change shield status."
1004 key = scanner.nexttok()
1005 if key == "IHALPHA":
1006 if scanner.sees("transfer"):
1009 if damaged(DSHIELD):
1010 prout(_("Shields damaged and down."))
1012 if scanner.sees("up"):
1014 elif scanner.sees("down"):
1016 if action == "NONE":
1017 proutn(_("Do you wish to change shield energy? "))
1020 elif damaged(DSHIELD):
1021 prout(_("Shields damaged and down."))
1024 proutn(_("Shields are up. Do you want them down? "))
1031 proutn(_("Shields are down. Do you want them up? "))
1037 if action == "SHUP": # raise shields
1039 prout(_("Shields already up."))
1043 if game.condition != "docked":
1045 prout(_("Shields raised."))
1046 if game.energy <= 0:
1048 prout(_("Shields raising uses up last of energy."))
1053 elif action == "SHDN":
1055 prout(_("Shields already down."))
1059 prout(_("Shields lowered."))
1062 elif action == "NRG":
1063 while scanner.nexttok() != "IHREAL":
1065 proutn(_("Energy to transfer to shields- "))
1070 if nrg > game.energy:
1071 prout(_("Insufficient ship energy."))
1074 if game.shield+nrg >= game.inshld:
1075 prout(_("Shield energy maximized."))
1076 if game.shield+nrg > game.inshld:
1077 prout(_("Excess energy requested returned to ship energy"))
1078 game.energy -= game.inshld-game.shield
1079 game.shield = game.inshld
1081 if nrg < 0.0 and game.energy-nrg > game.inenrg:
1082 # Prevent shield drain loophole
1084 prout(_("Engineering to bridge--"))
1085 prout(_(" Scott here. Power circuit problem, Captain."))
1086 prout(_(" I can't drain the shields."))
1089 if game.shield+nrg < 0:
1090 prout(_("All shield energy transferred to ship."))
1091 game.energy += game.shield
1094 proutn(_("Scotty- \""))
1096 prout(_("Transferring energy to shields.\""))
1098 prout(_("Draining energy from shields.\""))
1104 "Choose a device to damage, at random."
1106 105, # DSRSENS: short range scanners 10.5%
1107 105, # DLRSENS: long range scanners 10.5%
1108 120, # DPHASER: phasers 12.0%
1109 120, # DPHOTON: photon torpedoes 12.0%
1110 25, # DLIFSUP: life support 2.5%
1111 65, # DWARPEN: warp drive 6.5%
1112 70, # DIMPULS: impulse engines 6.5%
1113 145, # DSHIELD: deflector shields 14.5%
1114 30, # DRADIO: subspace radio 3.0%
1115 45, # DSHUTTL: shuttle 4.5%
1116 15, # DCOMPTR: computer 1.5%
1117 20, # NAVCOMP: navigation system 2.0%
1118 75, # DTRANSP: transporter 7.5%
1119 20, # DSHCTRL: high-speed shield controller 2.0%
1120 10, # DDRAY: death ray 1.0%
1121 30, # DDSP: deep-space probes 3.0%
1122 0, # DCLOAK: the cloaking device 0.0
1124 assert(sum(weights) == 1000)
1125 idx = randrange(1000)
1127 for (i, w) in enumerate(weights):
1131 return None # we should never get here
1133 def collision(rammed, enemy):
1134 "Collision handling for rammong events."
1135 prouts(_("***RED ALERT! RED ALERT!"))
1137 prout(_("***COLLISION IMMINENT."))
1141 hardness = {'R':1.5, 'C':2.0, 'S':2.5, 'T':0.5, '?':4.0}.get(enemy.type, 1.0)
1143 proutn(_(" rammed by "))
1146 proutn(crmena(False, enemy.type, "sector", enemy.location))
1148 proutn(_(" (original position)"))
1150 deadkl(enemy.location, enemy.type, game.sector)
1151 proutn("***" + crmshp() + " heavily damaged.")
1152 icas = randrange(10, 30)
1153 prout(_("***Sickbay reports %d casualties") % icas)
1155 game.state.crew -= icas
1156 # In the pre-SST2K version, all devices got equiprobably damaged,
1157 # which was silly. Instead, pick up to half the devices at
1158 # random according to our weighting table,
1159 ncrits = randrange(NDEVICES/2)
1163 if game.damage[dev] < 0:
1165 extradm = (10.0*hardness*randreal()+1.0)*game.damfac
1166 # Damage for at least time of travel!
1167 game.damage[dev] += game.optime + extradm
1169 prout(_("***Shields are down."))
1170 if game.state.remkl + len(game.state.kcmdr) + game.state.nscrem:
1177 def torpedo(origin, bearing, dispersion, number, nburst):
1178 "Let a photon torpedo fly"
1179 if not damaged(DSRSENS) or game.condition == "docked":
1180 setwnd(srscan_window)
1182 setwnd(message_window)
1183 ac = bearing + 0.25*dispersion # dispersion is a random variable
1184 bullseye = (15.0 - bearing)*0.5235988
1185 track = course(bearing=ac, distance=QUADSIZE, origin=cartesian(origin))
1186 bumpto = Coord(0, 0)
1187 # Loop to move a single torpedo
1188 setwnd(message_window)
1189 for step in range(1, QUADSIZE*2):
1190 if not track.nexttok():
1193 if not w.valid_sector():
1195 iquad = game.quad[w.i][w.j]
1196 tracktorpedo(w, step, number, nburst, iquad)
1200 setwnd(message_window)
1201 if not damaged(DSRSENS) or game.condition == "docked":
1202 skip(1) # start new line after text track
1203 if iquad in ('E', 'F'): # Hit our ship
1205 prout(_("Torpedo hits %s.") % crmshp())
1206 hit = 700.0 + randreal(100) - \
1207 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1208 newcnd() # we're blown out of dock
1209 if game.landed or game.condition == "docked":
1210 return hit # Cheat if on a planet
1211 # In the C/FORTRAN version, dispersion was 2.5 radians, which
1212 # is 143 degrees, which is almost exactly 4.8 clockface units
1213 displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
1214 displacement.nexttok()
1215 bumpto = displacement.sector()
1216 if not bumpto.valid_sector():
1218 if game.quad[bumpto.i][bumpto.j] == ' ':
1221 if game.quad[bumpto.i][bumpto.j] != '.':
1222 # can't move into object
1224 game.sector = bumpto
1226 game.quad[w.i][w.j] = '.'
1227 game.quad[bumpto.i][bumpto.j] = iquad
1228 prout(_(" displaced by blast to Sector %s ") % bumpto)
1229 for enemy in game.enemies:
1230 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1233 elif iquad in ('C', 'S', 'R', 'K'): # Hit a regular enemy
1235 if iquad in ('C', 'S') and withprob(0.05):
1236 prout(crmena(True, iquad, "sector", w) + _(" uses anti-photon device;"))
1237 prout(_(" torpedo neutralized."))
1239 for enemy in game.enemies:
1240 if w == enemy.location:
1241 kp = math.fabs(enemy.power)
1242 h1 = 700.0 + randrange(100) - \
1243 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1251 if enemy.power == 0:
1254 proutn(crmena(True, iquad, "sector", w))
1255 displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
1256 displacement.nexttok()
1257 bumpto = displacement.sector()
1258 if not bumpto.valid_sector():
1259 prout(_(" damaged but not destroyed."))
1261 if game.quad[bumpto.i][bumpto.j] == ' ':
1262 prout(_(" buffeted into black hole."))
1263 deadkl(w, iquad, bumpto)
1264 if game.quad[bumpto.i][bumpto.j] != '.':
1265 prout(_(" damaged but not destroyed."))
1267 prout(_(" damaged-- displaced by blast to Sector %s ")%bumpto)
1268 enemy.location = bumpto
1269 game.quad[w.i][w.j] = '.'
1270 game.quad[bumpto.i][bumpto.j] = iquad
1271 for enemy in game.enemies:
1272 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1276 prout("Internal error, no enemy where expected!")
1279 elif iquad == 'B': # Hit a base
1281 prout(_("***STARBASE DESTROYED.."))
1282 game.state.baseq = [x for x in game.state.baseq if x != game.quadrant]
1283 game.quad[w.i][w.j] = '.'
1284 game.base.invalidate()
1285 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
1286 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = False
1287 game.state.basekl += 1
1290 elif iquad == 'P': # Hit a planet
1291 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1292 game.state.nplankl += 1
1293 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1294 game.iplnet.pclass = "destroyed"
1296 game.plnet.invalidate()
1297 game.quad[w.i][w.j] = '.'
1299 # captain perishes on planet
1302 elif iquad == '@': # Hit an inhabited world -- very bad!
1303 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1304 game.state.nworldkl += 1
1305 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1306 game.iplnet.pclass = "destroyed"
1308 game.plnet.invalidate()
1309 game.quad[w.i][w.j] = '.'
1311 # captain perishes on planet
1313 prout(_("The torpedo destroyed an inhabited planet."))
1315 elif iquad == '*': # Hit a star
1319 prout(crmena(True, '*', "sector", w) + _(" unaffected by photon blast."))
1321 elif iquad == '?': # Hit a thingy
1322 if not (game.options & OPTION_THINGY) or withprob(0.3):
1324 prouts(_("AAAAIIIIEEEEEEEEAAAAAAAAUUUUUGGGGGHHHHHHHHHHHH!!!"))
1326 prouts(_(" HACK! HACK! HACK! *CHOKE!* "))
1328 proutn(_("Mr. Spock-"))
1329 prouts(_(" \"Fascinating!\""))
1333 # Stas Sergeev added the possibility that
1334 # you can shove the Thingy and piss it off.
1335 # It then becomes an enemy and may fire at you.
1338 elif iquad == ' ': # Black hole
1340 prout(crmena(True, ' ', "sector", w) + _(" swallows torpedo."))
1342 elif iquad == '#': # hit the web
1344 prout(_("***Torpedo absorbed by Tholian web."))
1346 elif iquad == 'T': # Hit a Tholian
1347 h1 = 700.0 + randrange(100) - \
1348 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1351 game.quad[w.i][w.j] = '.'
1356 proutn(crmena(True, 'T', "sector", w))
1358 prout(_(" survives photon blast."))
1360 prout(_(" disappears."))
1361 game.tholian.move(None)
1362 game.quad[w.i][w.j] = '#'
1367 proutn("Don't know how to handle torpedo collision with ")
1368 proutn(crmena(True, iquad, "sector", w))
1373 setwnd(message_window)
1374 prout(_("Torpedo missed."))
1378 "Critical-hit resolution."
1379 if hit < (275.0-25.0*game.skill)*randreal(1.0, 1.5):
1381 ncrit = int(1.0 + hit/(500.0+randreal(100)))
1382 proutn(_("***CRITICAL HIT--"))
1383 # Select devices and cause damage
1388 # Cheat to prevent shuttle damage unless on ship
1389 if not (game.damage[j]<0.0 or (j == DSHUTTL and game.iscraft != "onship") or (j == DCLOAK and game.ship != 'E' or j == DDRAY)):
1392 extradm = (hit*game.damfac)/(ncrit*randreal(75, 100))
1393 game.damage[j] += extradm
1396 for (i, j) in enumerate(cdam):
1398 if skipcount % 3 == 2 and i < len(cdam)-1:
1403 prout(_(" damaged."))
1404 if damaged(DSHIELD) and game.shldup:
1405 prout(_("***Shields knocked down."))
1407 if damaged(DCLOAK) and game.iscloaked:
1408 prout(_("***Cloaking device rendered inoperative."))
1409 game.iscloaked = False
1411 def attack(torps_ok):
1412 # bad guy attacks us
1413 # torps_ok == False forces use of phasers in an attack
1416 # game could be over at this point, check
1426 prout("=== ATTACK!")
1427 # Tholian gets to move before attacking
1430 # if you have just entered the RNZ, you'll get a warning
1431 if game.neutz: # The one chance not to be attacked
1434 # commanders get a chance to tac-move towards you
1435 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:
1436 for (bugout, enemy, old, goto) in moveklings():
1438 # we know about this if either short or long range
1439 # sensors are working
1440 if damaged(DSRSENS) and damaged(DLRSENS) \
1441 and game.condition != "docked":
1442 prout(crmena(True, enemy.type, "sector", old) + \
1443 (_(" escapes to Quadrant %s (and regains strength).") % goto))
1444 else: # Enemy still in-sector
1445 if enemy.move(goto):
1446 if not damaged(DSRSENS) or game.condition == "docked":
1447 proutn(_("*** %s from Sector %s") % (cramen(enemy.type), enemy.location))
1448 if enemy.kdist < old:
1449 proutn(_(" advances to "))
1451 proutn(_(" retreats to "))
1452 prout("Sector %s." % goto)
1454 # if no enemies remain after movement, we're done
1455 if len(game.enemies) == 0 or (len(game.enemies) == 1 and thing.at(game.quadrant) and not thing.angered):
1457 # set up partial hits if attack happens during shield status change
1458 pfac = 1.0/game.inshld
1460 chgfac = 0.25 + randreal(0.5)
1462 # message verbosity control
1463 if game.skill <= SKILL_FAIR:
1465 for enemy in game.enemies:
1467 continue # too weak to attack
1468 # compute hit strength and diminish shield power
1470 # Increase chance of photon torpedos if docked or enemy energy is low
1471 if game.condition == "docked":
1473 if enemy.power < 500:
1475 if enemy.type == 'T' or (enemy.type == '?' and not thing.angered):
1477 # different enemies have different probabilities of throwing a torp
1478 usephasers = not torps_ok or \
1479 (enemy.type == 'K' and r > 0.0005) or \
1480 (enemy.type == 'C' and r > 0.015) or \
1481 (enemy.type == 'R' and r > 0.3) or \
1482 (enemy.type == 'S' and r > 0.07) or \
1483 (enemy.type == '?' and r > 0.05)
1484 if usephasers: # Enemy uses phasers
1485 if game.condition == "docked":
1486 continue # Don't waste the effort!
1487 attempt = True # Attempt to attack
1488 dustfac = randreal(0.8, 0.85)
1489 hit = enemy.power*math.pow(dustfac, enemy.kavgd)
1491 else: # Enemy uses photon torpedo
1492 # We should be able to make the bearing() method work here
1493 pcourse = 1.90985*math.atan2(game.sector.j-enemy.location.j, enemy.location.i-game.sector.i)
1495 proutn(_("***TORPEDO INCOMING"))
1496 if not damaged(DSRSENS):
1497 proutn(_(" From ") + crmena(False, enemy.type, where, enemy.location))
1500 dispersion = (randreal()+randreal())*0.5 - 0.5
1501 dispersion += 0.002*enemy.power*dispersion
1502 hit = torpedo(enemy.location, pcourse, dispersion, number=1, nburst=1)
1503 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
1504 finish(FWON) # Klingons did themselves in!
1505 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.alldone:
1506 return # Supernova or finished
1509 # incoming phaser or torpedo, shields may dissipate it
1510 if game.shldup or game.shldchg or game.condition == "docked":
1511 # shields will take hits
1512 propor = pfac * game.shield
1513 if game.condition == "docked":
1517 hitsh = propor*chgfac*hit+1.0
1519 if absorb > game.shield:
1520 absorb = game.shield
1521 game.shield -= absorb
1523 # taking a hit blasts us out of a starbase dock
1524 if game.condition == "docked":
1526 # but the shields may take care of it
1527 if propor > 0.1 and hit < 0.005*game.energy:
1529 # hit from this opponent got through shields, so take damage
1531 proutn(_("%d unit hit") % int(hit))
1532 if (damaged(DSRSENS) and usephasers) or game.skill<=SKILL_FAIR:
1533 proutn(_(" on the ") + crmshp())
1534 if not damaged(DSRSENS) and usephasers:
1535 prout(_(" from ") + crmena(False, enemy.type, where, enemy.location))
1537 # Decide if hit is critical
1543 if game.energy <= 0:
1544 # Returning home upon your shield, not with it...
1547 if not attempt and game.condition == "docked":
1548 prout(_("***Enemies decide against attacking your ship."))
1549 percent = 100.0*pfac*game.shield+0.5
1551 # Shields fully protect ship
1552 proutn(_("Enemy attack reduces shield strength to "))
1554 # Emit message if starship suffered hit(s)
1556 proutn(_("Energy left %2d shields ") % int(game.energy))
1559 elif not damaged(DSHIELD):
1562 proutn(_("damaged, "))
1563 prout(_("%d%%, torpedoes left %d") % (percent, game.torps))
1564 # Check if anyone was hurt
1565 if hitmax >= 200 or hittot >= 500:
1566 icas = randrange(int(hittot * 0.015))
1569 prout(_("Mc Coy- \"Sickbay to bridge. We suffered %d casualties") % icas)
1570 prout(_(" in that last attack.\""))
1572 game.state.crew -= icas
1573 # After attack, reset average distance to enemies
1574 for enemy in game.enemies:
1575 enemy.kavgd = enemy.kdist
1579 def deadkl(w, etype, mv):
1580 "Kill a Klingon, Tholian, Romulan, or Thingy."
1581 # Added mv to allow enemy to "move" before dying
1582 proutn(crmena(True, etype, "sector", mv))
1583 # Decide what kind of enemy it is and update appropriately
1585 # Chalk up a Romulan
1586 game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans -= 1
1588 game.state.nromrem -= 1
1597 # Killed some type of Klingon
1598 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
1601 game.state.kcmdr.remove(game.quadrant)
1603 if game.state.kcmdr:
1604 schedule(FTBEAM, expran(1.0*game.incom/len(game.state.kcmdr)))
1605 if is_scheduled(FCDBAS) and game.battle == game.quadrant:
1608 game.state.remkl -= 1
1610 game.state.nscrem -= 1
1611 game.state.kscmdr.invalidate()
1616 # For each kind of enemy, finish message to player
1617 prout(_(" destroyed."))
1618 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
1621 # Remove enemy ship from arrays describing local conditions
1622 for e in game.enemies:
1629 "Return None if target is invalid, otherwise return a course angle."
1630 if not w.valid_sector():
1634 # C code this was translated from is wacky -- why the sign reversal?
1635 delta.j = (w.j - game.sector.j)
1636 delta.i = (game.sector.i - w.i)
1637 if delta == Coord(0, 0):
1639 prout(_("Spock- \"Bridge to sickbay. Dr. McCoy,"))
1640 prout(_(" I recommend an immediate review of"))
1641 prout(_(" the Captain's psychological profile.\""))
1644 return delta.bearing()
1647 "Launch photon torpedo salvo."
1650 if damaged(DPHOTON):
1651 prout(_("Photon tubes damaged."))
1655 prout(_("No torpedoes left."))
1658 # First, get torpedo count
1661 if scanner.token == "IHALPHA":
1664 elif scanner.token == "IHEOL" or not scanner.waiting():
1665 prout(_("%d torpedoes left.") % game.torps)
1667 proutn(_("Number of torpedoes to fire- "))
1668 continue # Go back around to get a number
1669 else: # key == "IHREAL"
1671 if n <= 0: # abort command
1676 prout(_("Maximum of %d torpedoes per burst.") % MAXBURST)
1679 scanner.chew() # User requested more torps than available
1680 continue # Go back around
1681 break # All is good, go to next stage
1685 key = scanner.nexttok()
1686 if i == 0 and key == "IHEOL":
1687 break # no coordinate waiting, we will try prompting
1688 if i == 1 and key == "IHEOL":
1689 # direct all torpedoes at one target
1691 target.append(target[0])
1692 tcourse.append(tcourse[0])
1695 scanner.push(scanner.token)
1696 target.append(scanner.getcoord())
1697 if target[-1] is None:
1699 tcourse.append(targetcheck(target[-1]))
1700 if tcourse[-1] is None:
1703 if len(target) == 0:
1704 # prompt for each one
1706 proutn(_("Target sector for torpedo number %d- ") % (i+1))
1708 target.append(scanner.getcoord())
1709 if target[-1] is None:
1711 tcourse.append(targetcheck(target[-1]))
1712 if tcourse[-1] is None:
1715 # Loop for moving <n> torpedoes
1717 if game.condition != "docked":
1719 dispersion = (randreal()+randreal())*0.5 -0.5
1720 if math.fabs(dispersion) >= 0.47:
1722 dispersion *= randreal(1.2, 2.2)
1724 prouts(_("***TORPEDO NUMBER %d MISFIRES") % (i+1))
1726 prouts(_("***TORPEDO MISFIRES."))
1729 prout(_(" Remainder of burst aborted."))
1731 prout(_("***Photon tubes damaged by misfire."))
1732 game.damage[DPHOTON] = game.damfac * randreal(1.0, 3.0)
1736 elif game.shldup or game.condition == "docked":
1737 dispersion *= 1.0 + 0.0001*game.shield
1738 torpedo(game.sector, tcourse[i], dispersion, number=i, nburst=n)
1739 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
1741 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)<=0:
1745 "Check for phasers overheating."
1747 checkburn = (rpow-1500.0)*0.00038
1748 if withprob(checkburn):
1749 prout(_("Weapons officer Sulu- \"Phasers overheated, sir.\""))
1750 game.damage[DPHASER] = game.damfac* randreal(1.0, 2.0) * (1.0+checkburn)
1752 def checkshctrl(rpow):
1753 "Check shield control."
1756 prout(_("Shields lowered."))
1758 # Something bad has happened
1759 prouts(_("***RED ALERT! RED ALERT!"))
1761 hit = rpow*game.shield/game.inshld
1762 game.energy -= rpow+hit*0.8
1763 game.shield -= hit*0.2
1764 if game.energy <= 0.0:
1765 prouts(_("Sulu- \"Captain! Shield malf***********************\""))
1770 prouts(_("Sulu- \"Captain! Shield malfunction! Phaser fire contained!\""))
1772 prout(_("Lt. Uhura- \"Sir, all decks reporting damage.\""))
1773 icas = randrange(int(hit*0.012))
1778 prout(_("McCoy to bridge- \"Severe radiation burns, Jim."))
1779 prout(_(" %d casualties so far.\"") % icas)
1781 game.state.crew -= icas
1783 prout(_("Phaser energy dispersed by shields."))
1784 prout(_("Enemy unaffected."))
1789 "Register a phaser hit on Klingons and Romulans."
1796 dustfac = randreal(0.9, 1.0)
1797 hit = wham*math.pow(dustfac, game.enemies[kk].kdist)
1798 kpini = game.enemies[kk].power
1799 kp = math.fabs(kpini)
1800 if PHASEFAC*hit < kp:
1802 if game.enemies[kk].power < 0:
1803 game.enemies[kk].power -= -kp
1805 game.enemies[kk].power -= kp
1806 kpow = game.enemies[kk].power
1807 w = game.enemies[kk].location
1809 if not damaged(DSRSENS):
1811 proutn(_("%d unit hit on ") % int(hit))
1813 proutn(_("Very small hit on "))
1814 ienm = game.quad[w.i][w.j]
1817 proutn(crmena(False, ienm, "sector", w))
1821 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1825 kk -= 1 # don't do the increment
1827 else: # decide whether or not to emasculate klingon
1828 if kpow > 0 and withprob(0.9) and kpow <= randreal(0.4, 0.8)*kpini:
1829 prout(_("***Mr. Spock- \"Captain, the vessel at Sector %s")%w)
1830 prout(_(" has just lost its firepower.\""))
1831 game.enemies[kk].power = -kpow
1836 "Fire phasers at bad guys."
1840 irec = 0 # Cheating inhibitor
1849 # SR sensors and Computer are needed for automode
1850 if damaged(DSRSENS) or damaged(DCOMPTR):
1852 if game.condition == "docked":
1853 prout(_("Phasers can't be fired through base shields."))
1856 if damaged(DPHASER):
1857 prout(_("Phaser control damaged."))
1861 if damaged(DSHCTRL):
1862 prout(_("High speed shield control damaged."))
1865 if game.energy <= 200.0:
1866 prout(_("Insufficient energy to activate high-speed shield control."))
1869 prout(_("Weapons Officer Sulu- \"High-speed shield control enabled, sir.\""))
1871 # Original code so convoluted, I re-did it all
1872 # (That was Tom Almy talking about the C code, I think -- ESR)
1873 while automode == "NOTSET":
1874 key = scanner.nexttok()
1875 if key == "IHALPHA":
1876 if scanner.sees("manual"):
1877 if len(game.enemies)==0:
1878 prout(_("There is no enemy present to select."))
1881 automode = "AUTOMATIC"
1884 key = scanner.nexttok()
1885 elif scanner.sees("automatic"):
1886 if (not itarg) and len(game.enemies) != 0:
1887 automode = "FORCEMAN"
1889 if len(game.enemies)==0:
1890 prout(_("Energy will be expended into space."))
1891 automode = "AUTOMATIC"
1892 key = scanner.nexttok()
1893 elif scanner.sees("no"):
1898 elif key == "IHREAL":
1899 if len(game.enemies)==0:
1900 prout(_("Energy will be expended into space."))
1901 automode = "AUTOMATIC"
1903 automode = "FORCEMAN"
1905 automode = "AUTOMATIC"
1908 if len(game.enemies)==0:
1909 prout(_("Energy will be expended into space."))
1910 automode = "AUTOMATIC"
1912 automode = "FORCEMAN"
1914 proutn(_("Manual or automatic? "))
1919 if automode == "AUTOMATIC":
1920 if key == "IHALPHA" and scanner.sees("no"):
1922 key = scanner.nexttok()
1923 if key != "IHREAL" and len(game.enemies) != 0:
1924 prout(_("Phasers locked on target. Energy available: %.2f")%avail)
1929 for i in range(len(game.enemies)):
1930 irec += math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))*randreal(1.01, 1.06) + 1.0
1932 proutn(_("%d units required. ") % irec)
1934 proutn(_("Units to fire= "))
1935 key = scanner.nexttok()
1940 proutn(_("Energy available= %.2f") % avail)
1943 if not rpow > avail:
1949 key = scanner.nexttok()
1950 if key == "IHALPHA" and scanner.sees("no"):
1953 game.energy -= 200 # Go and do it!
1954 if checkshctrl(rpow):
1959 if len(game.enemies):
1962 for i in range(len(game.enemies)):
1966 hits[i] = math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))
1967 over = randreal(1.01, 1.06) * hits[i]
1969 powrem -= hits[i] + over
1970 if powrem <= 0 and temp < hits[i]:
1979 if extra > 0 and not game.alldone:
1981 proutn(_("*** Tholian web absorbs "))
1982 if len(game.enemies)>0:
1983 proutn(_("excess "))
1984 prout(_("phaser energy."))
1986 prout(_("%d expended on empty space.") % int(extra))
1987 elif automode == "FORCEMAN":
1990 if damaged(DCOMPTR):
1991 prout(_("Battle computer damaged, manual fire only."))
1994 prouts(_("---WORKING---"))
1996 prout(_("Short-range-sensors-damaged"))
1997 prout(_("Insufficient-data-for-automatic-phaser-fire"))
1998 prout(_("Manual-fire-must-be-used"))
2000 elif automode == "MANUAL":
2002 for k in range(len(game.enemies)):
2003 aim = game.enemies[k].location
2004 ienm = game.quad[aim.i][aim.j]
2006 proutn(_("Energy available= %.2f") % (avail-0.006))
2010 if damaged(DSRSENS) and \
2011 not game.sector.distance(aim)<2**0.5 and ienm in ('C', 'S'):
2012 prout(cramen(ienm) + _(" can't be located without short range scan."))
2015 hits[k] = 0 # prevent overflow -- thanks to Alexei Voitenko
2020 if itarg and k > kz:
2021 irec = (abs(game.enemies[k].power)/(PHASEFAC*math.pow(0.9, game.enemies[k].kdist))) * randreal(1.01, 1.06) + 1.0
2024 if not damaged(DCOMPTR):
2029 proutn(_("units to fire at %s- ") % crmena(False, ienm, "sector", aim))
2030 key = scanner.nexttok()
2031 if key == "IHALPHA" and scanner.sees("no"):
2033 key = scanner.nexttok()
2035 if key == "IHALPHA":
2039 if k == 1: # Let me say I'm baffled by this
2042 if scanner.real < 0:
2046 hits[k] = scanner.real
2047 rpow += scanner.real
2048 # If total requested is too much, inform and start over
2050 prout(_("Available energy exceeded -- try again."))
2053 key = scanner.nexttok() # scan for next value
2056 # zero energy -- abort
2059 if key == "IHALPHA" and scanner.sees("no"):
2064 game.energy -= 200.0
2065 if checkshctrl(rpow):
2069 # Say shield raised or malfunction, if necessary
2076 prout(_("Sulu- \"Sir, the high-speed shield control has malfunctioned . . ."))
2077 prouts(_(" CLICK CLICK POP . . ."))
2078 prout(_(" No response, sir!"))
2081 prout(_("Shields raised."))
2088 game.ididit = False # Nothing if we fail
2091 # Make sure there is room in the brig */
2092 if game.brigfree == 0:
2093 prout(_("Security reports the brig is already full."))
2097 prout(_("Uhura- \"We have no subspace radio communication, sir.\""))
2100 if damaged(DTRANSP):
2101 prout(_("Scotty- \"Transporter damaged, sir.\""))
2104 # find out if there are any at all
2106 prout(_("Uhura- \"Getting no response, sir.\""))
2109 # if there is more than one Klingon, find out which one */
2110 # Cruddy, just takes one at random. Should ask the captain.
2111 # Nah, just select the weakest one since it is most likely to
2112 # surrender (Tom Almy mod)
2113 klingons = [e for e in game.enemies if e.type == 'K']
2114 weakest = sorted(klingons, key=lambda e: e.power)
2115 game.optime = 0.05 # This action will take some time
2116 game.ididit = True # So any others can strike back
2118 # check out that Klingon
2119 # The algorithm isn't that great and could use some more
2120 # intelligent design
2121 # x = 300 + 25*skill;
2122 x = game.energy / (weakest.power * len(klingons))
2123 x *= 2.5; # would originally have been equivalent of 1.4,
2124 # but we want command to work more often, more humanely */
2125 #prout(_("Prob = %d (%.4f)\n", i, x))
2126 # x = 100; // For testing, of course!
2127 if x > randreal(100):
2128 # guess what, he surrendered!!! */
2129 prout(_("Klingon captain at %s surrenders.") % weakest.location)
2132 prout(_("%d Klingons commit suicide rather than be taken captive.") % 200 - i)
2134 prout(_("%d Klingons die because there is no room for them in the brig.") % i-brigfree)
2137 prout(_("%d captives taken") % i)
2138 deadkl(weakest.location, weakest.type, game.sector)
2139 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)<=0:
2143 # big surprise, he refuses to surrender */
2144 prout(_("Fat chance, captain!"))
2146 # Code from events.c begins here.
2148 # This isn't a real event queue a la BSD Trek yet -- you can only have one
2149 # event of each type active at any given time. Mostly these means we can
2150 # only have one FDISTR/FENSLV/FREPRO sequence going at any given time
2151 # BSD Trek, from which we swiped the idea, can have up to 5.
2153 def unschedule(evtype):
2154 "Remove an event from the schedule."
2155 game.future[evtype].date = FOREVER
2156 return game.future[evtype]
2158 def is_scheduled(evtype):
2159 "Is an event of specified type scheduled."
2160 return game.future[evtype].date != FOREVER
2162 def scheduled(evtype):
2163 "When will this event happen?"
2164 return game.future[evtype].date
2166 def schedule(evtype, offset):
2167 "Schedule an event of specified type."
2168 game.future[evtype].date = game.state.date + offset
2169 return game.future[evtype]
2171 def postpone(evtype, offset):
2172 "Postpone a scheduled event."
2173 game.future[evtype].date += offset
2176 "Rest period is interrupted by event."
2179 proutn(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
2181 game.resting = False
2187 "Run through the event queue looking for things to do."
2189 fintim = game.state.date + game.optime
2198 def tractorbeam(yank):
2199 "Tractor-beaming cases merge here."
2201 game.optime = (10.0/(7.5*7.5))*yank # 7.5 is yank rate (warp 7.5)
2203 prout("***" + crmshp() + _(" caught in long range tractor beam--"))
2204 # If Kirk & Co. screwing around on planet, handle
2205 atover(True) # atover(true) is Grab
2208 if game.icraft: # Caught in Galileo?
2211 # Check to see if shuttle is aboard
2212 if game.iscraft == "offship":
2215 prout(_("Galileo, left on the planet surface, is captured"))
2216 prout(_("by aliens and made into a flying McDonald's."))
2217 game.damage[DSHUTTL] = -10
2218 game.iscraft = "removed"
2220 prout(_("Galileo, left on the planet surface, is well hidden."))
2222 game.quadrant = game.state.kscmdr
2224 game.quadrant = game.state.kcmdr[i]
2225 game.sector = randplace(QUADSIZE)
2226 prout(crmshp() + _(" is pulled to Quadrant %s, Sector %s") \
2227 % (game.quadrant, game.sector))
2229 prout(_("(Remainder of rest/repair period cancelled.)"))
2230 game.resting = False
2232 if not damaged(DSHIELD) and game.shield > 0:
2233 doshield(shraise=True) # raise shields
2234 game.shldchg = False
2236 prout(_("(Shields not currently useable.)"))
2238 # Adjust finish time to time of tractor beaming?
2239 # fintim = game.state.date+game.optime
2240 attack(torps_ok=False)
2241 if not game.state.kcmdr:
2244 schedule(FTBEAM, game.optime+expran(1.5*game.intime/len(game.state.kcmdr)))
2247 "Code merges here for any commander destroying a starbase."
2248 # Not perfect, but will have to do
2249 # Handle case where base is in same quadrant as starship
2250 if game.battle == game.quadrant:
2251 game.state.chart[game.battle.i][game.battle.j].starbase = False
2252 game.quad[game.base.i][game.base.j] = '.'
2253 game.base.invalidate()
2256 prout(_("Spock- \"Captain, I believe the starbase has been destroyed.\""))
2257 elif game.state.baseq and communicating():
2258 # Get word via subspace radio
2261 prout(_("Lt. Uhura- \"Captain, Starfleet Command reports that"))
2262 proutn(_(" the starbase in Quadrant %s has been destroyed by") % game.battle)
2264 prout(_("the Klingon Super-Commander"))
2266 prout(_("a Klingon Commander"))
2267 game.state.chart[game.battle.i][game.battle.j].starbase = False
2268 # Remove Starbase from galaxy
2269 game.state.galaxy[game.battle.i][game.battle.j].starbase = False
2270 game.state.baseq = [x for x in game.state.baseq if x != game.battle]
2272 # reinstate a commander's base attack
2276 game.battle.invalidate()
2278 prout("=== EVENTS from %.2f to %.2f:" % (game.state.date, fintim))
2279 for i in range(1, NEVENTS):
2280 if i == FSNOVA: proutn("=== Supernova ")
2281 elif i == FTBEAM: proutn("=== T Beam ")
2282 elif i == FSNAP: proutn("=== Snapshot ")
2283 elif i == FBATTAK: proutn("=== Base Attack ")
2284 elif i == FCDBAS: proutn("=== Base Destroy ")
2285 elif i == FSCMOVE: proutn("=== SC Move ")
2286 elif i == FSCDBAS: proutn("=== SC Base Destroy ")
2287 elif i == FDSPROB: proutn("=== Probe Move ")
2288 elif i == FDISTR: proutn("=== Distress Call ")
2289 elif i == FENSLV: proutn("=== Enslavement ")
2290 elif i == FREPRO: proutn("=== Klingon Build ")
2292 prout("%.2f" % (scheduled(i)))
2295 radio_was_broken = damaged(DRADIO)
2298 # Select earliest extraneous event, evcode==0 if no events
2303 for l in range(1, NEVENTS):
2304 if game.future[l].date < datemin:
2307 prout("== Event %d fires" % evcode)
2308 datemin = game.future[l].date
2309 xtime = datemin-game.state.date
2311 game.energy -= xtime*500.0
2312 if game.energy <= 0:
2315 game.state.date = datemin
2316 # Decrement Federation resources and recompute remaining time
2317 game.state.remres -= (game.state.remkl+4*len(game.state.kcmdr))*xtime
2319 if game.state.remtime <= 0:
2322 # Any crew left alive?
2323 if game.state.crew <= 0:
2326 # Is life support adequate?
2327 if damaged(DLIFSUP) and game.condition != "docked":
2328 if game.lsupres < xtime and game.damage[DLIFSUP] > game.lsupres:
2331 game.lsupres -= xtime
2332 if game.damage[DLIFSUP] <= xtime:
2333 game.lsupres = game.inlsr
2336 if game.condition == "docked":
2338 # Don't fix Deathray here
2339 for l in range(NDEVICES):
2340 if game.damage[l] > 0.0 and l != DDRAY:
2341 if game.damage[l]-repair > 0.0:
2342 game.damage[l] -= repair
2344 game.damage[l] = 0.0
2345 # If radio repaired, update star chart and attack reports
2346 if radio_was_broken and not damaged(DRADIO):
2347 prout(_("Lt. Uhura- \"Captain, the sub-space radio is working and"))
2348 prout(_(" surveillance reports are coming in."))
2350 if not game.iseenit:
2354 prout(_(" The star chart is now up to date.\""))
2356 # Cause extraneous event EVCODE to occur
2357 game.optime -= xtime
2358 if evcode == FSNOVA: # Supernova
2361 schedule(FSNOVA, expran(0.5*game.intime))
2362 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2364 elif evcode == FSPY: # Check with spy to see if SC should tractor beam
2365 if game.state.nscrem == 0 or game.iscloaked or \
2366 ictbeam or istract or \
2367 game.condition == "docked" or game.isatb == 1 or game.iscate:
2369 if game.ientesc or \
2370 (game.energy<2000 and game.torps<4 and game.shield < 1250) or \
2371 (damaged(DPHASER) and (damaged(DPHOTON) or game.torps<4)) or \
2372 (damaged(DSHIELD) and \
2373 (game.energy < 2500 or damaged(DPHASER)) and \
2374 (game.torps < 5 or damaged(DPHOTON))):
2376 istract = ictbeam = True
2377 tractorbeam((game.state.kscmdr-game.quadrant).distance())
2380 elif evcode == FTBEAM: # Tractor beam
2381 if not game.state.kcmdr:
2384 i = randrange(len(game.state.kcmdr))
2385 yank = (game.state.kcmdr[i]-game.quadrant).distance()
2386 if istract or game.condition == "docked" or game.iscloaked or yank == 0:
2387 # Drats! Have to reschedule
2389 game.optime + expran(1.5*game.intime/len(game.state.kcmdr)))
2393 elif evcode == FSNAP: # Snapshot of the universe (for time warp)
2394 game.snapsht = copy.deepcopy(game.state)
2395 game.state.snap = True
2396 schedule(FSNAP, expran(0.5 * game.intime))
2397 elif evcode == FBATTAK: # Commander attacks starbase
2398 if not game.state.kcmdr or not game.state.baseq:
2403 ibq = None # Force battle location to persist past loop
2405 for ibq in game.state.baseq:
2406 for cmdr in game.state.kcmdr:
2407 if ibq == cmdr and ibq != game.quadrant and ibq != game.state.kscmdr:
2409 # no match found -- try later
2410 schedule(FBATTAK, expran(0.3*game.intime))
2415 # commander + starbase combination found -- launch attack
2417 schedule(FCDBAS, randreal(1.0, 4.0))
2418 if game.isatb: # extra time if SC already attacking
2419 postpone(FCDBAS, scheduled(FSCDBAS)-game.state.date)
2420 game.future[FBATTAK].date = game.future[FCDBAS].date + expran(0.3*game.intime)
2421 game.iseenit = False
2422 if not communicating():
2423 continue # No warning :-(
2427 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") % game.battle)
2428 prout(_(" reports that it is under attack and that it can"))
2429 prout(_(" hold out only until stardate %d.\"") % (int(scheduled(FCDBAS))))
2432 elif evcode == FSCDBAS: # Supercommander destroys base
2435 if not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].starbase:
2436 continue # WAS RETURN!
2438 game.battle = game.state.kscmdr
2440 elif evcode == FCDBAS: # Commander succeeds in destroying base
2441 if evcode == FCDBAS:
2443 if not game.state.baseq() \
2444 or not game.state.galaxy[game.battle.i][game.battle.j].starbase:
2445 game.battle.invalidate()
2447 # find the lucky pair
2448 for cmdr in game.state.kcmdr:
2449 if cmdr == game.battle:
2452 # No action to take after all
2455 elif evcode == FSCMOVE: # Supercommander moves
2456 schedule(FSCMOVE, 0.2777)
2457 if not game.ientesc and not istract and game.isatb != 1 and \
2458 (not game.iscate or not game.justin):
2460 elif evcode == FDSPROB: # Move deep space probe
2461 schedule(FDSPROB, 0.01)
2462 if not game.probe.nexttok():
2463 if not game.probe.quadrant().valid_quadrant() or \
2464 game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j].supernova:
2465 # Left galaxy or ran into supernova
2469 proutn(_("Lt. Uhura- \"The deep space probe "))
2470 if not game.probe.quadrant().valid_quadrant():
2471 prout(_("has left the galaxy.\""))
2473 prout(_("is no longer transmitting.\""))
2479 prout(_("Lt. Uhura- \"The deep space probe is now in Quadrant %s.\"") % game.probe.quadrant())
2480 pquad = game.probe.quadrant()
2481 pdest = game.state.galaxy[pquad.i][pquad.j]
2483 game.state.chart[pquad.i][pquad.j].klingons = pdest.klingons
2484 game.state.chart[pquad.i][pquad.j].starbase = pdest.starbase
2485 game.state.chart[pquad.i][pquad.j].stars = pdest.stars
2486 pdest.charted = True
2487 game.probe.moves -= 1 # One less to travel
2488 if game.probe.arrived() and game.isarmed and pdest.stars:
2489 supernova(game.probe) # fire in the hole!
2491 if game.state.galaxy[pquad.i][pquad.j].supernova:
2493 elif evcode == FDISTR: # inhabited system issues distress call
2495 # try a whole bunch of times to find something suitable
2496 for i in range(100):
2497 # need a quadrant which is not the current one,
2498 # which has some stars which are inhabited and
2499 # not already under attack, which is not
2500 # supernova'ed, and which has some Klingons in it
2501 w = randplace(GALSIZE)
2502 q = game.state.galaxy[w.i][w.j]
2503 if not (game.quadrant == w or q.planet is None or \
2504 not q.planet.inhabited or \
2505 q.supernova or q.status!="secure" or q.klingons<=0):
2508 # can't seem to find one; ignore this call
2510 prout("=== Couldn't find location for distress event.")
2512 # got one!! Schedule its enslavement
2513 ev = schedule(FENSLV, expran(game.intime))
2515 q.status = "distressed"
2516 # tell the captain about it if we can
2518 prout(_("Uhura- Captain, %s in Quadrant %s reports it is under attack") \
2519 % (q.planet, repr(w)))
2520 prout(_("by a Klingon invasion fleet."))
2523 elif evcode == FENSLV: # starsystem is enslaved
2524 ev = unschedule(FENSLV)
2525 # see if current distress call still active
2526 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2530 q.status = "enslaved"
2532 # play stork and schedule the first baby
2533 ev2 = schedule(FREPRO, expran(2.0 * game.intime))
2534 ev2.quadrant = ev.quadrant
2536 # report the disaster if we can
2538 prout(_("Uhura- We've lost contact with starsystem %s") % \
2540 prout(_("in Quadrant %s.\n") % ev.quadrant)
2541 elif evcode == FREPRO: # Klingon reproduces
2542 # If we ever switch to a real event queue, we'll need to
2543 # explicitly retrieve and restore the x and y.
2544 ev = schedule(FREPRO, expran(1.0 * game.intime))
2545 # see if current distress call still active
2546 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2550 if game.state.remkl >= MAXKLGAME:
2551 continue # full right now
2552 # reproduce one Klingon
2555 if game.klhere >= MAXKLQUAD:
2557 # this quadrant not ok, pick an adjacent one
2558 for m.i in range(w.i - 1, w.i + 2):
2559 for m.j in range(w.j - 1, w.j + 2):
2560 if not m.valid_quadrant():
2562 q = game.state.galaxy[m.i][m.j]
2563 # check for this quad ok (not full & no snova)
2564 if q.klingons >= MAXKLQUAD or q.supernova:
2567 # search for eligible quadrant failed
2572 game.state.remkl += 1
2574 if game.quadrant == w:
2576 game.enemies.append(newkling())
2577 # recompute time left
2580 if game.quadrant == w:
2581 prout(_("Spock- sensors indicate the Klingons have"))
2582 prout(_("launched a warship from %s.") % q.planet)
2584 prout(_("Uhura- Starfleet reports increased Klingon activity"))
2585 if q.planet != None:
2586 proutn(_("near %s ") % q.planet)
2587 prout(_("in Quadrant %s.") % w)
2593 key = scanner.nexttok()
2596 proutn(_("How long? "))
2601 origTime = delay = scanner.real
2604 if delay >= game.state.remtime or len(game.enemies) != 0:
2605 proutn(_("Are you sure? "))
2608 # Alternate resting periods (events) with attacks
2612 game.resting = False
2613 if not game.resting:
2614 prout(_("%d stardates left.") % int(game.state.remtime))
2616 temp = game.optime = delay
2617 if len(game.enemies):
2618 rtime = randreal(1.0, 2.0)
2622 if game.optime < delay:
2623 attack(torps_ok=False)
2631 # Repair Deathray if long rest at starbase
2632 if origTime-delay >= 9.99 and game.condition == "docked":
2633 game.damage[DDRAY] = 0.0
2634 # leave if quadrant supernovas
2635 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2637 game.resting = False
2642 ncourse = (0.0, 10.5, 12.0, 1.5, 9.0, 0.0, 3.0, 7.5, 6.0, 4.5)
2643 newc = Coord(); neighbor = Coord(); bump = Coord(0, 0)
2645 # Wow! We've supernova'ed
2646 supernova(game.quadrant)
2648 # handle initial nova
2649 game.quad[nov.i][nov.j] = '.'
2650 prout(crmena(False, '*', "sector", nov) + _(" novas."))
2651 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2652 game.state.starkl += 1
2653 # Set up queue to recursively trigger adjacent stars
2659 for offset.i in range(-1, 1+1):
2660 for offset.j in range(-1, 1+1):
2661 if offset.j == 0 and offset.i == 0:
2663 neighbor = start + offset
2664 if not neighbor.valid_sector():
2666 iquad = game.quad[neighbor.i][neighbor.j]
2667 # Empty space ends reaction
2668 if iquad in ('.', '?', ' ', 'T', '#'):
2670 elif iquad == '*': # Affect another star
2672 # This star supernovas
2673 supernova(game.quadrant)
2676 hits.append(neighbor)
2677 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2678 game.state.starkl += 1
2679 proutn(crmena(True, '*', "sector", neighbor))
2681 game.quad[neighbor.i][neighbor.j] = '.'
2683 elif iquad in ('P', '@'): # Destroy planet
2684 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
2686 game.state.nplankl += 1
2688 game.state.nworldkl += 1
2689 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2690 game.iplnet.pclass = "destroyed"
2692 game.plnet.invalidate()
2696 game.quad[neighbor.i][neighbor.j] = '.'
2697 elif iquad == 'B': # Destroy base
2698 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
2699 game.state.baseq = [x for x in game.state.baseq if x!= game.quadrant]
2700 game.base.invalidate()
2701 game.state.basekl += 1
2703 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2704 game.quad[neighbor.i][neighbor.j] = '.'
2705 elif iquad in ('E', 'F'): # Buffet ship
2706 prout(_("***Starship buffeted by nova."))
2708 if game.shield >= 2000.0:
2709 game.shield -= 2000.0
2711 diff = 2000.0 - game.shield
2715 prout(_("***Shields knocked out."))
2716 game.damage[DSHIELD] += 0.005*game.damfac*randreal()*diff
2718 game.energy -= 2000.0
2719 if game.energy <= 0:
2722 # add in course nova contributes to kicking starship
2723 bump += (game.sector-hits[-1]).sgn()
2724 elif iquad == 'K': # kill klingon
2725 deadkl(neighbor, iquad, neighbor)
2726 elif iquad in ('C','S','R'): # Damage/destroy big enemies
2728 for ll in range(len(game.enemies)):
2729 if game.enemies[ll].location == neighbor:
2730 target = game.enemies[ll]
2732 if target is not None:
2733 target.power -= 800.0 # If firepower is lost, die
2734 if target.power <= 0.0:
2735 deadkl(neighbor, iquad, neighbor)
2736 continue # neighbor loop
2737 # Else enemy gets flung by the blast wave
2738 newc = neighbor + neighbor - hits[-1]
2739 proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged"))
2740 if not newc.valid_sector():
2741 # can't leave quadrant
2744 iquad1 = game.quad[newc.i][newc.j]
2746 proutn(_(", blasted into ") + crmena(False, ' ', "sector", newc))
2748 deadkl(neighbor, iquad, newc)
2751 # can't move into something else
2754 proutn(_(", buffeted to Sector %s") % newc)
2755 game.quad[neighbor.i][neighbor.j] = '.'
2756 game.quad[newc.i][newc.j] = iquad
2758 # Starship affected by nova -- kick it away.
2760 direc = ncourse[3*(bump.i+1)+bump.j+2]
2765 scourse = course(bearing=direc, distance=dist)
2766 game.optime = scourse.time(w=4)
2768 prout(_("Force of nova displaces starship."))
2769 imove(scourse, noattack=True)
2770 game.optime = scourse.time(w=4)
2774 "Star goes supernova."
2779 # Scheduled supernova -- select star at random.
2782 for nq.i in range(GALSIZE):
2783 for nq.j in range(GALSIZE):
2784 nstars += game.state.galaxy[nq.i][nq.j].stars
2786 return # nothing to supernova exists
2787 num = randrange(nstars) + 1
2788 for nq.i in range(GALSIZE):
2789 for nq.j in range(GALSIZE):
2790 num -= game.state.galaxy[nq.i][nq.j].stars
2796 proutn("=== Super nova here?")
2799 if not nq == game.quadrant or game.justin:
2800 # it isn't here, or we just entered (treat as enroute)
2803 prout(_("Message from Starfleet Command Stardate %.2f") % game.state.date)
2804 prout(_(" Supernova in Quadrant %s; caution advised.") % nq)
2807 # we are in the quadrant!
2808 num = randrange(game.state.galaxy[nq.i][nq.j].stars) + 1
2809 for ns.i in range(QUADSIZE):
2810 for ns.j in range(QUADSIZE):
2811 if game.quad[ns.i][ns.j]=='*':
2818 prouts(_("***RED ALERT! RED ALERT!"))
2820 prout(_("***Incipient supernova detected at Sector %s") % ns)
2821 if (ns.i-game.sector.i)**2 + (ns.j-game.sector.j)**2 <= 2.1:
2822 proutn(_("Emergency override attempts t"))
2823 prouts("***************")
2827 # destroy any Klingons in supernovaed quadrant
2828 kldead = game.state.galaxy[nq.i][nq.j].klingons
2829 game.state.galaxy[nq.i][nq.j].klingons = 0
2830 if nq == game.state.kscmdr:
2831 # did in the Supercommander!
2832 game.state.nscrem = game.state.kscmdr.i = game.state.kscmdr.j = game.isatb = 0
2836 survivors = filter(lambda w: w != nq, game.state.kcmdr)
2837 comkills = len(game.state.kcmdr) - len(survivors)
2838 game.state.kcmdr = survivors
2840 if not game.state.kcmdr:
2842 game.state.remkl -= kldead
2843 # destroy Romulans and planets in supernovaed quadrant
2844 nrmdead = game.state.galaxy[nq.i][nq.j].romulans
2845 game.state.galaxy[nq.i][nq.j].romulans = 0
2846 game.state.nromrem -= nrmdead
2848 for loop in range(game.inplan):
2849 if game.state.planets[loop].quadrant == nq:
2850 game.state.planets[loop].pclass = "destroyed"
2852 # Destroy any base in supernovaed quadrant
2853 game.state.baseq = [x for x in game.state.baseq if x != nq]
2854 # If starship caused supernova, tally up destruction
2856 game.state.starkl += game.state.galaxy[nq.i][nq.j].stars
2857 game.state.basekl += game.state.galaxy[nq.i][nq.j].starbase
2858 game.state.nplankl += npdead
2859 # mark supernova in galaxy and in star chart
2860 if game.quadrant == nq or communicating():
2861 game.state.galaxy[nq.i][nq.j].supernova = True
2862 # If supernova destroys last Klingons give special message
2863 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0 and not nq == game.quadrant:
2866 prout(_("Lucky you!"))
2867 proutn(_("A supernova in %s has just destroyed the last Klingons.") % nq)
2870 # if some Klingons remain, continue or die in supernova
2875 # Code from finish.c ends here.
2878 "Self-destruct maneuver. Finish with a BANG!"
2880 if damaged(DCOMPTR):
2881 prout(_("Computer damaged; cannot execute destruct sequence."))
2883 prouts(_("---WORKING---")); skip(1)
2884 prouts(_("SELF-DESTRUCT-SEQUENCE-ACTIVATED")); skip(1)
2885 prouts(" 10"); skip(1)
2886 prouts(" 9"); skip(1)
2887 prouts(" 8"); skip(1)
2888 prouts(" 7"); skip(1)
2889 prouts(" 6"); skip(1)
2891 prout(_("ENTER-CORRECT-PASSWORD-TO-CONTINUE-"))
2893 prout(_("SELF-DESTRUCT-SEQUENCE-OTHERWISE-"))
2895 prout(_("SELF-DESTRUCT-SEQUENCE-WILL-BE-ABORTED"))
2898 if game.passwd != scanner.token:
2899 prouts(_("PASSWORD-REJECTED;"))
2901 prouts(_("CONTINUITY-EFFECTED"))
2904 prouts(_("PASSWORD-ACCEPTED")); skip(1)
2905 prouts(" 5"); skip(1)
2906 prouts(" 4"); skip(1)
2907 prouts(" 3"); skip(1)
2908 prouts(" 2"); skip(1)
2909 prouts(" 1"); skip(1)
2911 prouts(_("GOODBYE-CRUEL-WORLD"))
2919 prouts(_("********* Entropy of %s maximized *********") % crmshp())
2923 if len(game.enemies) != 0:
2924 whammo = 25.0 * game.energy
2925 for l in range(len(game.enemies)):
2926 if game.enemies[l].power*game.enemies[l].kdist <= whammo:
2927 deadkl(game.enemies[l].location, game.quad[game.enemies[l].location.i][game.enemies[l].location.j], game.enemies[l].location)
2931 "Compute our rate of kils over time."
2932 elapsed = game.state.date - game.indate
2933 if elapsed == 0: # Avoid divide-by-zero error if calculated on turn 0
2936 starting = (game.inkling + game.incom + game.inscom)
2937 remaining = (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)
2938 return (starting - remaining)/elapsed
2942 badpt = 5.0*game.state.starkl + \
2944 10.0*game.state.nplankl + \
2945 300*game.state.nworldkl + \
2947 100.0*game.state.basekl +\
2948 3.0*game.abandoned +\
2950 if game.ship == 'F':
2952 elif game.ship is None:
2957 # end the game, with appropriate notifications
2961 prout(_("It is stardate %.1f.") % game.state.date)
2963 if ifin == FWON: # Game has been won
2964 if game.state.nromrem != 0:
2965 prout(_("The remaining %d Romulans surrender to Starfleet Command.") %
2968 prout(_("You have smashed the Klingon invasion fleet and saved"))
2969 prout(_("the Federation."))
2970 if game.alive and game.brigcapacity-game.brigfree > 0:
2971 game.kcaptured += game.brigcapacity-game.brigfree
2972 prout(_("The %d captured Klingons are transferred to Star Fleet Command.") % (game.brigcapacity-game.brigfree))
2977 badpt = 0.0 # Close enough!
2978 # killsPerDate >= RateMax
2979 if game.state.date-game.indate < 5.0 or \
2980 killrate() >= 0.1*game.skill*(game.skill+1.0) + 0.1 + 0.008*badpt:
2982 prout(_("In fact, you have done so well that Starfleet Command"))
2983 if game.skill == SKILL_NOVICE:
2984 prout(_("promotes you one step in rank from \"Novice\" to \"Fair\"."))
2985 elif game.skill == SKILL_FAIR:
2986 prout(_("promotes you one step in rank from \"Fair\" to \"Good\"."))
2987 elif game.skill == SKILL_GOOD:
2988 prout(_("promotes you one step in rank from \"Good\" to \"Expert\"."))
2989 elif game.skill == SKILL_EXPERT:
2990 prout(_("promotes you to Commodore Emeritus."))
2992 prout(_("Now that you think you're really good, try playing"))
2993 prout(_("the \"Emeritus\" game. It will splatter your ego."))
2994 elif game.skill == SKILL_EMERITUS:
2996 proutn(_("Computer- "))
2997 prouts(_("ERROR-ERROR-ERROR-ERROR"))
2999 prouts(_(" YOUR-SKILL-HAS-EXCEEDED-THE-CAPACITY-OF-THIS-PROGRAM"))
3001 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
3003 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
3005 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
3007 prouts(_(" THIS-PROGRAM-MUST?- MUST ? - SUR? ? -? VI"))
3009 prout(_("Now you can retire and write your own Star Trek game!"))
3011 elif game.skill >= SKILL_EXPERT:
3012 if game.thawed and not game.idebug:
3013 prout(_("You cannot get a citation, so..."))
3015 proutn(_("Do you want your Commodore Emeritus Citation printed? "))
3019 # Only grant long life if alive (original didn't!)
3021 prout(_("LIVE LONG AND PROSPER."))
3026 elif ifin == FDEPLETE: # Federation Resources Depleted
3027 prout(_("Your time has run out and the Federation has been"))
3028 prout(_("conquered. Your starship is now Klingon property,"))
3029 prout(_("and you are put on trial as a war criminal. On the"))
3030 proutn(_("basis of your record, you are "))
3031 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)*3.0 > (game.inkling + game.incom + game.inscom):
3032 prout(_("acquitted."))
3034 prout(_("LIVE LONG AND PROSPER."))
3036 prout(_("found guilty and"))
3037 prout(_("sentenced to death by slow torture."))
3041 elif ifin == FLIFESUP:
3042 prout(_("Your life support reserves have run out, and"))
3043 prout(_("you die of thirst, starvation, and asphyxiation."))
3044 prout(_("Your starship is a derelict in space."))
3046 prout(_("Your energy supply is exhausted."))
3048 prout(_("Your starship is a derelict in space."))
3049 elif ifin == FBATTLE:
3050 prout(_("The %s has been destroyed in battle.") % crmshp())
3052 prout(_("Dulce et decorum est pro patria mori."))
3054 prout(_("You have made three attempts to cross the negative energy"))
3055 prout(_("barrier which surrounds the galaxy."))
3057 prout(_("Your navigation is abominable."))
3060 prout(_("Your starship has been destroyed by a nova."))
3061 prout(_("That was a great shot."))
3063 elif ifin == FSNOVAED:
3064 prout(_("The %s has been fried by a supernova.") % crmshp())
3065 prout(_("...Not even cinders remain..."))
3066 elif ifin == FABANDN:
3067 prout(_("You have been captured by the Klingons. If you still"))
3068 prout(_("had a starbase to be returned to, you would have been"))
3069 prout(_("repatriated and given another chance. Since you have"))
3070 prout(_("no starbases, you will be mercilessly tortured to death."))
3071 elif ifin == FDILITHIUM:
3072 prout(_("Your starship is now an expanding cloud of subatomic particles"))
3073 elif ifin == FMATERIALIZE:
3074 prout(_("Starbase was unable to re-materialize your starship."))
3075 prout(_("Sic transit gloria mundi"))
3076 elif ifin == FPHASER:
3077 prout(_("The %s has been cremated by its own phasers.") % crmshp())
3079 prout(_("You and your landing party have been"))
3080 prout(_("converted to energy, dissipating through space."))
3081 elif ifin == FMINING:
3082 prout(_("You are left with your landing party on"))
3083 prout(_("a wild jungle planet inhabited by primitive cannibals."))
3085 prout(_("They are very fond of \"Captain Kirk\" soup."))
3087 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
3088 elif ifin == FDPLANET:
3089 prout(_("You and your mining party perish."))
3091 prout(_("That was a great shot."))
3094 prout(_("The Galileo is instantly annihilated by the supernova."))
3095 prout(_("You and your mining party are atomized."))
3097 prout(_("Mr. Spock takes command of the %s and") % crmshp())
3098 prout(_("joins the Romulans, wreaking terror on the Federation."))
3099 elif ifin == FPNOVA:
3100 prout(_("You and your mining party are atomized."))
3102 prout(_("Mr. Spock takes command of the %s and") % crmshp())
3103 prout(_("joins the Romulans, wreaking terror on the Federation."))
3104 elif ifin == FSTRACTOR:
3105 prout(_("The shuttle craft Galileo is also caught,"))
3106 prout(_("and breaks up under the strain."))
3108 prout(_("Your debris is scattered for millions of miles."))
3109 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
3111 prout(_("The mutants attack and kill Spock."))
3112 prout(_("Your ship is captured by Klingons, and"))
3113 prout(_("your crew is put on display in a Klingon zoo."))
3114 elif ifin == FTRIBBLE:
3115 prout(_("Tribbles consume all remaining water,"))
3116 prout(_("food, and oxygen on your ship."))
3118 prout(_("You die of thirst, starvation, and asphyxiation."))
3119 prout(_("Your starship is a derelict in space."))
3121 prout(_("Your ship is drawn to the center of the black hole."))
3122 prout(_("You are crushed into extremely dense matter."))
3123 elif ifin == FCLOAK:
3125 prout(_("You have violated the Treaty of Algeron."))
3126 prout(_("The Romulan Empire can never trust you again."))
3128 prout(_("Your last crew member has died."))
3129 if ifin != FWON and ifin != FCLOAK and game.iscloaked:
3130 prout(_("Your ship was cloaked so your subspace radio did not receive anything."))
3131 prout(_("You may have missed some warning messages."))
3133 if game.ship == 'F':
3135 elif game.ship == 'E':
3138 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0:
3139 goodies = game.state.remres/game.inresor
3140 baddies = (game.state.remkl + 2.0*len(game.state.kcmdr))/(game.inkling+2.0*game.incom)
3141 if goodies/baddies >= randreal(1.0, 1.5):
3142 prout(_("As a result of your actions, a treaty with the Klingon"))
3143 prout(_("Empire has been signed. The terms of the treaty are"))
3144 if goodies/baddies >= randreal(3.0):
3145 prout(_("favorable to the Federation."))
3147 prout(_("Congratulations!"))
3149 prout(_("highly unfavorable to the Federation."))
3151 prout(_("The Federation will be destroyed."))
3153 prout(_("Since you took the last Klingon with you, you are a"))
3154 prout(_("martyr and a hero. Someday maybe they'll erect a"))
3155 prout(_("statue in your memory. Rest in peace, and try not"))
3156 prout(_("to think about pigeons."))
3159 scanner.chew() # Clean up leftovers
3162 "Compute player's score."
3163 timused = game.state.date - game.indate
3164 if (timused == 0 or (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0) and timused < 5.0:
3166 game.perdate = killrate()
3167 ithperd = 500*game.perdate + 0.5
3170 iwon = 100*game.skill
3171 if game.ship == 'E':
3173 elif game.ship == 'F':
3177 game.score = 10*(game.inkling - game.state.remkl) \
3178 + 50*(game.incom - len(game.state.kcmdr)) \
3180 + 20*(game.inrom - game.state.nromrem) \
3181 + 200*(game.inscom - game.state.nscrem) \
3182 - game.state.nromrem \
3183 + 3 * game.kcaptured \
3188 prout(_("Your score --"))
3189 if game.inrom - game.state.nromrem:
3190 prout(_("%6d Romulans destroyed %5d") %
3191 (game.inrom - game.state.nromrem, 20*(game.inrom - game.state.nromrem)))
3192 if game.state.nromrem and game.gamewon:
3193 prout(_("%6d Romulans captured %5d") %
3194 (game.state.nromrem, game.state.nromrem))
3195 if game.inkling - game.state.remkl:
3196 prout(_("%6d ordinary Klingons destroyed %5d") %
3197 (game.inkling - game.state.remkl, 10*(game.inkling - game.state.remkl)))
3198 if game.incom - len(game.state.kcmdr):
3199 prout(_("%6d Klingon commanders destroyed %5d") %
3200 (game.incom - len(game.state.kcmdr), 50*(game.incom - len(game.state.kcmdr))))
3202 prout(_("%d Klingons captured %5d") %
3203 (game.kcaptured, 3 * game.kcaptured))
3204 if game.inscom - game.state.nscrem:
3205 prout(_("%6d Super-Commander destroyed %5d") %
3206 (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem)))
3208 prout(_("%6.2f Klingons per stardate %5d") %
3209 (game.perdate, ithperd))
3210 if game.state.starkl:
3211 prout(_("%6d stars destroyed by your action %5d") %
3212 (game.state.starkl, -5*game.state.starkl))
3213 if game.state.nplankl:
3214 prout(_("%6d planets destroyed by your action %5d") %
3215 (game.state.nplankl, -10*game.state.nplankl))
3216 if (game.options & OPTION_WORLDS) and game.state.nworldkl:
3217 prout(_("%6d inhabited planets destroyed by your action %5d") %
3218 (game.state.nworldkl, -300*game.state.nworldkl))
3219 if game.state.basekl:
3220 prout(_("%6d bases destroyed by your action %5d") %
3221 (game.state.basekl, -100*game.state.basekl))
3223 prout(_("%6d calls for help from starbase %5d") %
3224 (game.nhelp, -45*game.nhelp))
3226 prout(_("%6d casualties incurred %5d") %
3227 (game.casual, -game.casual))
3229 prout(_("%6d crew abandoned in space %5d") %
3230 (game.abandoned, -3*game.abandoned))
3232 prout(_("%6d ship(s) lost or destroyed %5d") %
3233 (klship, -100*klship))
3236 prout(_("1 Treaty of Algeron violation -100"))
3238 prout(_("%6d Treaty of Algeron violations %5d\n") %
3239 (ncviol, -100*ncviol))
3241 prout(_("Penalty for getting yourself killed -200"))
3243 proutn(_("Bonus for winning "))
3244 if game.skill == SKILL_NOVICE: proutn(_("Novice game "))
3245 elif game.skill == SKILL_FAIR: proutn(_("Fair game "))
3246 elif game.skill == SKILL_GOOD: proutn(_("Good game "))
3247 elif game.skill == SKILL_EXPERT: proutn(_("Expert game "))
3248 elif game.skill == SKILL_EMERITUS: proutn(_("Emeritus game"))
3249 prout(" %5d" % iwon)
3251 prout(_("TOTAL SCORE %5d") % game.score)
3254 "Emit winner's commemmorative plaque."
3257 proutn(_("File or device name for your plaque: "))
3260 fp = open(winner, "w")
3263 prout(_("Invalid name."))
3265 proutn(_("Enter name to go on plaque (up to 30 characters): "))
3267 # The 38 below must be 64 for 132-column paper
3268 nskip = 38 - len(winner)/2
3269 fp.write("\n\n\n\n")
3270 # --------DRAW ENTERPRISE PICTURE.
3271 fp.write(" EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n" )
3272 fp.write(" EEE E : : : E\n" )
3273 fp.write(" EE EEE E : : NCC-1701 : E\n")
3274 fp.write("EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEE : : : E\n")
3275 fp.write(" E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n")
3276 fp.write(" EEEEEEEEE EEEEEEEEEEEEE E E\n")
3277 fp.write(" EEEEEEE EEEEE E E E E\n")
3278 fp.write(" EEE E E E E\n")
3279 fp.write(" E E E E\n")
3280 fp.write(" EEEEEEEEEEEEE E E\n")
3281 fp.write(" EEE : EEEEEEE EEEEEEEE\n")
3282 fp.write(" :E : EEEE E\n")
3283 fp.write(" .-E -:----- E\n")
3284 fp.write(" :E : E\n")
3285 fp.write(" EE : EEEEEEEE\n")
3286 fp.write(" EEEEEEEEEEEEEEEEEEEEEEE\n")
3288 fp.write(_(" U. S. S. ENTERPRISE\n"))
3289 fp.write("\n\n\n\n")
3290 fp.write(_(" For demonstrating outstanding ability as a starship captain\n"))
3292 fp.write(_(" Starfleet Command bestows to you\n"))
3294 fp.write("%*s%s\n\n" % (nskip, "", winner))
3295 fp.write(_(" the rank of\n\n"))
3296 fp.write(_(" \"Commodore Emeritus\"\n\n"))
3298 if game.skill == SKILL_EXPERT:
3299 fp.write(_(" Expert level\n\n"))
3300 elif game.skill == SKILL_EMERITUS:
3301 fp.write(_("Emeritus level\n\n"))
3303 fp.write(_(" Cheat level\n\n"))
3304 timestring = time.ctime()
3305 fp.write(_(" This day of %.6s %.4s, %.8s\n\n") %
3306 (timestring+4, timestring+20, timestring+11))
3307 fp.write(_(" Your score: %d\n\n") % game.score)
3308 fp.write(_(" Klingons per stardate: %.2f\n") % game.perdate)
3311 # Code from io.c begins here
3313 rows = linecount = 0 # for paging
3316 fullscreen_window = None
3317 srscan_window = None # Short range scan
3318 report_window = None # Report legends for status window
3319 status_window = None # The status window itself
3320 lrscan_window = None # Long range scan
3321 message_window = None # Main window for scrolling text
3322 prompt_window = None # Prompt window at bottom of display
3327 # for some recent versions of python2, the following enables UTF8
3328 # for the older ones we probably need to set C locale, and python3
3329 # has no problems at all
3330 if sys.version_info[0] < 3:
3331 locale.setlocale(locale.LC_ALL, "")
3332 gettext.bindtextdomain("sst", "/usr/local/share/locale")
3333 gettext.textdomain("sst")
3334 if not (game.options & OPTION_CURSES):
3335 ln_env = os.getenv("LINES")
3341 stdscr = curses.initscr()
3345 if game.options & OPTION_COLOR:
3346 curses.start_color()
3347 curses.use_default_colors()
3348 curses.init_pair(curses.COLOR_BLACK, curses.COLOR_BLACK, -1)
3349 curses.init_pair(curses.COLOR_GREEN, curses.COLOR_GREEN, -1)
3350 curses.init_pair(curses.COLOR_RED, curses.COLOR_RED, -1)
3351 curses.init_pair(curses.COLOR_CYAN, curses.COLOR_CYAN, -1)
3352 curses.init_pair(curses.COLOR_WHITE, curses.COLOR_WHITE, -1)
3353 curses.init_pair(curses.COLOR_MAGENTA, curses.COLOR_MAGENTA, -1)
3354 curses.init_pair(curses.COLOR_BLUE, curses.COLOR_BLUE, -1)
3355 curses.init_pair(curses.COLOR_YELLOW, curses.COLOR_YELLOW, -1)
3356 global fullscreen_window, srscan_window, report_window, status_window
3357 global lrscan_window, message_window, prompt_window
3358 (rows, _columns) = stdscr.getmaxyx()
3359 fullscreen_window = stdscr
3360 srscan_window = curses.newwin(12, 25, 0, 0)
3361 report_window = curses.newwin(11, 0, 1, 25)
3362 status_window = curses.newwin(10, 0, 1, 39)
3363 lrscan_window = curses.newwin(5, 0, 0, 64)
3364 message_window = curses.newwin(0, 0, 12, 0)
3365 prompt_window = curses.newwin(1, 0, rows-2, 0)
3366 message_window.scrollok(True)
3367 setwnd(fullscreen_window)
3371 if game.options & OPTION_CURSES:
3372 stdscr.keypad(False)
3378 "Wait for user action -- OK to do nothing if on a TTY"
3379 if game.options & OPTION_CURSES:
3384 prouts(_("[ANNOUNCEMENT ARRIVING...]"))
3388 if game.skill > SKILL_FAIR:
3389 prompt = _("[CONTINUE?]")
3391 prompt = _("[PRESS ENTER TO CONTINUE]")
3393 if game.options & OPTION_CURSES:
3395 setwnd(prompt_window)
3396 prompt_window.clear()
3397 prompt_window.addstr(prompt)
3398 prompt_window.getstr()
3399 prompt_window.clear()
3400 prompt_window.refresh()
3401 setwnd(message_window)
3404 sys.stdout.write('\n')
3408 sys.stdout.write('\n' * rows)
3412 "Skip i lines. Pause game if this would cause a scrolling event."
3413 for _dummy in range(i):
3414 if game.options & OPTION_CURSES:
3415 (y, _x) = curwnd.getyx()
3418 except curses.error:
3423 if rows and linecount >= rows:
3426 sys.stdout.write('\n')
3428 def proutn(proutntline):
3429 "Utter a line with no following line feed."
3430 if game.options & OPTION_CURSES:
3431 (y, x) = curwnd.getyx()
3432 (my, _mx) = curwnd.getmaxyx()
3433 if curwnd == message_window and y >= my - 2:
3436 # Uncomment this to debug curses problems
3438 logfp.write("#curses: at %s proutn(%s)\n" % ((y, x), repr(proutntline)))
3439 curwnd.addstr(proutntline)
3442 sys.stdout.write(proutntline)
3445 def prout(proutline):
3449 def prouts(proutsline):
3451 for c in proutsline:
3452 if not replayfp or replayfp.closed: # Don't slow down replays
3455 if game.options & OPTION_CURSES:
3459 if not replayfp or replayfp.closed:
3463 "Get a line of input."
3464 if game.options & OPTION_CURSES:
3465 linein = curwnd.getstr() + "\n"
3468 if replayfp and not replayfp.closed:
3470 linein = replayfp.readline()
3473 prout("*** Replay finished")
3476 elif linein[0] != "#":
3479 linein = eval(input()) + "\n"
3485 "Change windows -- OK for this to be a no-op in tty mode."
3487 if game.options & OPTION_CURSES:
3488 # Uncomment this to debug curses problems
3490 if wnd == fullscreen_window:
3491 legend = "fullscreen"
3492 elif wnd == srscan_window:
3494 elif wnd == report_window:
3496 elif wnd == status_window:
3498 elif wnd == lrscan_window:
3500 elif wnd == message_window:
3502 elif wnd == prompt_window:
3506 logfp.write("#curses: setwnd(%s)\n" % legend)
3508 # Some curses implementations get confused when you try this.
3510 curses.curs_set(wnd in (fullscreen_window, message_window, prompt_window))
3511 except curses.error:
3515 "Clear to end of line -- can be a no-op in tty mode"
3516 if game.options & OPTION_CURSES:
3521 "Clear screen -- can be a no-op in tty mode."
3523 if game.options & OPTION_CURSES:
3529 def textcolor(color=DEFAULT):
3530 if game.options & OPTION_COLOR:
3531 if color == DEFAULT:
3533 elif color == BLACK:
3534 curwnd.attron(curses.color_pair(curses.COLOR_BLACK))
3536 curwnd.attron(curses.color_pair(curses.COLOR_BLUE))
3537 elif color == GREEN:
3538 curwnd.attron(curses.color_pair(curses.COLOR_GREEN))
3540 curwnd.attron(curses.color_pair(curses.COLOR_CYAN))
3542 curwnd.attron(curses.color_pair(curses.COLOR_RED))
3543 elif color == MAGENTA:
3544 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA))
3545 elif color == BROWN:
3546 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW))
3547 elif color == LIGHTGRAY:
3548 curwnd.attron(curses.color_pair(curses.COLOR_WHITE))
3549 elif color == DARKGRAY:
3550 curwnd.attron(curses.color_pair(curses.COLOR_BLACK) | curses.A_BOLD)
3551 elif color == LIGHTBLUE:
3552 curwnd.attron(curses.color_pair(curses.COLOR_BLUE) | curses.A_BOLD)
3553 elif color == LIGHTGREEN:
3554 curwnd.attron(curses.color_pair(curses.COLOR_GREEN) | curses.A_BOLD)
3555 elif color == LIGHTCYAN:
3556 curwnd.attron(curses.color_pair(curses.COLOR_CYAN) | curses.A_BOLD)
3557 elif color == LIGHTRED:
3558 curwnd.attron(curses.color_pair(curses.COLOR_RED) | curses.A_BOLD)
3559 elif color == LIGHTMAGENTA:
3560 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA) | curses.A_BOLD)
3561 elif color == YELLOW:
3562 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW) | curses.A_BOLD)
3563 elif color == WHITE:
3564 curwnd.attron(curses.color_pair(curses.COLOR_WHITE) | curses.A_BOLD)
3567 if game.options & OPTION_COLOR:
3568 curwnd.attron(curses.A_REVERSE)
3571 # Things past this point have policy implications.
3575 "Hook to be called after moving to redraw maps."
3576 if game.options & OPTION_CURSES:
3579 setwnd(srscan_window)
3583 setwnd(status_window)
3584 status_window.clear()
3585 status_window.move(0, 0)
3586 setwnd(report_window)
3587 report_window.clear()
3588 report_window.move(0, 0)
3590 setwnd(lrscan_window)
3591 lrscan_window.clear()
3592 lrscan_window.move(0, 0)
3593 lrscan(silent=False)
3595 def put_srscan_sym(w, sym):
3596 "Emit symbol for short-range scan."
3597 srscan_window.move(w.i+1, w.j*2+2)
3598 srscan_window.addch(sym)
3599 srscan_window.refresh()
3602 "Enemy fall down, go boom."
3603 if game.options & OPTION_CURSES:
3605 setwnd(srscan_window)
3606 srscan_window.attron(curses.A_REVERSE)
3607 put_srscan_sym(w, game.quad[w.i][w.j])
3611 srscan_window.attroff(curses.A_REVERSE)
3612 put_srscan_sym(w, game.quad[w.i][w.j])
3613 curses.delay_output(500)
3614 setwnd(message_window)
3617 "Sound and visual effects for teleportation."
3618 if game.options & OPTION_CURSES:
3620 setwnd(message_window)
3622 prouts(" . . . . . ")
3623 if game.options & OPTION_CURSES:
3624 #curses.delay_output(1000)
3628 def tracktorpedo(w, step, i, n, iquad):
3629 "Torpedo-track animation."
3630 if not game.options & OPTION_CURSES:
3634 proutn(_("Track for torpedo number %d- ") % (i+1))
3637 proutn(_("Torpedo track- "))
3638 elif step==4 or step==9:
3642 if not damaged(DSRSENS) or game.condition=="docked":
3643 if i != 0 and step == 1:
3646 if (iquad=='.') or (iquad==' '):
3647 put_srscan_sym(w, '+')
3651 put_srscan_sym(w, iquad)
3653 curwnd.attron(curses.A_REVERSE)
3654 put_srscan_sym(w, iquad)
3658 curwnd.attroff(curses.A_REVERSE)
3659 put_srscan_sym(w, iquad)
3664 "Display the current galaxy chart."
3665 if game.options & OPTION_CURSES:
3666 setwnd(message_window)
3667 message_window.clear()
3669 if game.options & OPTION_TTY:
3674 def prstat(txt, data):
3676 if game.options & OPTION_CURSES:
3678 setwnd(status_window)
3680 proutn(" " * (NSYM - len(txt)))
3683 if game.options & OPTION_CURSES:
3684 setwnd(report_window)
3686 # Code from moving.c begins here
3688 def imove(icourse=None, noattack=False):
3689 "Movement execution for warp, impulse, supernova, and tractor-beam events."
3692 def newquadrant(noattack):
3693 # Leaving quadrant -- allow final enemy attack
3694 # Don't set up attack if being pushed by nova or cloaked
3695 if len(game.enemies) != 0 and not noattack and not game.iscloaked:
3697 for enemy in game.enemies:
3698 finald = (w - enemy.location).distance()
3699 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3700 # Stas Sergeev added the condition
3701 # that attacks only happen if Klingons
3702 # are present and your skill is good.
3703 if game.skill > SKILL_GOOD and game.klhere > 0 and not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3704 attack(torps_ok=False)
3707 # check for edge of galaxy
3713 if icourse.final.i < 0:
3714 icourse.final.i = -icourse.final.i
3716 if icourse.final.j < 0:
3717 icourse.final.j = -icourse.final.j
3719 if icourse.final.i >= GALSIZE*QUADSIZE:
3720 icourse.final.i = (GALSIZE*QUADSIZE*2) - icourse.final.i
3722 if icourse.final.j >= GALSIZE*QUADSIZE:
3723 icourse.final.j = (GALSIZE*QUADSIZE*2) - icourse.final.j
3731 if game.nkinks == 3:
3732 # Three strikes -- you're out!
3736 prout(_("YOU HAVE ATTEMPTED TO CROSS THE NEGATIVE ENERGY BARRIER"))
3737 prout(_("AT THE EDGE OF THE GALAXY. THE THIRD TIME YOU TRY THIS,"))
3738 prout(_("YOU WILL BE DESTROYED."))
3739 # Compute final position in new quadrant
3740 if trbeam: # Don't bother if we are to be beamed
3742 game.quadrant = icourse.final.quadrant()
3743 game.sector = icourse.final.sector()
3745 prout(_("Entering Quadrant %s.") % game.quadrant)
3746 game.quad[game.sector.i][game.sector.j] = game.ship
3748 if game.skill>SKILL_NOVICE:
3749 attack(torps_ok=False)
3751 def check_collision(h):
3752 iquad = game.quad[h.i][h.j]
3754 # object encountered in flight path
3755 stopegy = 50.0*icourse.distance/game.optime
3756 if iquad in ('T', 'K', 'C', 'S', 'R', '?'):
3757 for enemy in game.enemies:
3758 if enemy.location == game.sector:
3759 collision(rammed=False, enemy=enemy)
3761 # This should not happen
3762 prout(_("Which way did he go?"))
3766 prouts(_("***RED ALERT! RED ALERT!"))
3768 proutn("***" + crmshp())
3769 proutn(_(" pulled into black hole at Sector %s") % h)
3770 # Getting pulled into a black hole was certain
3771 # death in Almy's original. Stas Sergeev added a
3772 # possibility that you'll get timewarped instead.
3774 for m in range(NDEVICES):
3775 if game.damage[m]>0:
3777 probf=math.pow(1.4,(game.energy+game.shield)/5000.0-1.0)*math.pow(1.3,1.0/(n+1)-1.0)
3778 if (game.options & OPTION_BLKHOLE) and withprob(1-probf):
3788 prout(_(" encounters Tholian web at %s;") % h)
3790 prout(_(" blocked by object at %s;") % h)
3791 proutn(_("Emergency stop required "))
3792 prout(_("%2d units of energy.") % int(stopegy))
3793 game.energy -= stopegy
3794 if game.energy <= 0:
3801 prout(_("Helmsman Sulu- \"Leaving standard orbit.\""))
3802 game.inorbit = False
3803 # If tractor beam is to occur, don't move full distance
3804 if game.state.date+game.optime >= scheduled(FTBEAM):
3806 # We can't be tractor beamed if cloaked,
3807 # so move the event into the future
3808 postpone(FTBEAM, game.optime + expran(1.5*game.intime/len(game.kcmdr)))
3812 game.condition = "red"
3813 icourse.distance = icourse.distance*(scheduled(FTBEAM)-game.state.date)/game.optime + 0.1
3814 game.optime = scheduled(FTBEAM) - game.state.date + 1e-5
3816 game.quad[game.sector.i][game.sector.j] = '.'
3817 for _m in range(icourse.moves):
3819 w = icourse.sector()
3820 if icourse.origin.quadrant() != icourse.location.quadrant():
3821 newquadrant(noattack)
3823 elif check_collision(w):
3824 print("Collision detected")
3828 # We're in destination quadrant -- compute new average enemy distances
3829 game.quad[game.sector.i][game.sector.j] = game.ship
3831 for enemy in game.enemies:
3832 finald = (w-enemy.location).distance()
3833 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3834 enemy.kdist = finald
3836 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3837 attack(torps_ok=False)
3838 for enemy in game.enemies:
3839 enemy.kavgd = enemy.kdist
3842 setwnd(message_window)
3846 "Dock our ship at a starbase."
3848 if game.condition == "docked" and verbose:
3849 prout(_("Already docked."))
3852 prout(_("You must first leave standard orbit."))
3854 if not game.base.is_valid() or abs(game.sector.i-game.base.i) > 1 or abs(game.sector.j-game.base.j) > 1:
3855 prout(crmshp() + _(" not adjacent to base."))
3858 prout(_("You cannot dock while cloaked."))
3860 game.condition = "docked"
3864 if game.energy < game.inenrg:
3865 game.energy = game.inenrg
3866 game.shield = game.inshld
3867 game.torps = game.intorps
3868 game.lsupres = game.inlsr
3869 game.state.crew = FULLCREW
3870 if game.brigcapacity-game.brigfree > 0:
3871 prout(_("%d captured Klingons transferred to base") % (game.brigcapacity-game.brigfree))
3872 game.kcaptured += game.brigcapacity-game.brigfree
3873 game.brigfree = game.brigcapacity
3874 if not damaged(DRADIO) and \
3875 ((is_scheduled(FCDBAS) or game.isatb == 1) and not game.iseenit):
3876 # get attack report from base
3877 prout(_("Lt. Uhura- \"Captain, an important message from the starbase:\""))
3881 def cartesian(loc1=None, loc2=None):
3883 return game.quadrant * QUADSIZE + game.sector
3885 return game.quadrant * QUADSIZE + loc1
3887 return loc1 * QUADSIZE + loc2
3889 def getcourse(isprobe):
3890 "Get a course and distance from the user."
3892 dquad = copy.copy(game.quadrant)
3893 navmode = "unspecified"
3897 if game.landed and not isprobe:
3898 prout(_("Dummy! You can't leave standard orbit until you"))
3899 proutn(_("are back aboard the ship."))
3902 while navmode == "unspecified":
3903 if damaged(DNAVSYS):
3905 prout(_("Computer damaged; manual navigation only"))
3907 prout(_("Computer damaged; manual movement only"))
3912 key = scanner.nexttok()
3914 proutn(_("Manual or automatic- "))
3917 elif key == "IHALPHA":
3918 if scanner.sees("manual"):
3920 key = scanner.nexttok()
3922 elif scanner.sees("automatic"):
3923 navmode = "automatic"
3924 key = scanner.nexttok()
3932 prout(_("(Manual navigation assumed.)"))
3934 prout(_("(Manual movement assumed.)"))
3938 if navmode == "automatic":
3939 while key == "IHEOL":
3941 proutn(_("Target quadrant or quadrant§or- "))
3943 proutn(_("Destination sector or quadrant§or- "))
3946 key = scanner.nexttok()
3950 xi = int(round(scanner.real))-1
3951 key = scanner.nexttok()
3955 xj = int(round(scanner.real))-1
3956 key = scanner.nexttok()
3958 # both quadrant and sector specified
3959 xk = int(round(scanner.real))-1
3960 key = scanner.nexttok()
3964 xl = int(round(scanner.real))-1
3970 # only one pair of numbers was specified
3972 # only quadrant specified -- go to center of dest quad
3975 dsect.j = dsect.i = 4 # preserves 1-origin behavior
3977 # only sector specified
3981 if not dquad.valid_quadrant() or not dsect.valid_sector():
3988 prout(_("Helmsman Sulu- \"Course locked in for Sector %s.\"") % dsect)
3990 prout(_("Ensign Chekov- \"Course laid in, Captain.\""))
3991 # the actual deltas get computed here
3992 delta.j = dquad.j-game.quadrant.j + (dsect.j-game.sector.j)/(QUADSIZE*1.0)
3993 delta.i = game.quadrant.i-dquad.i + (game.sector.i-dsect.i)/(QUADSIZE*1.0)
3995 while key == "IHEOL":
3996 proutn(_("X and Y displacements- "))
3999 key = scanner.nexttok()
4004 delta.j = scanner.real
4005 key = scanner.nexttok()
4009 delta.i = scanner.real
4010 # Check for zero movement
4011 if delta.i == 0 and delta.j == 0:
4014 if itemp == "verbose" and not isprobe:
4016 prout(_("Helmsman Sulu- \"Aye, Sir.\""))
4018 return course(bearing=delta.bearing(), distance=delta.distance())
4021 def __init__(self, bearing, distance, origin=None):
4022 self.distance = distance
4023 self.bearing = bearing
4025 self.origin = cartesian(game.quadrant, game.sector)
4027 self.origin = origin
4028 # The bearing() code we inherited from FORTRAN is actually computing
4029 # clockface directions!
4030 if self.bearing < 0.0:
4031 self.bearing += 12.0
4032 self.angle = ((15.0 - self.bearing) * 0.5235988)
4033 self.increment = Coord(-math.sin(self.angle), math.cos(self.angle))
4034 bigger = max(abs(self.increment.i), abs(self.increment.j))
4035 self.increment /= bigger
4036 self.moves = int(round(10*self.distance*bigger))
4038 self.final = (self.location + self.moves*self.increment).roundtogrid()
4039 self.location = self.origin
4040 self.nextlocation = None
4042 self.location = self.origin
4045 return self.location.roundtogrid() == self.final
4047 "Next step on course."
4049 self.nextlocation = self.location + self.increment
4050 samequad = (self.location.quadrant() == self.nextlocation.quadrant())
4051 self.location = self.nextlocation
4054 return self.location.quadrant()
4056 return self.location.sector()
4058 return self.distance*(w**3)*(game.shldup+1)
4060 return 10.0*self.distance/w**2
4063 "Move under impulse power."
4065 if damaged(DIMPULS):
4068 prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
4070 if game.energy > 30.0:
4072 icourse = getcourse(isprobe=False)
4075 power = 20.0 + 100.0*icourse.distance
4078 if power >= game.energy:
4079 # Insufficient power for trip
4081 prout(_("First Officer Spock- \"Captain, the impulse engines"))
4082 prout(_("require 20.0 units to engage, plus 100.0 units per"))
4083 if game.energy > 30:
4084 proutn(_("quadrant. We can go, therefore, a maximum of %d") %
4085 int(0.01 * (game.energy-20.0)-0.05))
4086 prout(_(" quadrants.\""))
4088 prout(_("quadrant. They are, therefore, useless.\""))
4091 # Make sure enough time is left for the trip
4092 game.optime = icourse.distance/0.095
4093 if game.optime >= game.state.remtime:
4094 prout(_("First Officer Spock- \"Captain, our speed under impulse"))
4095 prout(_("power is only 0.95 sectors per stardate. Are you sure"))
4096 proutn(_("we dare spend the time?\" "))
4099 # Activate impulse engines and pay the cost
4100 imove(icourse, noattack=False)
4104 power = 20.0 + 100.0*icourse.distance
4105 game.energy -= power
4106 game.optime = icourse.distance/0.095
4107 if game.energy <= 0:
4111 def warp(wcourse, involuntary):
4112 "ove under warp drive."
4113 blooey = False; twarp = False
4114 if not involuntary: # Not WARPX entry
4119 prout(_("Engineer Scott- \"The warp engines can not be used while cloaked, Sir.\""))
4121 if game.damage[DWARPEN] > 10.0:
4124 prout(_("Engineer Scott- \"The warp engines are damaged, Sir.\""))
4126 if damaged(DWARPEN) and game.warpfac > 4.0:
4129 prout(_("Engineer Scott- \"Sorry, Captain. Until this damage"))
4130 prout(_(" is repaired, I can only give you warp 4.\""))
4132 # Read in course and distance
4135 wcourse = getcourse(isprobe=False)
4138 # Make sure starship has enough energy for the trip
4139 # Note: this formula is slightly different from the C version,
4140 # and lets you skate a bit closer to the edge.
4141 if wcourse.power(game.warpfac) >= game.energy:
4142 # Insufficient power for trip
4145 prout(_("Engineering to bridge--"))
4146 if not game.shldup or 0.5*wcourse.power(game.warpfac) > game.energy:
4147 iwarp = (game.energy/(wcourse.distance+0.05)) ** 0.333333333
4149 prout(_("We can't do it, Captain. We don't have enough energy."))
4151 proutn(_("We don't have enough energy, but we could do it at warp %d") % iwarp)
4154 prout(_("if you'll lower the shields."))
4158 prout(_("We haven't the energy to go that far with the shields up."))
4160 # Make sure enough time is left for the trip
4161 game.optime = wcourse.time(game.warpfac)
4162 if game.optime >= 0.8*game.state.remtime:
4164 prout(_("First Officer Spock- \"Captain, I compute that such"))
4165 proutn(_(" a trip would require approximately %2.0f") %
4166 (100.0*game.optime/game.state.remtime))
4167 prout(_(" percent of our"))
4168 proutn(_(" remaining time. Are you sure this is wise?\" "))
4174 if game.warpfac > 6.0:
4175 # Decide if engine damage will occur
4176 # ESR: Seems wrong. Probability of damage goes *down* with distance?
4177 prob = wcourse.distance*(6.0-game.warpfac)**2/66.666666666
4178 if prob > randreal():
4180 wcourse.distance = randreal(wcourse.distance)
4181 # Decide if time warp will occur
4182 if 0.5*wcourse.distance*math.pow(7.0,game.warpfac-10.0) > randreal():
4184 if game.idebug and game.warpfac==10 and not twarp:
4186 proutn("=== Force time warp? ")
4190 # If time warp or engine damage, check path
4191 # If it is obstructed, don't do warp or damage
4192 look = wcourse.moves
4196 w = wcourse.sector()
4197 if not w.valid_sector():
4199 if game.quad[w.i][w.j] != '.':
4203 # Activate Warp Engines and pay the cost
4204 imove(wcourse, noattack=False)
4207 game.energy -= wcourse.power(game.warpfac)
4208 if game.energy <= 0:
4210 game.optime = wcourse.time(game.warpfac)
4214 game.damage[DWARPEN] = game.damfac * randreal(1.0, 4.0)
4216 prout(_("Engineering to bridge--"))
4217 prout(_(" Scott here. The warp engines are damaged."))
4218 prout(_(" We'll have to reduce speed to warp 4."))
4223 "Change the warp factor."
4225 key=scanner.nexttok()
4229 proutn(_("Warp factor- "))
4233 if game.damage[DWARPEN] > 10.0:
4234 prout(_("Warp engines inoperative."))
4236 if damaged(DWARPEN) and scanner.real > 4.0:
4237 prout(_("Engineer Scott- \"I'm doing my best, Captain,"))
4238 prout(_(" but right now we can only go warp 4.\""))
4240 if scanner.real > 10.0:
4241 prout(_("Helmsman Sulu- \"Our top speed is warp 10, Captain.\""))
4243 if scanner.real < 1.0:
4244 prout(_("Helmsman Sulu- \"We can't go below warp 1, Captain.\""))
4246 oldfac = game.warpfac
4247 game.warpfac = scanner.real
4248 if game.warpfac <= oldfac or game.warpfac <= 6.0:
4249 prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\"") %
4252 if game.warpfac < 8.00:
4253 prout(_("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\""))
4255 if game.warpfac == 10.0:
4256 prout(_("Engineer Scott- \"Aye, Captain, we'll try it.\""))
4258 prout(_("Engineer Scott- \"Aye, Captain, but our engines may not take it.\""))
4262 "Cope with being tossed out of quadrant by supernova or yanked by beam."
4264 # is captain on planet?
4266 if damaged(DTRANSP):
4269 prout(_("Scotty rushes to the transporter controls."))
4271 prout(_("But with the shields up it's hopeless."))
4273 prouts(_("His desperate attempt to rescue you . . ."))
4278 prout(_("SUCCEEDS!"))
4281 proutn(_("The crystals mined were "))
4289 # Check to see if captain in shuttle craft
4294 # Inform captain of attempt to reach safety
4298 prouts(_("***RED ALERT! RED ALERT!"))
4300 proutn(_("The %s has stopped in a quadrant containing") % crmshp())
4301 prouts(_(" a supernova."))
4303 prout(_("***Emergency automatic override attempts to hurl ")+crmshp())
4304 prout(_("safely out of quadrant."))
4305 if not damaged(DRADIO):
4306 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
4307 # Try to use warp engines
4308 if damaged(DWARPEN):
4310 prout(_("Warp engines damaged."))
4313 game.warpfac = randreal(6.0, 8.0)
4314 prout(_("Warp factor set to %d") % int(game.warpfac))
4315 power = 0.75*game.energy
4316 dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1))
4317 dist = max(dist, randreal(math.sqrt(2)))
4318 bugout = course(bearing=randreal(12), distance=dist) # How dumb!
4319 game.optime = bugout.time(game.warpfac)
4321 game.inorbit = False
4322 warp(bugout, involuntary=True)
4324 # This is bad news, we didn't leave quadrant.
4328 prout(_("Insufficient energy to leave quadrant."))
4331 # Repeat if another snova
4332 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
4334 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
4335 finish(FWON) # Snova killed remaining enemy.
4338 "Let's do the time warp again."
4339 prout(_("***TIME WARP ENTERED."))
4340 if game.state.snap and withprob(0.5):
4342 prout(_("You are traveling backwards in time %d stardates.") %
4343 int(game.state.date-game.snapsht.date))
4344 game.state = game.snapsht
4345 game.state.snap = False
4346 if len(game.state.kcmdr):
4347 schedule(FTBEAM, expran(game.intime/len(game.state.kcmdr)))
4348 schedule(FBATTAK, expran(0.3*game.intime))
4349 schedule(FSNOVA, expran(0.5*game.intime))
4350 # next snapshot will be sooner
4351 schedule(FSNAP, expran(0.25*game.state.remtime))
4353 if game.state.nscrem:
4354 schedule(FSCMOVE, 0.2777)
4358 game.battle.invalidate()
4359 # Make sure Galileo is consistant -- Snapshot may have been taken
4360 # when on planet, which would give us two Galileos!
4362 for l in range(game.inplan):
4363 if game.state.planets[l].known == "shuttle_down":
4365 if game.iscraft == "onship" and game.ship=='E':
4366 prout(_("Chekov- \"Security reports the Galileo has disappeared, Sir!"))
4367 game.iscraft = "offship"
4368 # Likewise, if in the original time the Galileo was abandoned, but
4369 # was on ship earlier, it would have vanished -- let's restore it.
4370 if game.iscraft == "offship" and not gotit and game.damage[DSHUTTL] >= 0.0:
4371 prout(_("Chekov- \"Security reports the Galileo has reappeared in the dock!\""))
4372 game.iscraft = "onship"
4373 # There used to be code to do the actual reconstrction here,
4374 # but the starchart is now part of the snapshotted galaxy state.
4375 prout(_("Spock has reconstructed a correct star chart from memory"))
4377 # Go forward in time
4378 game.optime = expran(0.5*game.intime)
4379 prout(_("You are traveling forward in time %d stardates.") % int(game.optime))
4380 # cheat to make sure no tractor beams occur during time warp
4381 postpone(FTBEAM, game.optime)
4382 game.damage[DRADIO] += game.optime
4384 events() # Stas Sergeev added this -- do pending events
4387 "Launch deep-space probe."
4388 # New code to launch a deep space probe
4389 if game.nprobes == 0:
4392 if game.ship == 'E':
4393 prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\""))
4395 prout(_("Ye Faerie Queene has no deep space probes."))
4400 prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\""))
4402 if is_scheduled(FDSPROB):
4405 if damaged(DRADIO) and game.condition != "docked":
4406 prout(_("Spock- \"Records show the previous probe has not yet"))
4407 prout(_(" reached its destination.\""))
4409 prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""))
4411 key = scanner.nexttok()
4413 if game.nprobes == 1:
4414 prout(_("1 probe left."))
4416 prout(_("%d probes left") % game.nprobes)
4417 proutn(_("Are you sure you want to fire a probe? "))
4420 game.isarmed = False
4421 if key == "IHALPHA" and scanner.token == "armed":
4423 key = scanner.nexttok()
4424 elif key == "IHEOL":
4425 proutn(_("Arm NOVAMAX warhead? "))
4427 elif key == "IHREAL": # first element of course
4428 scanner.push(scanner.token)
4430 game.probe = getcourse(isprobe=True)
4434 schedule(FDSPROB, 0.01) # Time to move one sector
4435 prout(_("Ensign Chekov- \"The deep space probe is launched, Captain.\""))
4440 "Yell for help from nearest starbase."
4441 # There's more than one way to move in this game!
4443 # Test for conditions which prevent calling for help
4444 if game.condition == "docked":
4445 prout(_("Lt. Uhura- \"But Captain, we're already docked.\""))
4448 prout(_("Subspace radio damaged."))
4450 if not game.state.baseq:
4451 prout(_("Lt. Uhura- \"Captain, I'm not getting any response from Starbase.\""))
4454 prout(_("You must be aboard the %s.") % crmshp())
4456 # OK -- call for help from nearest starbase
4459 # There's one in this quadrant
4460 ddist = (game.base - game.sector).distance()
4462 ibq = None # Force base-quadrant game to persist past loop
4464 for ibq in game.state.baseq:
4465 xdist = QUADSIZE * (ibq - game.quadrant).distance()
4469 prout(_("No starbases remain. You are alone in a hostile galaxy."))
4471 # Since starbase not in quadrant, set up new quadrant
4474 # dematerialize starship
4475 game.quad[game.sector.i][game.sector.j]='.'
4476 proutn(_("Starbase in Quadrant %s responds--%s dematerializes") \
4477 % (game.quadrant, crmshp()))
4478 game.sector.invalidate()
4479 for m in range(1, 5+1):
4480 w = game.base.scatter()
4481 if w.valid_sector() and game.quad[w.i][w.j]=='.':
4482 # found one -- finish up
4485 if not game.sector.is_valid():
4486 prout(_("You have been lost in space..."))
4487 finish(FMATERIALIZE)
4489 # Give starbase three chances to rematerialize starship
4490 probf = math.pow((1.0 - math.pow(0.98,ddist)), 0.33333333)
4491 for m in range(1, 3+1):
4492 if m == 1: proutn(_("1st"))
4493 elif m == 2: proutn(_("2nd"))
4494 elif m == 3: proutn(_("3rd"))
4495 proutn(_(" attempt to re-materialize ") + crmshp())
4496 game.quad[game.sector.i][game.sector.j]=('-','o','O')[m-1]
4499 if randreal() > probf:
4503 curses.delay_output(500)
4505 game.quad[game.sector.i][game.sector.j]='?'
4508 setwnd(message_window)
4509 finish(FMATERIALIZE)
4511 game.quad[game.sector.i][game.sector.j]=game.ship
4513 prout(_("succeeds."))
4517 prout(_("Lt. Uhura- \"Captain, we made it!\""))
4522 if game.condition=="docked":
4524 prout(_("You cannot abandon Ye Faerie Queene."))
4527 # Must take shuttle craft to exit
4528 if game.damage[DSHUTTL]==-1:
4529 prout(_("Ye Faerie Queene has no shuttle craft."))
4531 if game.damage[DSHUTTL]<0:
4532 prout(_("Shuttle craft now serving Big Macs."))
4534 if game.damage[DSHUTTL]>0:
4535 prout(_("Shuttle craft damaged."))
4538 prout(_("You must be aboard the ship."))
4540 if game.iscraft != "onship":
4541 prout(_("Shuttle craft not currently available."))
4543 # Emit abandon ship messages
4545 prouts(_("***ABANDON SHIP! ABANDON SHIP!"))
4547 prouts(_("***ALL HANDS ABANDON SHIP!"))
4549 prout(_("Captain and crew escape in shuttle craft."))
4550 if not game.state.baseq:
4551 # Oops! no place to go...
4554 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
4556 if not (game.options & OPTION_WORLDS) and not damaged(DTRANSP):
4557 prout(_("Remainder of ship's complement beam down"))
4558 prout(_("to nearest habitable planet."))
4559 elif q.planet != None and not damaged(DTRANSP):
4560 prout(_("Remainder of ship's complement beam down to %s.") %
4563 prout(_("Entire crew of %d left to die in outer space.") %
4565 game.casual += game.state.crew
4566 game.abandoned += game.state.crew
4567 # If at least one base left, give 'em the Faerie Queene
4569 game.icrystl = False # crystals are lost
4570 game.nprobes = 0 # No probes
4571 prout(_("You are captured by Klingons and released to"))
4572 prout(_("the Federation in a prisoner-of-war exchange."))
4573 nb = randrange(len(game.state.baseq))
4574 # Set up quadrant and position FQ adjacient to base
4575 if not game.quadrant == game.state.baseq[nb]:
4576 game.quadrant = game.state.baseq[nb]
4577 game.sector.i = game.sector.j = 5
4580 # position next to base by trial and error
4581 game.quad[game.sector.i][game.sector.j] = '.'
4583 for l in range(QUADSIZE):
4584 game.sector = game.base.scatter()
4585 if game.sector.valid_sector() and \
4586 game.quad[game.sector.i][game.sector.j] == '.':
4589 break # found a spot
4590 game.sector.i=QUADSIZE/2
4591 game.sector.j=QUADSIZE/2
4593 # Get new commission
4594 game.quad[game.sector.i][game.sector.j] = game.ship = 'F'
4595 game.state.crew = FULLCREW
4596 prout(_("Starfleet puts you in command of another ship,"))
4597 prout(_("the Faerie Queene, which is antiquated but,"))
4598 prout(_("still useable."))
4600 prout(_("The dilithium crystals have been moved."))
4602 game.iscraft = "offship" # Galileo disappears
4604 game.condition="docked"
4605 for l in range(NDEVICES):
4606 game.damage[l] = 0.0
4607 game.damage[DSHUTTL] = -1
4608 game.energy = game.inenrg = 3000.0
4609 game.shield = game.inshld = 1250.0
4610 game.torps = game.intorps = 6
4611 game.lsupres=game.inlsr=3.0
4614 game.brigfree = game.brigcapacity = 300
4617 # Code from planets.c begins here.
4620 "Abort a lengthy operation if an event interrupts it."
4623 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.justin:
4628 "Report on (uninhabited) planets in the galaxy."
4632 prout(_("Spock- \"Planet report follows, Captain.\""))
4634 for i in range(game.inplan):
4635 if game.state.planets[i].pclass == "destroyed":
4637 if (game.state.planets[i].known != "unknown" \
4638 and not game.state.planets[i].inhabited) \
4641 if game.idebug and game.state.planets[i].known=="unknown":
4642 proutn("(Unknown) ")
4643 proutn(_("Quadrant %s") % game.state.planets[i].quadrant)
4644 proutn(_(" class "))
4645 proutn(game.state.planets[i].pclass)
4647 if game.state.planets[i].crystals != "present":
4649 prout(_("dilithium crystals present."))
4650 if game.state.planets[i].known=="shuttle_down":
4651 prout(_(" Shuttle Craft Galileo on surface."))
4653 prout(_("No information available."))
4656 "Enter standard orbit."
4660 prout(_("Already in standard orbit."))
4662 if damaged(DWARPEN) and damaged(DIMPULS):
4663 prout(_("Both warp and impulse engines damaged."))
4665 if not game.plnet.is_valid():
4666 prout("There is no planet in this sector.")
4668 if abs(game.sector.i-game.plnet.i)>1 or abs(game.sector.j-game.plnet.j)>1:
4669 prout(crmshp() + _(" not adjacent to planet."))
4672 game.optime = randreal(0.02, 0.05)
4673 prout(_("Helmsman Sulu- \"Entering standard orbit, Sir.\""))
4677 game.height = randreal(1400, 8600)
4678 prout(_("Sulu- \"Entered orbit at altitude %.2f kilometers.\"") % game.height)
4683 "Examine planets in this quadrant."
4684 if damaged(DSRSENS):
4685 if game.options & OPTION_TTY:
4686 prout(_("Short range sensors damaged."))
4688 if game.iplnet is None:
4689 if game.options & OPTION_TTY:
4690 prout(_("Spock- \"No planet in this quadrant, Captain.\""))
4692 if game.iplnet.known == "unknown":
4693 prout(_("Spock- \"Sensor scan for Quadrant %s-") % game.quadrant)
4695 prout(_(" Planet at Sector %s is of class %s.") %
4696 (game.plnet, game.iplnet.pclass))
4697 if game.iplnet.known=="shuttle_down":
4698 prout(_(" Sensors show Galileo still on surface."))
4699 proutn(_(" Readings indicate"))
4700 if game.iplnet.crystals != "present":
4702 prout(_(" dilithium crystals present.\""))
4703 if game.iplnet.known == "unknown":
4704 game.iplnet.known = "known"
4705 elif game.iplnet.inhabited:
4706 prout(_("Spock- \"The inhabited planet %s ") % game.iplnet.name)
4707 prout(_(" is located at Sector %s, Captain.\"") % game.plnet)
4710 "Use the transporter."
4714 if damaged(DTRANSP):
4715 prout(_("Transporter damaged."))
4716 if not damaged(DSHUTTL) and (game.iplnet.known=="shuttle_down" or game.iscraft == "onship"):
4718 proutn(_("Spock- \"May I suggest the shuttle craft, Sir?\" "))
4722 if not game.inorbit:
4723 prout(crmshp() + _(" not in standard orbit."))
4726 prout(_("Impossible to transport through shields."))
4728 if game.iplnet.known=="unknown":
4729 prout(_("Spock- \"Captain, we have no information on this planet"))
4730 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4731 prout(_(" you may not go down.\""))
4733 if not game.landed and game.iplnet.crystals=="absent":
4734 prout(_("Spock- \"Captain, I fail to see the logic in"))
4735 prout(_(" exploring a planet with no dilithium crystals."))
4736 proutn(_(" Are you sure this is wise?\" "))
4740 if not (game.options & OPTION_PLAIN):
4741 nrgneed = 50 * game.skill + game.height / 100.0
4742 if nrgneed > game.energy:
4743 prout(_("Engineering to bridge--"))
4744 prout(_(" Captain, we don't have enough energy for transportation."))
4746 if not game.landed and nrgneed * 2 > game.energy:
4747 prout(_("Engineering to bridge--"))
4748 prout(_(" Captain, we have enough energy only to transport you down to"))
4749 prout(_(" the planet, but there wouldn't be an energy for the trip back."))
4750 if game.iplnet.known == "shuttle_down":
4751 prout(_(" Although the Galileo shuttle craft may still be on a surface."))
4752 proutn(_(" Are you sure this is wise?\" "))
4757 # Coming from planet
4758 if game.iplnet.known=="shuttle_down":
4759 proutn(_("Spock- \"Wouldn't you rather take the Galileo?\" "))
4763 prout(_("Your crew hides the Galileo to prevent capture by aliens."))
4764 prout(_("Landing party assembled, ready to beam up."))
4766 prout(_("Kirk whips out communicator..."))
4767 prouts(_("BEEP BEEP BEEP"))
4769 prout(_("\"Kirk to enterprise- Lock on coordinates...energize.\""))
4772 prout(_("Scotty- \"Transporter room ready, Sir.\""))
4774 prout(_("Kirk and landing party prepare to beam down to planet surface."))
4776 prout(_("Kirk- \"Energize.\""))
4779 prouts("WWHOOOIIIIIRRRRREEEE.E.E. . . . . . .")
4781 if not withprob(0.98):
4782 prouts("BOOOIIIOOOIIOOOOIIIOIING . . .")
4784 prout(_("Scotty- \"Oh my God! I've lost them.\""))
4787 prouts(". . . . . . .E.E.EEEERRRRRIIIIIOOOHWW")
4788 game.landed = not game.landed
4789 game.energy -= nrgneed
4791 prout(_("Transport complete."))
4792 if game.landed and game.iplnet.known=="shuttle_down":
4793 prout(_("The shuttle craft Galileo is here!"))
4794 if not game.landed and game.imine:
4801 "Strip-mine a world for dilithium."
4805 prout(_("Mining party not on planet."))
4807 if game.iplnet.crystals == "mined":
4808 prout(_("This planet has already been strip-mined for dilithium."))
4810 elif game.iplnet.crystals == "absent":
4811 prout(_("No dilithium crystals on this planet."))
4814 prout(_("You've already mined enough crystals for this trip."))
4816 if game.icrystl and game.cryprob == 0.05:
4817 prout(_("With all those fresh crystals aboard the ") + crmshp())
4818 prout(_("there's no reason to mine more at this time."))
4820 game.optime = randreal(0.1, 0.3)*(ord(game.iplnet.pclass)-ord("L"))
4823 prout(_("Mining operation complete."))
4824 game.iplnet.crystals = "mined"
4825 game.imine = game.ididit = True
4828 "Use dilithium crystals."
4832 if not game.icrystl:
4833 prout(_("No dilithium crystals available."))
4835 if game.energy >= 1000:
4836 prout(_("Spock- \"Captain, Starfleet Regulations prohibit such an operation"))
4837 prout(_(" except when Condition Yellow exists."))
4839 prout(_("Spock- \"Captain, I must warn you that loading"))
4840 prout(_(" raw dilithium crystals into the ship's power"))
4841 prout(_(" system may risk a severe explosion."))
4842 proutn(_(" Are you sure this is wise?\" "))
4847 prout(_("Engineering Officer Scott- \"(GULP) Aye Sir."))
4848 prout(_(" Mr. Spock and I will try it.\""))
4850 prout(_("Spock- \"Crystals in place, Sir."))
4851 prout(_(" Ready to activate circuit.\""))
4853 prouts(_("Scotty- \"Keep your fingers crossed, Sir!\""))
4855 if withprob(game.cryprob):
4856 prouts(_(" \"Activating now! - - No good! It's***"))
4858 prouts(_("***RED ALERT! RED A*L********************************"))
4861 prouts(_("****************** KA-BOOM!!!! *******************"))
4865 game.energy += randreal(5000.0, 5500.0)
4866 prouts(_(" \"Activating now! - - "))
4867 prout(_("The instruments"))
4868 prout(_(" are going crazy, but I think it's"))
4869 prout(_(" going to work!! Congratulations, Sir!\""))
4874 "Use shuttlecraft for planetary jaunt."
4877 if damaged(DSHUTTL):
4878 if game.damage[DSHUTTL] == -1.0:
4879 if game.inorbit and game.iplnet.known == "shuttle_down":
4880 prout(_("Ye Faerie Queene has no shuttle craft bay to dock it at."))
4882 prout(_("Ye Faerie Queene had no shuttle craft."))
4883 elif game.damage[DSHUTTL] > 0:
4884 prout(_("The Galileo is damaged."))
4885 else: # game.damage[DSHUTTL] < 0
4886 prout(_("Shuttle craft is now serving Big Macs."))
4888 if not game.inorbit:
4889 prout(crmshp() + _(" not in standard orbit."))
4891 if (game.iplnet.known != "shuttle_down") and game.iscraft != "onship":
4892 prout(_("Shuttle craft not currently available."))
4894 if not game.landed and game.iplnet.known=="shuttle_down":
4895 prout(_("You will have to beam down to retrieve the shuttle craft."))
4897 if game.shldup or game.condition == "docked":
4898 prout(_("Shuttle craft cannot pass through shields."))
4900 if game.iplnet.known=="unknown":
4901 prout(_("Spock- \"Captain, we have no information on this planet"))
4902 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4903 prout(_(" you may not fly down.\""))
4905 game.optime = 3.0e-5*game.height
4906 if game.optime >= 0.8*game.state.remtime:
4907 prout(_("First Officer Spock- \"Captain, I compute that such"))
4908 proutn(_(" a maneuver would require approximately %2d%% of our") % \
4909 int(100*game.optime/game.state.remtime))
4910 prout(_("remaining time."))
4911 proutn(_("Are you sure this is wise?\" "))
4917 if game.iscraft == "onship":
4919 if not damaged(DTRANSP):
4920 proutn(_("Spock- \"Would you rather use the transporter?\" "))
4924 proutn(_("Shuttle crew"))
4926 proutn(_("Rescue party"))
4927 prout(_(" boards Galileo and swoops toward planet surface."))
4928 game.iscraft = "offship"
4932 game.iplnet.known="shuttle_down"
4933 prout(_("Trip complete."))
4936 # Ready to go back to ship
4937 prout(_("You and your mining party board the"))
4938 prout(_("shuttle craft for the trip back to the Enterprise."))
4940 prouts(_("The short hop begins . . ."))
4942 game.iplnet.known="known"
4948 game.iscraft = "onship"
4954 prout(_("Trip complete."))
4957 # Kirk on ship and so is Galileo
4958 prout(_("Mining party assembles in the hangar deck,"))
4959 prout(_("ready to board the shuttle craft \"Galileo\"."))
4961 prouts(_("The hangar doors open; the trip begins."))
4964 game.iscraft = "offship"
4967 game.iplnet.known = "shuttle_down"
4970 prout(_("Trip complete."))
4974 "Use the big zapper."
4978 if game.ship != 'E':
4979 prout(_("Ye Faerie Queene has no death ray."))
4981 if len(game.enemies)==0:
4982 prout(_("Sulu- \"But Sir, there are no enemies in this quadrant.\""))
4985 prout(_("Death Ray is damaged."))
4987 prout(_("Spock- \"Captain, the 'Experimental Death Ray'"))
4988 prout(_(" is highly unpredictible. Considering the alternatives,"))
4989 proutn(_(" are you sure this is wise?\" "))
4992 prout(_("Spock- \"Acknowledged.\""))
4995 prouts(_("WHOOEE ... WHOOEE ... WHOOEE ... WHOOEE"))
4997 prout(_("Crew scrambles in emergency preparation."))
4998 prout(_("Spock and Scotty ready the death ray and"))
4999 prout(_("prepare to channel all ship's power to the device."))
5001 prout(_("Spock- \"Preparations complete, sir.\""))
5002 prout(_("Kirk- \"Engage!\""))
5004 prouts(_("WHIRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"))
5007 if game.options & OPTION_PLAIN:
5011 prouts(_("Sulu- \"Captain! It's working!\""))
5013 while len(game.enemies) > 0:
5014 deadkl(game.enemies[1].location, game.quad[game.enemies[1].location.i][game.enemies[1].location.j],game.enemies[1].location)
5015 prout(_("Ensign Chekov- \"Congratulations, Captain!\""))
5016 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
5018 if (game.options & OPTION_PLAIN) == 0:
5019 prout(_("Spock- \"Captain, I believe the `Experimental Death Ray'"))
5021 prout(_(" is still operational.\""))
5023 prout(_(" has been rendered nonfunctional.\""))
5024 game.damage[DDRAY] = 39.95
5026 r = randreal() # Pick failure method
5028 prouts(_("Sulu- \"Captain! It's working!\""))
5030 prouts(_("***RED ALERT! RED ALERT!"))
5032 prout(_("***MATTER-ANTIMATTER IMPLOSION IMMINENT!"))
5034 prouts(_("***RED ALERT! RED A*L********************************"))
5037 prouts(_("****************** KA-BOOM!!!! *******************"))
5042 prouts(_("Sulu- \"Captain! Yagabandaghangrapl, brachriigringlanbla!\""))
5044 prout(_("Lt. Uhura- \"Graaeek! Graaeek!\""))
5046 prout(_("Spock- \"Fascinating! . . . All humans aboard"))
5047 prout(_(" have apparently been transformed into strange mutations."))
5048 prout(_(" Vulcans do not seem to be affected."))
5050 prout(_("Kirk- \"Raauch! Raauch!\""))
5054 prouts(_("Sulu- \"Captain! It's --WHAT?!?!\""))
5056 proutn(_("Spock- \"I believe the word is"))
5057 prouts(_(" *ASTONISHING*"))
5058 prout(_(" Mr. Sulu."))
5059 for i in range(QUADSIZE):
5060 for j in range(QUADSIZE):
5061 if game.quad[i][j] == '.':
5062 game.quad[i][j] = '?'
5063 prout(_(" Captain, our quadrant is now infested with"))
5064 prouts(_(" - - - - - - *THINGS*."))
5066 prout(_(" I have no logical explanation.\""))
5068 prouts(_("Sulu- \"Captain! The Death Ray is creating tribbles!\""))
5070 prout(_("Scotty- \"There are so many tribbles down here"))
5071 prout(_(" in Engineering, we can't move for 'em, Captain.\""))
5075 # Code from reports.c begins here
5077 def attackreport(curt):
5078 "eport status of bases under attack."
5080 if is_scheduled(FCDBAS):
5081 prout(_("Starbase in Quadrant %s is currently under Commander attack.") % game.battle)
5082 prout(_("It can hold out until Stardate %d.") % int(scheduled(FCDBAS)))
5083 elif game.isatb == 1:
5084 prout(_("Starbase in Quadrant %s is under Super-commander attack.") % game.state.kscmdr)
5085 prout(_("It can hold out until Stardate %d.") % int(scheduled(FSCDBAS)))
5087 prout(_("No Starbase is currently under attack."))
5089 if is_scheduled(FCDBAS):
5090 proutn(_("Base in %s attacked by C. Alive until %.1f") % (game.battle, scheduled(FCDBAS)))
5092 proutn(_("Base in %s attacked by S. Alive until %.1f") % (game.state.kscmdr, scheduled(FSCDBAS)))
5096 # report on general game status
5098 s1 = (game.thawed and _("thawed ")) or ""
5099 s2 = {1:"short", 2:"medium", 4:"long"}[game.length]
5100 s3 = (None, _("novice"), _("fair"),
5101 _("good"), _("expert"), _("emeritus"))[game.skill]
5102 prout(_("You %s a %s%s %s game.") % ((_("were playing"), _("are playing"))[game.alldone], s1, s2, s3))
5103 if game.skill>SKILL_GOOD and game.thawed and not game.alldone:
5104 prout(_("No plaque is allowed."))
5106 prout(_("This is tournament game %d.") % game.tourn)
5107 prout(_("Your secret password is \"%s\"") % game.passwd)
5108 proutn(_("%d of %d Klingons have been killed") % (((game.inkling + game.incom + game.inscom) - (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)),
5109 (game.inkling + game.incom + game.inscom)))
5110 if game.incom - len(game.state.kcmdr):
5111 prout(_(", including %d Commander%s.") % (game.incom - len(game.state.kcmdr), (_("s"), "")[(game.incom - len(game.state.kcmdr))==1]))
5112 elif game.inkling - game.state.remkl + (game.inscom - game.state.nscrem) > 0:
5113 prout(_(", but no Commanders."))
5116 if game.skill > SKILL_FAIR:
5117 prout(_("The Super Commander has %sbeen destroyed.") % ("", _("not "))[game.state.nscrem])
5118 if len(game.state.baseq) != game.inbase:
5120 if game.inbase-len(game.state.baseq)==1:
5121 proutn(_("has been 1 base"))
5123 proutn(_("have been %d bases") % (game.inbase-len(game.state.baseq)))
5124 prout(_(" destroyed, %d remaining.") % len(game.state.baseq))
5126 prout(_("There are %d bases.") % game.inbase)
5127 if communicating() or game.iseenit:
5128 # Don't report this if not seen and
5129 # either the radio is dead or not at base!
5133 prout(_("%d casualt%s suffered so far.") % (game.casual, ("y", "ies")[game.casual!=1]))
5134 if game.brigcapacity != game.brigfree:
5135 embriggened = brigcapacity-brigfree
5136 if embriggened == 1:
5137 prout(_("1 Klingon in brig"))
5139 prout(_("%d Klingons in brig.") % embriggened)
5140 if game.kcaptured == 0:
5142 elif game.kcaptured == 1:
5143 prout(_("1 captured Klingon turned in to Starfleet."))
5145 prout(_("%d captured Klingons turned in to Star Fleet.") % game.kcaptured)
5147 prout(_("There were %d call%s for help.") % (game.nhelp, ("" , _("s"))[game.nhelp!=1]))
5148 if game.ship == 'E':
5149 proutn(_("You have "))
5151 proutn("%d" % (game.nprobes))
5154 proutn(_(" deep space probe"))
5158 if communicating() and is_scheduled(FDSPROB):
5160 proutn(_("An armed deep space probe is in "))
5162 proutn(_("A deep space probe is in "))
5163 prout("Quadrant %s." % game.probe.quadrant())
5165 if game.cryprob <= .05:
5166 prout(_("Dilithium crystals aboard ship... not yet used."))
5170 while game.cryprob > ai:
5173 prout(_("Dilithium crystals have been used %d time%s.") % \
5174 (i, (_("s"), "")[i==1]))
5178 "Long-range sensor scan."
5179 if damaged(DLRSENS):
5180 # Now allow base's sensors if docked
5181 if game.condition != "docked":
5183 prout(_("LONG-RANGE SENSORS DAMAGED."))
5186 prout(_("Starbase's long-range scan"))
5188 prout(_("Long-range scan"))
5189 for x in range(game.quadrant.i-1, game.quadrant.i+2):
5192 for y in range(game.quadrant.j-1, game.quadrant.j+2):
5193 if not Coord(x, y).valid_quadrant():
5197 if not damaged(DRADIO):
5198 game.state.galaxy[x][y].charted = True
5199 game.state.chart[x][y].klingons = game.state.galaxy[x][y].klingons
5200 game.state.chart[x][y].starbase = game.state.galaxy[x][y].starbase
5201 game.state.chart[x][y].stars = game.state.galaxy[x][y].stars
5202 if not silent and game.state.galaxy[x][y].supernova:
5205 proutn(" %3d" % (game.state.chart[x][y].klingons*100 + game.state.chart[x][y].starbase * 10 + game.state.chart[x][y].stars))
5213 for i in range(NDEVICES):
5216 prout(_("\tDEVICE\t\t\t-REPAIR TIMES-"))
5217 prout(_("\t\t\tIN FLIGHT\t\tDOCKED"))
5219 prout(" %-26s\t%8.2f\t\t%8.2f" % (device[i],
5220 game.damage[i]+0.05,
5221 DOCKFAC*game.damage[i]+0.005))
5223 prout(_("All devices functional."))
5226 "Update the chart in the Enterprise's computer from galaxy data."
5227 game.lastchart = game.state.date
5228 for i in range(GALSIZE):
5229 for j in range(GALSIZE):
5230 if game.state.galaxy[i][j].charted:
5231 game.state.chart[i][j].klingons = game.state.galaxy[i][j].klingons
5232 game.state.chart[i][j].starbase = game.state.galaxy[i][j].starbase
5233 game.state.chart[i][j].stars = game.state.galaxy[i][j].stars
5236 "Display the star chart."
5238 if (game.options & OPTION_AUTOSCAN):
5240 if not damaged(DRADIO):
5242 if game.lastchart < game.state.date and game.condition == "docked":
5243 prout(_("Spock- \"I revised the Star Chart from the starbase's records.\""))
5245 prout(_(" STAR CHART FOR THE KNOWN GALAXY"))
5246 if game.state.date > game.lastchart:
5247 prout(_("(Last surveillance update %d stardates ago).") % ((int)(game.state.date-game.lastchart)))
5248 prout(" 1 2 3 4 5 6 7 8")
5249 for i in range(GALSIZE):
5250 proutn("%d |" % (i+1))
5251 for j in range(GALSIZE):
5252 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5256 if game.state.galaxy[i][j].supernova:
5258 elif not game.state.galaxy[i][j].charted and game.state.galaxy[i][j].starbase:
5260 elif game.state.galaxy[i][j].charted:
5261 show = "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars)
5265 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5273 def sectscan(goodScan, i, j):
5274 "Light up an individual dot in a sector."
5275 if goodScan or (abs(i-game.sector.i)<= 1 and abs(j-game.sector.j) <= 1):
5276 if game.quad[i][j] in ('E', 'F'):
5277 textcolor({"green":GREEN,
5281 "dead":BROWN}[game.condition])
5283 textcolor({'?':LIGHTMAGENTA,
5289 }.get(game.quad[i][j], DEFAULT))
5292 proutn("%c " % game.quad[i][j])
5298 "Emit status report lines"
5299 if not req or req == 1:
5300 prstat(_("Stardate"), _("%.1f, Time Left %.2f") \
5301 % (game.state.date, game.state.remtime))
5302 if not req or req == 2:
5303 if game.condition != "docked":
5305 prstat(_("Condition"), _("%s, %i DAMAGES") % \
5306 (game.condition.upper(), sum([x > 0 for x in game.damage])))
5308 prout(_(", CLOAKED"))
5309 if not req or req == 3:
5310 prstat(_("Position"), "%s , %s" % (game.quadrant, game.sector))
5311 if not req or req == 4:
5312 if damaged(DLIFSUP):
5313 if game.condition == "docked":
5314 s = _("DAMAGED, Base provides")
5316 s = _("DAMAGED, reserves=%4.2f") % game.lsupres
5319 prstat(_("Life Support"), s)
5320 if not req or req == 5:
5321 prstat(_("Warp Factor"), "%.1f" % game.warpfac)
5322 if not req or req == 6:
5324 if game.icrystl and (game.options & OPTION_SHOWME):
5325 extra = _(" (have crystals)")
5326 prstat(_("Energy"), "%.2f%s" % (game.energy, extra))
5327 if not req or req == 7:
5328 prstat(_("Torpedoes"), "%d" % (game.torps))
5329 if not req or req == 8:
5330 if damaged(DSHIELD):
5336 data = _(" %d%% %.1f units") \
5337 % (int((100.0*game.shield)/game.inshld + 0.5), game.shield)
5338 prstat(_("Shields"), s+data)
5339 if not req or req == 9:
5340 prstat(_("Klingons Left"), "%d" \
5341 % (game.state.remkl+len(game.state.kcmdr)+game.state.nscrem))
5342 if not req or req == 10:
5343 if game.options & OPTION_WORLDS:
5344 plnet = game.state.galaxy[game.quadrant.i][game.quadrant.j].planet
5345 if plnet and plnet.inhabited:
5346 prstat(_("Major system"), plnet.name)
5348 prout(_("Sector is uninhabited"))
5349 elif not req or req == 11:
5350 attackreport(not req)
5353 "Request specified status data, a historical relic from slow TTYs."
5354 requests = ("da","co","po","ls","wa","en","to","sh","kl","sy", "ti")
5355 while scanner.nexttok() == "IHEOL":
5356 proutn(_("Information desired? "))
5358 if scanner.token in requests:
5359 status(requests.index(scanner.token))
5361 prout(_("UNRECOGNIZED REQUEST. Legal requests are:"))
5362 prout((" date, condition, position, lsupport, warpfactor,"))
5363 prout((" energy, torpedoes, shields, klingons, system, time."))
5368 if damaged(DSRSENS):
5369 # Allow base's sensors if docked
5370 if game.condition != "docked":
5371 prout(_(" S.R. SENSORS DAMAGED!"))
5374 prout(_(" [Using Base's sensors]"))
5376 prout(_(" Short-range scan"))
5377 if goodScan and not damaged(DRADIO):
5378 game.state.chart[game.quadrant.i][game.quadrant.j].klingons = game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons
5379 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase
5380 game.state.chart[game.quadrant.i][game.quadrant.j].stars = game.state.galaxy[game.quadrant.i][game.quadrant.j].stars
5381 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
5382 prout(" 1 2 3 4 5 6 7 8 9 10")
5383 if game.condition != "docked":
5385 for i in range(QUADSIZE):
5386 proutn("%2d " % (i+1))
5387 for j in range(QUADSIZE):
5388 sectscan(goodScan, i, j)
5392 "Use computer to get estimated time of arrival for a warp jump."
5393 w1 = Coord(); w2 = Coord()
5395 if damaged(DCOMPTR):
5396 prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR."))
5399 if scanner.nexttok() != "IHREAL":
5402 proutn(_("Destination quadrant and/or sector? "))
5403 if scanner.nexttok()!="IHREAL":
5406 w1.j = int(scanner.real-0.5)
5407 if scanner.nexttok() != "IHREAL":
5410 w1.i = int(scanner.real-0.5)
5411 if scanner.nexttok() == "IHREAL":
5412 w2.j = int(scanner.real-0.5)
5413 if scanner.nexttok() != "IHREAL":
5416 w2.i = int(scanner.real-0.5)
5418 if game.quadrant.j>w1.i:
5422 if game.quadrant.i>w1.j:
5426 if not w1.valid_quadrant() or not w2.valid_sector():
5429 dist = math.sqrt((w1.j-game.quadrant.j+(w2.j-game.sector.j)/(QUADSIZE*1.0))**2+
5430 (w1.i-game.quadrant.i+(w2.i-game.sector.i)/(QUADSIZE*1.0))**2)
5433 prout(_("Answer \"no\" if you don't know the value:"))
5436 proutn(_("Time or arrival date? "))
5437 if scanner.nexttok()=="IHREAL":
5438 ttime = scanner.real
5439 if ttime > game.state.date:
5440 ttime -= game.state.date # Actually a star date
5441 twarp=(math.floor(math.sqrt((10.0*dist)/ttime)*10.0)+1.0)/10.0
5442 if ttime <= 1e-10 or twarp > 10:
5443 prout(_("We'll never make it, sir."))
5450 proutn(_("Warp factor? "))
5451 if scanner.nexttok()== "IHREAL":
5453 twarp = scanner.real
5454 if twarp<1.0 or twarp > 10.0:
5458 prout(_("Captain, certainly you can give me one of these."))
5461 ttime = (10.0*dist)/twarp**2
5462 tpower = dist*twarp*twarp*twarp*(game.shldup+1)
5463 if tpower >= game.energy:
5464 prout(_("Insufficient energy, sir."))
5465 if not game.shldup or tpower > game.energy*2.0:
5468 proutn(_("New warp factor to try? "))
5469 if scanner.nexttok() == "IHREAL":
5471 twarp = scanner.real
5472 if twarp<1.0 or twarp > 10.0:
5480 prout(_("But if you lower your shields,"))
5481 proutn(_("remaining"))
5484 proutn(_("Remaining"))
5485 prout(_(" energy will be %.2f.") % (game.energy-tpower))
5487 prout(_("And we will arrive at stardate %.2f.") % (game.state.date+ttime))
5489 prout(_("Any warp speed is adequate."))
5491 prout(_("Minimum warp needed is %.2f,") % (twarp))
5492 prout(_("and we will arrive at stardate %.2f.") % (game.state.date+ttime))
5493 if game.state.remtime < ttime:
5494 prout(_("Unfortunately, the Federation will be destroyed by then."))
5496 prout(_("You'll be taking risks at that speed, Captain"))
5497 if (game.isatb==1 and game.state.kscmdr == w1 and \
5498 scheduled(FSCDBAS)< ttime+game.state.date) or \
5499 (scheduled(FCDBAS)<ttime+game.state.date and game.battle == w1):
5500 prout(_("The starbase there will be destroyed by then."))
5501 proutn(_("New warp factor to try? "))
5502 if scanner.nexttok() == "IHREAL":
5504 twarp = scanner.real
5505 if twarp<1.0 or twarp > 10.0:
5513 # Code from setup.c begins here
5516 "Issue a historically correct banner."
5518 prout(_("-SUPER- STAR TREK"))
5520 # From the FORTRAN original
5521 # prout(_("Latest update-21 Sept 78"))
5527 scanner.push("emsave.trk")
5528 key = scanner.nexttok()
5530 proutn(_("File name: "))
5531 key = scanner.nexttok()
5532 if key != "IHALPHA":
5535 if '.' not in scanner.token:
5536 scanner.token += ".trk"
5538 fp = open(scanner.token, "wb")
5540 prout(_("Can't freeze game as file %s") % scanner.token)
5542 pickle.dump(game, fp)
5547 "Retrieve saved game."
5550 key = scanner.nexttok()
5552 proutn(_("File name: "))
5553 key = scanner.nexttok()
5554 if key != "IHALPHA":
5557 if '.' not in scanner.token:
5558 scanner.token += ".trk"
5560 fp = open(scanner.token, "rb")
5562 prout(_("Can't thaw game in %s") % scanner.token)
5564 game = pickle.load(fp)
5569 # I used <http://www.memory-alpha.org> to find planets
5570 # with references in ST:TOS. Earth and the Alpha Centauri
5571 # Colony have been omitted.
5573 # Some planets marked Class G and P here will be displayed as class M
5574 # because of the way planets are generated. This is a known bug.
5577 _("Andoria (Fesoan)"), # several episodes
5578 _("Tellar Prime (Miracht)"), # TOS: "Journey to Babel"
5579 _("Vulcan (T'Khasi)"), # many episodes
5580 _("Medusa"), # TOS: "Is There in Truth No Beauty?"
5581 _("Argelius II (Nelphia)"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5582 _("Ardana"), # TOS: "The Cloud Minders"
5583 _("Catulla (Cendo-Prae)"), # TOS: "The Way to Eden"
5584 _("Gideon"), # TOS: "The Mark of Gideon"
5585 _("Aldebaran III"), # TOS: "The Deadly Years"
5586 _("Alpha Majoris I"), # TOS: "Wolf in the Fold"
5587 _("Altair IV"), # TOS: "Amok Time
5588 _("Ariannus"), # TOS: "Let That Be Your Last Battlefield"
5589 _("Benecia"), # TOS: "The Conscience of the King"
5590 _("Beta Niobe I (Sarpeidon)"), # TOS: "All Our Yesterdays"
5591 _("Alpha Carinae II"), # TOS: "The Ultimate Computer"
5592 _("Capella IV (Kohath)"), # TOS: "Friday's Child" (Class G)
5593 _("Daran V"), # TOS: "For the World is Hollow and I Have Touched the Sky"
5594 _("Deneb II"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5595 _("Eminiar VII"), # TOS: "A Taste of Armageddon"
5596 _("Gamma Canaris IV"), # TOS: "Metamorphosis"
5597 _("Gamma Tranguli VI (Vaalel)"), # TOS: "The Apple"
5598 _("Ingraham B"), # TOS: "Operation: Annihilate"
5599 _("Janus IV"), # TOS: "The Devil in the Dark"
5600 _("Makus III"), # TOS: "The Galileo Seven"
5601 _("Marcos XII"), # TOS: "And the Children Shall Lead",
5602 _("Omega IV"), # TOS: "The Omega Glory"
5603 _("Regulus V"), # TOS: "Amok Time
5604 _("Deneva"), # TOS: "Operation -- Annihilate!"
5605 # Worlds from BSD Trek
5606 _("Rigel II"), # TOS: "Shore Leave" ("III" in BSD)
5607 _("Beta III"), # TOS: "The Return of the Archons"
5608 _("Triacus"), # TOS: "And the Children Shall Lead",
5609 _("Exo III"), # TOS: "What Are Little Girls Made Of?" (Class P)
5611 # _("Hansen's Planet"), # TOS: "The Galileo Seven"
5612 # _("Taurus IV"), # TOS: "The Galileo Seven" (class G)
5613 # _("Antos IV (Doraphane)"), # TOS: "Whom Gods Destroy", "Who Mourns for Adonais?"
5614 # _("Izar"), # TOS: "Whom Gods Destroy"
5615 # _("Tiburon"), # TOS: "The Way to Eden"
5616 # _("Merak II"), # TOS: "The Cloud Minders"
5617 # _("Coridan (Desotriana)"), # TOS: "Journey to Babel"
5618 # _("Iotia"), # TOS: "A Piece of the Action"
5622 _("S. R. Sensors"), \
5623 _("L. R. Sensors"), \
5625 _("Photon Tubes"), \
5626 _("Life Support"), \
5627 _("Warp Engines"), \
5628 _("Impulse Engines"), \
5630 _("Subspace Radio"), \
5631 _("Shuttle Craft"), \
5633 _("Navigation System"), \
5635 _("Shield Control"), \
5638 _("Cloaking Device"), \
5642 "Prepare to play, set up cosmos."
5644 # Decide how many of everything
5646 return # frozen game
5647 # Prepare the Enterprise
5648 game.alldone = game.gamewon = game.shldchg = game.shldup = False
5650 game.state.crew = FULLCREW
5651 game.energy = game.inenrg = 5000.0
5652 game.shield = game.inshld = 2500.0
5655 game.quadrant = randplace(GALSIZE)
5656 game.sector = randplace(QUADSIZE)
5657 game.torps = game.intorps = 10
5658 game.nprobes = randrange(2, 5)
5660 for i in range(NDEVICES):
5661 game.damage[i] = 0.0
5662 # Set up assorted game parameters
5663 game.battle = Coord()
5664 game.state.date = game.indate = 100.0 * randreal(20, 51)
5665 game.nkinks = game.nhelp = game.casual = game.abandoned = 0
5666 game.iscate = game.resting = game.imine = game.icrystl = game.icraft = False
5667 game.isatb = game.state.nplankl = 0
5668 game.state.starkl = game.state.basekl = game.state.nworldkl = 0
5669 game.iscraft = "onship"
5674 game.state.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
5676 game.state.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
5678 game.state.planets = [] # Planet information
5679 game.state.baseq = [] # Base quadrant coordinates
5680 game.state.kcmdr = [] # Commander quadrant coordinates
5681 game.statekscmdr = Coord() # Supercommander quadrant coordinates
5683 # Starchart is functional but we've never seen it
5684 game.lastchart = FOREVER
5685 # Put stars in the galaxy
5687 for i in range(GALSIZE):
5688 for j in range(GALSIZE):
5689 # Can't have more stars per quadrant than fit in one decimal digit,
5690 # if we do the chart representation will break.
5691 k = randrange(1, min(10, QUADSIZE**2/10))
5693 game.state.galaxy[i][j].stars = k
5694 # Locate star bases in galaxy
5696 prout("=== Allocating %d bases" % game.inbase)
5697 for i in range(game.inbase):
5700 w = randplace(GALSIZE)
5701 if not game.state.galaxy[w.i][w.j].starbase:
5704 # C version: for (j = i-1; j > 0; j--)
5705 # so it did them in the opposite order.
5706 for j in range(1, i):
5707 # Improved placement algorithm to spread out bases
5708 distq = (w - game.state.baseq[j]).distance()
5709 if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75):
5712 prout("=== Abandoning base #%d at %s" % (i, w))
5714 elif distq < 6.0 * (BASEMAX+1-game.inbase):
5716 prout("=== Saving base #%d, close to #%d" % (i, j))
5720 prout("=== Placing base #%d in quadrant %s" % (i, w))
5721 game.state.baseq.append(w)
5722 game.state.galaxy[w.i][w.j].starbase = game.state.chart[w.i][w.j].starbase = True
5723 # Position ordinary Klingon Battle Cruisers
5725 klumper = 0.25*game.skill*(9.0-game.length)+1.0
5726 if klumper > MAXKLQUAD:
5730 klump = (1.0 - r*r)*klumper
5735 w = randplace(GALSIZE)
5736 if not game.state.galaxy[w.i][w.j].supernova and \
5737 game.state.galaxy[w.i][w.j].klingons + klump <= MAXKLQUAD:
5739 game.state.galaxy[w.i][w.j].klingons += int(klump)
5742 # Position Klingon Commander Ships
5743 for i in range(game.incom):
5745 w = randplace(GALSIZE)
5746 if not welcoming(w) or w in game.state.kcmdr:
5748 if (game.state.galaxy[w.i][w.j].klingons or withprob(0.25)):
5750 game.state.galaxy[w.i][w.j].klingons += 1
5751 game.state.kcmdr.append(w)
5752 # Locate planets in galaxy
5753 for i in range(game.inplan):
5755 w = randplace(GALSIZE)
5756 if game.state.galaxy[w.i][w.j].planet is None:
5760 new.crystals = "absent"
5761 if (game.options & OPTION_WORLDS) and i < NINHAB:
5762 new.pclass = "M" # All inhabited planets are class M
5763 new.crystals = "absent"
5765 new.name = systnames[i]
5766 new.inhabited = True
5768 new.pclass = ("M", "N", "O")[randrange(0, 3)]
5770 new.crystals = "present"
5771 new.known = "unknown"
5772 new.inhabited = False
5773 game.state.galaxy[w.i][w.j].planet = new
5774 game.state.planets.append(new)
5776 for i in range(game.state.nromrem):
5777 w = randplace(GALSIZE)
5778 game.state.galaxy[w.i][w.j].romulans += 1
5779 # Place the Super-Commander if needed
5780 if game.state.nscrem > 0:
5782 w = randplace(GALSIZE)
5785 game.state.kscmdr = w
5786 game.state.galaxy[w.i][w.j].klingons += 1
5787 # Initialize times for extraneous events
5788 schedule(FSNOVA, expran(0.5 * game.intime))
5789 schedule(FTBEAM, expran(1.5 * (game.intime / len(game.state.kcmdr))))
5790 schedule(FSNAP, randreal(1.0, 2.0)) # Force an early snapshot
5791 schedule(FBATTAK, expran(0.3*game.intime))
5793 if game.state.nscrem:
5794 schedule(FSCMOVE, 0.2777)
5799 if (game.options & OPTION_WORLDS) and game.skill >= SKILL_GOOD:
5800 schedule(FDISTR, expran(1.0 + game.intime))
5805 # Place thing (in tournament game, we don't want one!)
5806 # New in SST2K: never place the Thing near a starbase.
5807 # This makes sense and avoids a special case in the old code.
5809 if game.tourn is None:
5811 thing = randplace(GALSIZE)
5812 if thing not in game.state.baseq:
5815 game.state.snap = False
5816 if game.skill == SKILL_NOVICE:
5817 prout(_("It is stardate %d. The Federation is being attacked by") % int(game.state.date))
5818 prout(_("a deadly Klingon invasion force. As captain of the United"))
5819 prout(_("Starship U.S.S. Enterprise, it is your mission to seek out"))
5820 prout(_("and destroy this invasion force of %d battle cruisers.") % ((game.inkling + game.incom + game.inscom)))
5821 prout(_("You have an initial allotment of %d stardates to complete") % int(game.intime))
5822 prout(_("your mission. As you proceed you may be given more time."))
5824 prout(_("You will have %d supporting starbases.") % (game.inbase))
5825 proutn(_("Starbase locations- "))
5827 prout(_("Stardate %d.") % int(game.state.date))
5829 prout(_("%d Klingons.") % (game.inkling + game.incom + game.inscom))
5830 prout(_("An unknown number of Romulans."))
5831 if game.state.nscrem:
5832 prout(_("And one (GULP) Super-Commander."))
5833 prout(_("%d stardates.") % int(game.intime))
5834 proutn(_("%d starbases in ") % game.inbase)
5835 for i in range(game.inbase):
5836 proutn(repr(game.state.baseq[i]))
5839 proutn(_("The Enterprise is currently in Quadrant %s") % game.quadrant)
5840 proutn(_(" Sector %s") % game.sector)
5842 prout(_("Good Luck!"))
5843 if game.state.nscrem:
5844 prout(_(" YOU'LL NEED IT."))
5847 setwnd(message_window)
5849 if len(game.enemies) - (thing == game.quadrant) - (game.tholian != None):
5851 if game.neutz: # bad luck to start in a Romulan Neutral Zone
5852 attack(torps_ok=False)
5855 "Choose your game type."
5857 game.tourn = game.length = 0
5859 game.skill = SKILL_NONE
5860 # Do not chew here, we want to use command-line tokens
5861 if not scanner.inqueue: # Can start with command line options
5862 proutn(_("Would you like a regular, tournament, or saved game? "))
5864 if scanner.sees("tournament"):
5865 while scanner.nexttok() == "IHEOL":
5866 proutn(_("Type in tournament number-"))
5867 if scanner.real == 0:
5869 continue # We don't want a blank entry
5870 game.tourn = int(round(scanner.real))
5871 random.seed(scanner.real)
5873 logfp.write("# random.seed(%d)\n" % scanner.real)
5875 if scanner.sees("saved") or scanner.sees("frozen"):
5879 if game.passwd is None:
5881 if not game.alldone:
5882 game.thawed = True # No plaque if not finished
5886 if scanner.sees("regular"):
5888 proutn(_("What is \"%s\"? ") % scanner.token)
5890 while game.length==0 or game.skill==SKILL_NONE:
5891 if scanner.nexttok() == "IHALPHA":
5892 if scanner.sees("short"):
5894 elif scanner.sees("medium"):
5896 elif scanner.sees("long"):
5898 elif scanner.sees("novice"):
5899 game.skill = SKILL_NOVICE
5900 elif scanner.sees("fair"):
5901 game.skill = SKILL_FAIR
5902 elif scanner.sees("good"):
5903 game.skill = SKILL_GOOD
5904 elif scanner.sees("expert"):
5905 game.skill = SKILL_EXPERT
5906 elif scanner.sees("emeritus"):
5907 game.skill = SKILL_EMERITUS
5909 proutn(_("What is \""))
5910 proutn(scanner.token)
5915 proutn(_("Would you like a Short, Medium, or Long game? "))
5916 elif game.skill == SKILL_NONE:
5917 proutn(_("Are you a Novice, Fair, Good, Expert, or Emeritus player? "))
5918 # Choose game options -- added by ESR for SST2K
5919 if scanner.nexttok() != "IHALPHA":
5921 proutn(_("Choose your game style (plain, almy, fancy or just press enter): "))
5923 if scanner.sees("plain"):
5924 # Approximates the UT FORTRAN version.
5925 game.options &=~ (OPTION_THOLIAN | OPTION_PLANETS | OPTION_THINGY | OPTION_PROBE | OPTION_RAMMING | OPTION_MVBADDY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS | OPTION_COLOR | OPTION_CAPTURE | OPTION_CLOAK)
5926 game.options |= OPTION_PLAIN
5927 elif scanner.sees("almy"):
5928 # Approximates Tom Almy's version.
5929 game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS | OPTION_COLOR)
5930 game.options |= OPTION_ALMY
5931 elif scanner.sees("fancy") or scanner.sees("\n"):
5933 elif len(scanner.token):
5934 proutn(_("What is \"%s\"?") % scanner.token)
5936 if game.passwd == "debug":
5938 prout("=== Debug mode enabled.")
5939 # Use parameters to generate initial values of things
5940 game.damfac = 0.5 * game.skill
5941 game.inbase = randrange(BASEMIN, BASEMAX+1)
5943 if game.options & OPTION_PLANETS:
5944 game.inplan += randrange(MAXUNINHAB/2, MAXUNINHAB+1)
5945 if game.options & OPTION_WORLDS:
5946 game.inplan += int(NINHAB)
5947 game.state.nromrem = game.inrom = randrange(2 * game.skill)
5948 game.state.nscrem = game.inscom = (game.skill > SKILL_FAIR)
5949 game.state.remtime = 7.0 * game.length
5950 game.intime = game.state.remtime
5951 game.state.remkl = game.inkling = 2.0*game.intime*((game.skill+1 - 2*randreal())*game.skill*0.1+.15)
5952 game.incom = min(MINCMDR, int(game.skill + 0.0625*game.inkling*randreal()))
5953 game.state.remres = (game.inkling+4*game.incom)*game.intime
5954 game.inresor = game.state.remres
5955 if game.inkling > 50:
5959 def dropin(iquad=None):
5960 "Drop a feature on a random dot in the current quadrant."
5962 w = randplace(QUADSIZE)
5963 if game.quad[w.i][w.j] == '.':
5965 if iquad is not None:
5966 game.quad[w.i][w.j] = iquad
5970 "Update our alert status."
5971 game.condition = "green"
5972 if game.energy < 1000.0:
5973 game.condition = "yellow"
5974 if game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons or game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans:
5975 game.condition = "red"
5977 game.condition="dead"
5980 "Drop new Klingon into current quadrant."
5981 return Enemy('K', loc=dropin(), power=randreal(300,450)+25.0*game.skill)
5984 "Sort enemies by distance so 'nearest' is meaningful."
5985 game.enemies.sort(key=lambda x: x.kdist)
5988 "Set up a new state of quadrant, for when we enter or re-enter it."
5991 game.neutz = game.inorbit = game.landed = False
5992 game.ientesc = game.iseenit = game.isviolreported = False
5993 # Create a blank quadrant
5994 game.quad = fill2d(QUADSIZE, lambda i, j: '.')
5996 # Attempt to escape Super-commander, so tbeam back!
5999 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
6000 # cope with supernova
6003 game.klhere = q.klingons
6004 game.irhere = q.romulans
6006 game.quad[game.sector.i][game.sector.j] = game.ship
6009 # Position ordinary Klingons
6010 for _i in range(game.klhere):
6012 # If we need a commander, promote a Klingon
6013 for cmdr in game.state.kcmdr:
6014 if cmdr == game.quadrant:
6015 e = game.enemies[game.klhere-1]
6016 game.quad[e.location.i][e.location.j] = 'C'
6017 e.power = randreal(950,1350) + 50.0*game.skill
6019 # If we need a super-commander, promote a Klingon
6020 if game.quadrant == game.state.kscmdr:
6022 game.quad[e.location.i][e.location.j] = 'S'
6023 e.power = randreal(1175.0, 1575.0) + 125.0*game.skill
6024 game.iscate = (game.state.remkl > 1)
6025 # Put in Romulans if needed
6026 for _i in range(q.romulans):
6027 Enemy('R', loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill)
6028 # If quadrant needs a starbase, put it in
6030 game.base = dropin('B')
6031 # If quadrant needs a planet, put it in
6033 game.iplnet = q.planet
6034 if not q.planet.inhabited:
6035 game.plnet = dropin('P')
6037 game.plnet = dropin('@')
6038 # Check for condition
6041 if game.irhere > 0 and game.klhere == 0:
6043 if not damaged(DRADIO):
6045 prout(_("LT. Uhura- \"Captain, an urgent message."))
6046 prout(_(" I'll put it on audio.\" CLICK"))
6048 prout(_("INTRUDER! YOU HAVE VIOLATED THE ROMULAN NEUTRAL ZONE."))
6049 prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!"))
6050 # Put in THING if needed
6051 if thing == game.quadrant:
6052 Enemy(etype='?', loc=dropin(),
6053 power=randreal(6000,6500.0)+250.0*game.skill)
6054 if not damaged(DSRSENS):
6056 prout(_("Mr. Spock- \"Captain, this is most unusual."))
6057 prout(_(" Please examine your short-range scan.\""))
6058 # Decide if quadrant needs a Tholian; lighten up if skill is low
6059 if game.options & OPTION_THOLIAN:
6060 if (game.skill < SKILL_GOOD and withprob(0.02)) or \
6061 (game.skill == SKILL_GOOD and withprob(0.05)) or \
6062 (game.skill > SKILL_GOOD and withprob(0.08)):
6065 w.i = withprob(0.5) * (QUADSIZE-1)
6066 w.j = withprob(0.5) * (QUADSIZE-1)
6067 if game.quad[w.i][w.j] == '.':
6069 game.tholian = Enemy(etype='T', loc=w,
6070 power=randrange(100, 500) + 25.0*game.skill)
6071 # Reserve unoccupied corners
6072 if game.quad[0][0]=='.':
6073 game.quad[0][0] = 'X'
6074 if game.quad[0][QUADSIZE-1]=='.':
6075 game.quad[0][QUADSIZE-1] = 'X'
6076 if game.quad[QUADSIZE-1][0]=='.':
6077 game.quad[QUADSIZE-1][0] = 'X'
6078 if game.quad[QUADSIZE-1][QUADSIZE-1]=='.':
6079 game.quad[QUADSIZE-1][QUADSIZE-1] = 'X'
6081 # And finally the stars
6082 for _i in range(q.stars):
6084 # Put in a few black holes
6085 for _i in range(1, 3+1):
6088 # Take out X's in corners if Tholian present
6090 if game.quad[0][0]=='X':
6091 game.quad[0][0] = '.'
6092 if game.quad[0][QUADSIZE-1]=='X':
6093 game.quad[0][QUADSIZE-1] = '.'
6094 if game.quad[QUADSIZE-1][0]=='X':
6095 game.quad[QUADSIZE-1][0] = '.'
6096 if game.quad[QUADSIZE-1][QUADSIZE-1]=='X':
6097 game.quad[QUADSIZE-1][QUADSIZE-1] = '.'
6100 "Set the self-destruct password."
6101 if game.options & OPTION_PLAIN:
6104 proutn(_("Please type in a secret password- "))
6106 game.passwd = scanner.token
6107 if game.passwd != None:
6111 game.passwd += chr(ord('a')+randrange(26))
6112 game.passwd += chr(ord('a')+randrange(26))
6113 game.passwd += chr(ord('a')+randrange(26))
6115 # Code from sst.c begins here
6118 ("SRSCAN", OPTION_TTY),
6119 ("STATUS", OPTION_TTY),
6120 ("REQUEST", OPTION_TTY),
6121 ("LRSCAN", OPTION_TTY),
6133 ("SENSORS", OPTION_PLANETS),
6134 ("ORBIT", OPTION_PLANETS),
6135 ("TRANSPORT", OPTION_PLANETS),
6136 ("MINE", OPTION_PLANETS),
6137 ("CRYSTALS", OPTION_PLANETS),
6138 ("SHUTTLE", OPTION_PLANETS),
6139 ("PLANETS", OPTION_PLANETS),
6144 ("PROBE", OPTION_PROBE),
6146 ("FREEZE", 0), # Synonym for SAVE
6150 ("CAPTURE", OPTION_CAPTURE),
6151 ("CLOAK", OPTION_CLOAK),
6154 ("SOS", 0), # Synonym for MAYDAY
6155 ("CALL", 0), # Synonym for MAYDAY
6163 "Generate a list of legal commands."
6164 prout(_("LEGAL COMMANDS ARE:"))
6166 for (key, opt) in commands:
6167 if not opt or (opt & game.options):
6168 proutn("%-12s " % key)
6170 if emitted % 5 == 4:
6175 "Browse on-line help."
6176 key = scanner.nexttok()
6179 setwnd(prompt_window)
6180 proutn(_("Help on what command? "))
6181 key = scanner.nexttok()
6182 setwnd(message_window)
6185 cmds = [x[0] for x in commands]
6186 if scanner.token.upper() in cmds or scanner.token.upper() == "ABBREV":
6193 cmd = scanner.token.upper()
6194 for directory in docpath:
6196 fp = open(os.path.join(directory, "sst.doc"), "r")
6201 prout(_("Spock- \"Captain, that information is missing from the"))
6202 prout(_(" computer. You need to find sst.doc and put it somewhere"))
6203 proutn(_(" in these directories: %s") % ":".join(docpath))
6205 # This used to continue: "You need to find SST.DOC and put
6206 # it in the current directory."
6209 linebuf = fp.readline()
6211 prout(_("Spock- \"Captain, there is no information on that command.\""))
6214 if linebuf[0] == '%' and linebuf[1] == '%' and linebuf[2] == ' ':
6215 linebuf = linebuf[3:].strip()
6216 if cmd.upper() == linebuf:
6219 prout(_("Spock- \"Captain, I've found the following information:\""))
6222 linebuf = fp.readline()
6223 if "******" in linebuf:
6229 "Command-interpretation loop."
6231 if game.irhere and game.state.date >= ALGERON and not game.isviolreported and game.iscloaked:
6232 prout(_("The Romulan ship discovers you are breaking the Treaty of Algeron!"))
6234 game.isviolreported = True
6235 while True: # command loop
6237 while True: # get a command
6239 game.optime = game.justin = False
6241 setwnd(prompt_window)
6244 if scanner.nexttok() == "IHEOL":
6245 if game.options & OPTION_CURSES:
6248 elif scanner.token == "":
6252 setwnd(message_window)
6254 abandon_passed = False
6255 cmd = "" # Force cmd to persist after loop
6256 opt = 0 # Force opt to persist after loop
6257 for (cmd, opt) in commands:
6258 # commands after ABANDON cannot be abbreviated
6259 if cmd == "ABANDON":
6260 abandon_passed = True
6261 if cmd == scanner.token.upper() or (not abandon_passed \
6262 and cmd.startswith(scanner.token.upper())):
6267 elif opt and not (opt & game.options):
6271 if cmd == "SRSCAN": # srscan
6273 elif cmd == "STATUS": # status
6275 elif cmd == "REQUEST": # status request
6277 elif cmd == "LRSCAN": # long range scan
6278 lrscan(silent=False)
6279 elif cmd == "PHASERS": # phasers
6284 elif cmd in ("TORPEDO", "PHOTONS"): # photon torpedos
6289 elif cmd == "MOVE": # move under warp
6290 warp(wcourse=None, involuntary=False)
6291 elif cmd == "SHIELDS": # shields
6292 doshield(shraise=False)
6295 game.shldchg = False
6296 elif cmd == "DOCK": # dock at starbase
6299 attack(torps_ok=False)
6300 elif cmd == "DAMAGES": # damage reports
6302 elif cmd == "CHART": # chart
6304 elif cmd == "IMPULSE": # impulse
6306 elif cmd == "REST": # rest
6310 elif cmd == "WARP": # warp
6312 elif cmd == "SENSORS": # sensors
6314 elif cmd == "ORBIT": # orbit
6318 elif cmd == "TRANSPORT": # transport "beam"
6320 elif cmd == "MINE": # mine
6324 elif cmd == "CRYSTALS": # crystals
6328 elif cmd == "SHUTTLE": # shuttle
6332 elif cmd == "PLANETS": # Planet list
6334 elif cmd == "REPORT": # Game Report
6336 elif cmd == "COMPUTER": # use COMPUTER!
6338 elif cmd == "COMMANDS":
6340 elif cmd == "EMEXIT": # Emergency exit
6341 clrscr() # Hide screen
6342 freeze(True) # forced save
6343 raise SystemExit(1) # And quick exit
6344 elif cmd == "PROBE":
6345 probe() # Launch probe
6348 elif cmd == "ABANDON": # Abandon Ship
6350 elif cmd == "DESTRUCT": # Self Destruct
6352 elif cmd == "SAVE": # Save Game
6355 if game.skill > SKILL_GOOD:
6356 prout(_("WARNING--Saved games produce no plaques!"))
6357 elif cmd == "DEATHRAY": # Try a desparation measure
6361 elif cmd == "CAPTURE":
6363 elif cmd == "DEBUGCMD": # What do we want for debug???
6365 elif cmd == "MAYDAY": # Call for help
6370 game.alldone = True # quit the game
6373 elif cmd == "SCORE":
6374 score() # see current score
6377 break # Game has ended
6378 if game.optime != 0.0:
6381 break # Events did us in
6382 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6385 if hitme and not game.justin:
6386 attack(torps_ok=True)
6389 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6400 "Emit the name of an enemy or feature."
6401 if ch == 'R': s = _("Romulan")
6402 elif ch == 'K': s = _("Klingon")
6403 elif ch == 'C': s = _("Commander")
6404 elif ch == 'S': s = _("Super-commander")
6405 elif ch == '*': s = _("Star")
6406 elif ch == 'P': s = _("Planet")
6407 elif ch == 'B': s = _("Starbase")
6408 elif ch == ' ': s = _("Black hole")
6409 elif ch == 'T': s = _("Tholian")
6410 elif ch == '#': s = _("Tholian web")
6411 elif ch == '?': s = _("Stranger")
6412 elif ch == '@': s = _("Inhabited World")
6413 else: s = "Unknown??"
6416 def crmena(loud, enemy, loctype, w):
6417 "Emit the name of an enemy and his location."
6421 buf += cramen(enemy) + _(" at ")
6422 if loctype == "quadrant":
6423 buf += _("Quadrant ")
6424 elif loctype == "sector":
6426 return buf + repr(w)
6429 "Emit our ship name."
6430 return{'E':_("Enterprise"),'F':_("Faerie Queene")}.get(game.ship,"Ship???")
6433 "Emit a line of stars"
6434 prouts("******************************************************")
6438 return -avrage*math.log(1e-7 + randreal())
6440 def randplace(size):
6441 "Choose a random location."
6443 w.i = randrange(size)
6444 w.j = randrange(size)
6454 # Get a token from the user
6457 # Fill the token quue if nothing here
6458 while not self.inqueue:
6460 if curwnd==prompt_window:
6462 setwnd(message_window)
6469 self.inqueue = sline.lstrip().split() + ["\n"]
6470 # From here on in it's all looking at the queue
6471 self.token = self.inqueue.pop(0)
6472 if self.token == "\n":
6476 self.real = float(self.token)
6477 self.type = "IHREAL"
6482 self.token = self.token.lower()
6483 self.type = "IHALPHA"
6486 def append(self, tok):
6487 self.inqueue.append(tok)
6488 def push(self, tok):
6489 self.inqueue.insert(0, tok)
6493 # Demand input for next scan
6495 self.real = self.token = None
6497 # compares s to item and returns true if it matches to the length of s
6498 return s.startswith(self.token)
6500 # Round token value to nearest integer
6501 return int(round(self.real))
6505 if self.type != "IHREAL":
6510 if self.type != "IHREAL":
6516 return "<sstcanner: token=%s, type=%s, queue=%s>" % (self.token, self.type, self.inqueue)
6519 "Yes-or-no confirmation."
6523 if scanner.token == 'y':
6525 if scanner.token == 'n':
6528 proutn(_("Please answer with \"y\" or \"n\": "))
6531 "Complain about unparseable input."
6534 prout(_("Beg your pardon, Captain?"))
6537 "Access to the internals for debugging."
6538 proutn("Reset levels? ")
6540 if game.energy < game.inenrg:
6541 game.energy = game.inenrg
6542 game.shield = game.inshld
6543 game.torps = game.intorps
6544 game.lsupres = game.inlsr
6545 proutn("Reset damage? ")
6547 for i in range(NDEVICES):
6548 if game.damage[i] > 0.0:
6549 game.damage[i] = 0.0
6550 proutn("Toggle debug flag? ")
6552 game.idebug = not game.idebug
6554 prout("Debug output ON")
6556 prout("Debug output OFF")
6557 proutn("Cause selective damage? ")
6559 for i in range(NDEVICES):
6560 proutn("Kill %s?" % device[i])
6562 key = scanner.nexttok()
6563 if key == "IHALPHA" and scanner.sees("y"):
6564 game.damage[i] = 10.0
6565 proutn("Examine/change events? ")
6570 FSNOVA: "Supernova ",
6573 FBATTAK: "Base Attack ",
6574 FCDBAS: "Base Destroy ",
6575 FSCMOVE: "SC Move ",
6576 FSCDBAS: "SC Base Destroy ",
6577 FDSPROB: "Probe Move ",
6578 FDISTR: "Distress Call ",
6579 FENSLV: "Enslavement ",
6580 FREPRO: "Klingon Build ",
6582 for i in range(1, NEVENTS):
6585 proutn("%.2f" % (scheduled(i)-game.state.date))
6586 if i == FENSLV or i == FREPRO:
6588 proutn(" in %s" % ev.quadrant)
6593 key = scanner.nexttok()
6597 elif key == "IHREAL":
6598 ev = schedule(i, scanner.real)
6599 if i == FENSLV or i == FREPRO:
6601 proutn("In quadrant- ")
6602 key = scanner.nexttok()
6603 # "IHEOL" says to leave coordinates as they are
6606 prout("Event %d canceled, no x coordinate." % (i))
6609 w.i = int(round(scanner.real))
6610 key = scanner.nexttok()
6612 prout("Event %d canceled, no y coordinate." % (i))
6615 w.j = int(round(scanner.real))
6618 proutn("Induce supernova here? ")
6620 game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova = True
6623 if __name__ == '__main__':
6625 #global line, thing, game
6629 game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY)
6630 if os.getenv("TERM"):
6631 game.options |= OPTION_CURSES
6633 game.options |= OPTION_TTY
6634 seed = int(time.time())
6635 (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:txV")
6637 for (switch, val) in options:
6640 replayfp = open(val, "r")
6642 sys.stderr.write("sst: can't open replay file %s\n" % val)
6645 line = replayfp.readline().strip()
6646 (leader, __, seed) = line.split()
6648 sys.stderr.write("sst2k: seed set to %s\n" % seed)
6649 line = replayfp.readline().strip()
6650 arguments += line.split()[2:]
6653 sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
6655 game.options |= OPTION_TTY
6656 game.options &=~ OPTION_CURSES
6657 elif switch == '-s':
6659 elif switch == '-t':
6660 game.options |= OPTION_TTY
6661 game.options &=~ OPTION_CURSES
6662 elif switch == '-x':
6664 elif switch == '-V':
6665 print("SST2K", version)
6668 sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n")
6670 # where to save the input in case of bugs
6671 if "TMPDIR" in os.environ:
6672 tmpdir = os.environ['TMPDIR']
6676 logfp = open(os.path.join(tmpdir, "sst-input.log"), "w")
6678 sys.stderr.write("sst: warning, can't open logfile\n")
6681 logfp.write("# seed %s\n" % seed)
6682 logfp.write("# options %s\n" % " ".join(arguments))
6683 logfp.write("# SST2K version %s\n" % version)
6684 logfp.write("# recorded by %s@%s on %s\n" % \
6685 (getpass.getuser(),socket.gethostname(),time.ctime()))
6687 scanner = sstscanner()
6688 for arg in arguments:
6692 while True: # Play a game
6693 setwnd(fullscreen_window)
6699 game.alldone = False
6707 if game.tourn and game.alldone:
6708 proutn(_("Do you want your score recorded?"))
6714 proutn(_("Do you want to play again? "))
6718 prout(_("May the Great Bird of the Galaxy roost upon your home planet."))
6722 except KeyboardInterrupt: