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.state.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."))
3161 "Compute player's score."
3162 timused = game.state.date - game.indate
3163 if (timused == 0 or (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0) and timused < 5.0:
3165 game.perdate = killrate()
3166 ithperd = 500*game.perdate + 0.5
3169 iwon = 100*game.skill
3170 if game.ship == 'E':
3172 elif game.ship == 'F':
3176 game.score = 10*(game.inkling - game.state.remkl) \
3177 + 50*(game.incom - len(game.state.kcmdr)) \
3179 + 20*(game.inrom - game.state.nromrem) \
3180 + 200*(game.inscom - game.state.nscrem) \
3181 - game.state.nromrem \
3182 + 3 * game.kcaptured \
3187 prout(_("Your score --"))
3188 if game.inrom - game.state.nromrem:
3189 prout(_("%6d Romulans destroyed %5d") %
3190 (game.inrom - game.state.nromrem, 20*(game.inrom - game.state.nromrem)))
3191 if game.state.nromrem and game.gamewon:
3192 prout(_("%6d Romulans captured %5d") %
3193 (game.state.nromrem, game.state.nromrem))
3194 if game.inkling - game.state.remkl:
3195 prout(_("%6d ordinary Klingons destroyed %5d") %
3196 (game.inkling - game.state.remkl, 10*(game.inkling - game.state.remkl)))
3197 if game.incom - len(game.state.kcmdr):
3198 prout(_("%6d Klingon commanders destroyed %5d") %
3199 (game.incom - len(game.state.kcmdr), 50*(game.incom - len(game.state.kcmdr))))
3201 prout(_("%d Klingons captured %5d") %
3202 (game.kcaptured, 3 * game.kcaptured))
3203 if game.inscom - game.state.nscrem:
3204 prout(_("%6d Super-Commander destroyed %5d") %
3205 (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem)))
3207 prout(_("%6.2f Klingons per stardate %5d") %
3208 (game.perdate, ithperd))
3209 if game.state.starkl:
3210 prout(_("%6d stars destroyed by your action %5d") %
3211 (game.state.starkl, -5*game.state.starkl))
3212 if game.state.nplankl:
3213 prout(_("%6d planets destroyed by your action %5d") %
3214 (game.state.nplankl, -10*game.state.nplankl))
3215 if (game.options & OPTION_WORLDS) and game.state.nworldkl:
3216 prout(_("%6d inhabited planets destroyed by your action %5d") %
3217 (game.state.nworldkl, -300*game.state.nworldkl))
3218 if game.state.basekl:
3219 prout(_("%6d bases destroyed by your action %5d") %
3220 (game.state.basekl, -100*game.state.basekl))
3222 prout(_("%6d calls for help from starbase %5d") %
3223 (game.nhelp, -45*game.nhelp))
3225 prout(_("%6d casualties incurred %5d") %
3226 (game.casual, -game.casual))
3228 prout(_("%6d crew abandoned in space %5d") %
3229 (game.abandoned, -3*game.abandoned))
3231 prout(_("%6d ship(s) lost or destroyed %5d") %
3232 (klship, -100*klship))
3235 prout(_("1 Treaty of Algeron violation -100"))
3237 prout(_("%6d Treaty of Algeron violations %5d\n") %
3238 (ncviol, -100*ncviol))
3240 prout(_("Penalty for getting yourself killed -200"))
3242 proutn(_("Bonus for winning "))
3243 if game.skill == SKILL_NOVICE: proutn(_("Novice game "))
3244 elif game.skill == SKILL_FAIR: proutn(_("Fair game "))
3245 elif game.skill == SKILL_GOOD: proutn(_("Good game "))
3246 elif game.skill == SKILL_EXPERT: proutn(_("Expert game "))
3247 elif game.skill == SKILL_EMERITUS: proutn(_("Emeritus game"))
3248 prout(" %5d" % iwon)
3250 prout(_("TOTAL SCORE %5d") % game.score)
3253 "Emit winner's commemmorative plaque."
3256 proutn(_("File or device name for your plaque: "))
3259 fp = open(winner, "w")
3262 prout(_("Invalid name."))
3264 proutn(_("Enter name to go on plaque (up to 30 characters): "))
3266 # The 38 below must be 64 for 132-column paper
3267 nskip = 38 - len(winner)/2
3268 fp.write("\n\n\n\n")
3269 # --------DRAW ENTERPRISE PICTURE.
3270 fp.write(" EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n" )
3271 fp.write(" EEE E : : : E\n" )
3272 fp.write(" EE EEE E : : NCC-1701 : E\n")
3273 fp.write("EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEE : : : E\n")
3274 fp.write(" E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n")
3275 fp.write(" EEEEEEEEE EEEEEEEEEEEEE E E\n")
3276 fp.write(" EEEEEEE EEEEE E E E E\n")
3277 fp.write(" EEE E E E E\n")
3278 fp.write(" E E E E\n")
3279 fp.write(" EEEEEEEEEEEEE E E\n")
3280 fp.write(" EEE : EEEEEEE EEEEEEEE\n")
3281 fp.write(" :E : EEEE E\n")
3282 fp.write(" .-E -:----- E\n")
3283 fp.write(" :E : E\n")
3284 fp.write(" EE : EEEEEEEE\n")
3285 fp.write(" EEEEEEEEEEEEEEEEEEEEEEE\n")
3287 fp.write(_(" U. S. S. ENTERPRISE\n"))
3288 fp.write("\n\n\n\n")
3289 fp.write(_(" For demonstrating outstanding ability as a starship captain\n"))
3291 fp.write(_(" Starfleet Command bestows to you\n"))
3293 fp.write("%*s%s\n\n" % (nskip, "", winner))
3294 fp.write(_(" the rank of\n\n"))
3295 fp.write(_(" \"Commodore Emeritus\"\n\n"))
3297 if game.skill == SKILL_EXPERT:
3298 fp.write(_(" Expert level\n\n"))
3299 elif game.skill == SKILL_EMERITUS:
3300 fp.write(_("Emeritus level\n\n"))
3302 fp.write(_(" Cheat level\n\n"))
3303 timestring = time.ctime()
3304 fp.write(_(" This day of %.6s %.4s, %.8s\n\n") %
3305 (timestring+4, timestring+20, timestring+11))
3306 fp.write(_(" Your score: %d\n\n") % game.score)
3307 fp.write(_(" Klingons per stardate: %.2f\n") % game.perdate)
3310 # Code from io.c begins here
3312 rows = linecount = 0 # for paging
3315 fullscreen_window = None
3316 srscan_window = None # Short range scan
3317 report_window = None # Report legends for status window
3318 status_window = None # The status window itself
3319 lrscan_window = None # Long range scan
3320 message_window = None # Main window for scrolling text
3321 prompt_window = None # Prompt window at bottom of display
3326 # for some recent versions of python2, the following enables UTF8
3327 # for the older ones we probably need to set C locale, and python3
3328 # has no problems at all
3329 if sys.version_info[0] < 3:
3330 locale.setlocale(locale.LC_ALL, "")
3331 gettext.bindtextdomain("sst", "/usr/local/share/locale")
3332 gettext.textdomain("sst")
3333 if not (game.options & OPTION_CURSES):
3334 ln_env = os.getenv("LINES")
3340 stdscr = curses.initscr()
3344 if game.options & OPTION_COLOR:
3345 curses.start_color()
3346 curses.use_default_colors()
3347 curses.init_pair(curses.COLOR_BLACK, curses.COLOR_BLACK, -1)
3348 curses.init_pair(curses.COLOR_GREEN, curses.COLOR_GREEN, -1)
3349 curses.init_pair(curses.COLOR_RED, curses.COLOR_RED, -1)
3350 curses.init_pair(curses.COLOR_CYAN, curses.COLOR_CYAN, -1)
3351 curses.init_pair(curses.COLOR_WHITE, curses.COLOR_WHITE, -1)
3352 curses.init_pair(curses.COLOR_MAGENTA, curses.COLOR_MAGENTA, -1)
3353 curses.init_pair(curses.COLOR_BLUE, curses.COLOR_BLUE, -1)
3354 curses.init_pair(curses.COLOR_YELLOW, curses.COLOR_YELLOW, -1)
3355 global fullscreen_window, srscan_window, report_window, status_window
3356 global lrscan_window, message_window, prompt_window
3357 (rows, _columns) = stdscr.getmaxyx()
3358 fullscreen_window = stdscr
3359 srscan_window = curses.newwin(12, 25, 0, 0)
3360 report_window = curses.newwin(11, 0, 1, 25)
3361 status_window = curses.newwin(10, 0, 1, 39)
3362 lrscan_window = curses.newwin(5, 0, 0, 64)
3363 message_window = curses.newwin(0, 0, 12, 0)
3364 prompt_window = curses.newwin(1, 0, rows-2, 0)
3365 message_window.scrollok(True)
3366 setwnd(fullscreen_window)
3370 if game.options & OPTION_CURSES:
3371 stdscr.keypad(False)
3377 "Wait for user action -- OK to do nothing if on a TTY"
3378 if game.options & OPTION_CURSES:
3383 prouts(_("[ANNOUNCEMENT ARRIVING...]"))
3387 if game.skill > SKILL_FAIR:
3388 prompt = _("[CONTINUE?]")
3390 prompt = _("[PRESS ENTER TO CONTINUE]")
3392 if game.options & OPTION_CURSES:
3394 setwnd(prompt_window)
3395 prompt_window.clear()
3396 prompt_window.addstr(prompt)
3397 prompt_window.getstr()
3398 prompt_window.clear()
3399 prompt_window.refresh()
3400 setwnd(message_window)
3403 sys.stdout.write('\n')
3407 sys.stdout.write('\n' * rows)
3411 "Skip i lines. Pause game if this would cause a scrolling event."
3412 for _dummy in range(i):
3413 if game.options & OPTION_CURSES:
3414 (y, _x) = curwnd.getyx()
3417 except curses.error:
3422 if rows and linecount >= rows:
3425 sys.stdout.write('\n')
3427 def proutn(proutntline):
3428 "Utter a line with no following line feed."
3429 if game.options & OPTION_CURSES:
3430 (y, x) = curwnd.getyx()
3431 (my, _mx) = curwnd.getmaxyx()
3432 if curwnd == message_window and y >= my - 2:
3435 # Uncomment this to debug curses problems
3437 logfp.write("#curses: at %s proutn(%s)\n" % ((y, x), repr(proutntline)))
3438 curwnd.addstr(proutntline)
3441 sys.stdout.write(proutntline)
3444 def prout(proutline):
3448 def prouts(proutsline):
3450 for c in proutsline:
3451 if not replayfp or replayfp.closed: # Don't slow down replays
3454 if game.options & OPTION_CURSES:
3458 if not replayfp or replayfp.closed:
3462 "Get a line of input."
3463 if game.options & OPTION_CURSES:
3464 linein = curwnd.getstr() + "\n"
3467 if replayfp and not replayfp.closed:
3469 linein = replayfp.readline()
3472 prout("*** Replay finished")
3475 elif linein[0] != "#":
3478 linein = eval(input()) + "\n"
3484 "Change windows -- OK for this to be a no-op in tty mode."
3486 if game.options & OPTION_CURSES:
3487 # Uncomment this to debug curses problems
3489 if wnd == fullscreen_window:
3490 legend = "fullscreen"
3491 elif wnd == srscan_window:
3493 elif wnd == report_window:
3495 elif wnd == status_window:
3497 elif wnd == lrscan_window:
3499 elif wnd == message_window:
3501 elif wnd == prompt_window:
3505 logfp.write("#curses: setwnd(%s)\n" % legend)
3507 # Some curses implementations get confused when you try this.
3509 curses.curs_set(wnd in (fullscreen_window, message_window, prompt_window))
3510 except curses.error:
3514 "Clear to end of line -- can be a no-op in tty mode"
3515 if game.options & OPTION_CURSES:
3520 "Clear screen -- can be a no-op in tty mode."
3522 if game.options & OPTION_CURSES:
3528 def textcolor(color=DEFAULT):
3529 if game.options & OPTION_COLOR:
3530 if color == DEFAULT:
3532 elif color == BLACK:
3533 curwnd.attron(curses.color_pair(curses.COLOR_BLACK))
3535 curwnd.attron(curses.color_pair(curses.COLOR_BLUE))
3536 elif color == GREEN:
3537 curwnd.attron(curses.color_pair(curses.COLOR_GREEN))
3539 curwnd.attron(curses.color_pair(curses.COLOR_CYAN))
3541 curwnd.attron(curses.color_pair(curses.COLOR_RED))
3542 elif color == MAGENTA:
3543 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA))
3544 elif color == BROWN:
3545 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW))
3546 elif color == LIGHTGRAY:
3547 curwnd.attron(curses.color_pair(curses.COLOR_WHITE))
3548 elif color == DARKGRAY:
3549 curwnd.attron(curses.color_pair(curses.COLOR_BLACK) | curses.A_BOLD)
3550 elif color == LIGHTBLUE:
3551 curwnd.attron(curses.color_pair(curses.COLOR_BLUE) | curses.A_BOLD)
3552 elif color == LIGHTGREEN:
3553 curwnd.attron(curses.color_pair(curses.COLOR_GREEN) | curses.A_BOLD)
3554 elif color == LIGHTCYAN:
3555 curwnd.attron(curses.color_pair(curses.COLOR_CYAN) | curses.A_BOLD)
3556 elif color == LIGHTRED:
3557 curwnd.attron(curses.color_pair(curses.COLOR_RED) | curses.A_BOLD)
3558 elif color == LIGHTMAGENTA:
3559 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA) | curses.A_BOLD)
3560 elif color == YELLOW:
3561 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW) | curses.A_BOLD)
3562 elif color == WHITE:
3563 curwnd.attron(curses.color_pair(curses.COLOR_WHITE) | curses.A_BOLD)
3566 if game.options & OPTION_COLOR:
3567 curwnd.attron(curses.A_REVERSE)
3570 # Things past this point have policy implications.
3574 "Hook to be called after moving to redraw maps."
3575 if game.options & OPTION_CURSES:
3578 setwnd(srscan_window)
3582 setwnd(status_window)
3583 status_window.clear()
3584 status_window.move(0, 0)
3585 setwnd(report_window)
3586 report_window.clear()
3587 report_window.move(0, 0)
3589 setwnd(lrscan_window)
3590 lrscan_window.clear()
3591 lrscan_window.move(0, 0)
3592 lrscan(silent=False)
3594 def put_srscan_sym(w, sym):
3595 "Emit symbol for short-range scan."
3596 srscan_window.move(w.i+1, w.j*2+2)
3597 srscan_window.addch(sym)
3598 srscan_window.refresh()
3601 "Enemy fall down, go boom."
3602 if game.options & OPTION_CURSES:
3604 setwnd(srscan_window)
3605 srscan_window.attron(curses.A_REVERSE)
3606 put_srscan_sym(w, game.quad[w.i][w.j])
3610 srscan_window.attroff(curses.A_REVERSE)
3611 put_srscan_sym(w, game.quad[w.i][w.j])
3612 curses.delay_output(500)
3613 setwnd(message_window)
3616 "Sound and visual effects for teleportation."
3617 if game.options & OPTION_CURSES:
3619 setwnd(message_window)
3621 prouts(" . . . . . ")
3622 if game.options & OPTION_CURSES:
3623 #curses.delay_output(1000)
3627 def tracktorpedo(w, step, i, n, iquad):
3628 "Torpedo-track animation."
3629 if not game.options & OPTION_CURSES:
3633 proutn(_("Track for torpedo number %d- ") % (i+1))
3636 proutn(_("Torpedo track- "))
3637 elif step==4 or step==9:
3641 if not damaged(DSRSENS) or game.condition=="docked":
3642 if i != 0 and step == 1:
3645 if (iquad=='.') or (iquad==' '):
3646 put_srscan_sym(w, '+')
3650 put_srscan_sym(w, iquad)
3652 curwnd.attron(curses.A_REVERSE)
3653 put_srscan_sym(w, iquad)
3657 curwnd.attroff(curses.A_REVERSE)
3658 put_srscan_sym(w, iquad)
3663 "Display the current galaxy chart."
3664 if game.options & OPTION_CURSES:
3665 setwnd(message_window)
3666 message_window.clear()
3668 if game.options & OPTION_TTY:
3673 def prstat(txt, data):
3675 if game.options & OPTION_CURSES:
3677 setwnd(status_window)
3679 proutn(" " * (NSYM - len(txt)))
3682 if game.options & OPTION_CURSES:
3683 setwnd(report_window)
3685 # Code from moving.c begins here
3687 def imove(icourse=None, noattack=False):
3688 "Movement execution for warp, impulse, supernova, and tractor-beam events."
3691 def newquadrant(noattack):
3692 # Leaving quadrant -- allow final enemy attack
3693 # Don't set up attack if being pushed by nova or cloaked
3694 if len(game.enemies) != 0 and not noattack and not game.iscloaked:
3696 for enemy in game.enemies:
3697 finald = (w - enemy.location).distance()
3698 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3699 # Stas Sergeev added the condition
3700 # that attacks only happen if Klingons
3701 # are present and your skill is good.
3702 if game.skill > SKILL_GOOD and game.klhere > 0 and not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3703 attack(torps_ok=False)
3706 # check for edge of galaxy
3712 if icourse.final.i < 0:
3713 icourse.final.i = -icourse.final.i
3715 if icourse.final.j < 0:
3716 icourse.final.j = -icourse.final.j
3718 if icourse.final.i >= GALSIZE*QUADSIZE:
3719 icourse.final.i = (GALSIZE*QUADSIZE*2) - icourse.final.i
3721 if icourse.final.j >= GALSIZE*QUADSIZE:
3722 icourse.final.j = (GALSIZE*QUADSIZE*2) - icourse.final.j
3730 if game.nkinks == 3:
3731 # Three strikes -- you're out!
3735 prout(_("YOU HAVE ATTEMPTED TO CROSS THE NEGATIVE ENERGY BARRIER"))
3736 prout(_("AT THE EDGE OF THE GALAXY. THE THIRD TIME YOU TRY THIS,"))
3737 prout(_("YOU WILL BE DESTROYED."))
3738 # Compute final position in new quadrant
3739 if trbeam: # Don't bother if we are to be beamed
3741 game.quadrant = icourse.final.quadrant()
3742 game.sector = icourse.final.sector()
3744 prout(_("Entering Quadrant %s.") % game.quadrant)
3745 game.quad[game.sector.i][game.sector.j] = game.ship
3747 if game.skill>SKILL_NOVICE:
3748 attack(torps_ok=False)
3750 def check_collision(h):
3751 iquad = game.quad[h.i][h.j]
3753 # object encountered in flight path
3754 stopegy = 50.0*icourse.distance/game.optime
3755 if iquad in ('T', 'K', 'C', 'S', 'R', '?'):
3756 for enemy in game.enemies:
3757 if enemy.location == game.sector:
3758 collision(rammed=False, enemy=enemy)
3760 # This should not happen
3761 prout(_("Which way did he go?"))
3765 prouts(_("***RED ALERT! RED ALERT!"))
3767 proutn("***" + crmshp())
3768 proutn(_(" pulled into black hole at Sector %s") % h)
3769 # Getting pulled into a black hole was certain
3770 # death in Almy's original. Stas Sergeev added a
3771 # possibility that you'll get timewarped instead.
3773 for m in range(NDEVICES):
3774 if game.damage[m]>0:
3776 probf=math.pow(1.4,(game.energy+game.shield)/5000.0-1.0)*math.pow(1.3,1.0/(n+1)-1.0)
3777 if (game.options & OPTION_BLKHOLE) and withprob(1-probf):
3787 prout(_(" encounters Tholian web at %s;") % h)
3789 prout(_(" blocked by object at %s;") % h)
3790 proutn(_("Emergency stop required "))
3791 prout(_("%2d units of energy.") % int(stopegy))
3792 game.energy -= stopegy
3793 if game.energy <= 0:
3800 prout(_("Helmsman Sulu- \"Leaving standard orbit.\""))
3801 game.inorbit = False
3802 # If tractor beam is to occur, don't move full distance
3803 if game.state.date+game.optime >= scheduled(FTBEAM):
3805 # We can't be tractor beamed if cloaked,
3806 # so move the event into the future
3807 postpone(FTBEAM, game.optime + expran(1.5*game.intime/len(game.kcmdr)))
3811 game.condition = "red"
3812 icourse.distance = icourse.distance*(scheduled(FTBEAM)-game.state.date)/game.optime + 0.1
3813 game.optime = scheduled(FTBEAM) - game.state.date + 1e-5
3815 game.quad[game.sector.i][game.sector.j] = '.'
3816 for _m in range(icourse.moves):
3818 w = icourse.sector()
3819 if icourse.origin.quadrant() != icourse.location.quadrant():
3820 newquadrant(noattack)
3822 elif check_collision(w):
3823 print("Collision detected")
3827 # We're in destination quadrant -- compute new average enemy distances
3828 game.quad[game.sector.i][game.sector.j] = game.ship
3830 for enemy in game.enemies:
3831 finald = (w-enemy.location).distance()
3832 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3833 enemy.kdist = finald
3835 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3836 attack(torps_ok=False)
3837 for enemy in game.enemies:
3838 enemy.kavgd = enemy.kdist
3841 setwnd(message_window)
3845 "Dock our ship at a starbase."
3847 if game.condition == "docked" and verbose:
3848 prout(_("Already docked."))
3851 prout(_("You must first leave standard orbit."))
3853 if not game.base.is_valid() or abs(game.sector.i-game.base.i) > 1 or abs(game.sector.j-game.base.j) > 1:
3854 prout(crmshp() + _(" not adjacent to base."))
3857 prout(_("You cannot dock while cloaked."))
3859 game.condition = "docked"
3863 if game.energy < game.inenrg:
3864 game.energy = game.inenrg
3865 game.shield = game.inshld
3866 game.torps = game.intorps
3867 game.lsupres = game.inlsr
3868 game.state.crew = FULLCREW
3869 if game.brigcapacity-game.brigfree > 0:
3870 prout(_("%d captured Klingons transferred to base") % (game.brigcapacity-game.brigfree))
3871 game.kcaptured += game.brigcapacity-game.brigfree
3872 game.brigfree = game.brigcapacity
3873 if not damaged(DRADIO) and \
3874 ((is_scheduled(FCDBAS) or game.isatb == 1) and not game.iseenit):
3875 # get attack report from base
3876 prout(_("Lt. Uhura- \"Captain, an important message from the starbase:\""))
3880 def cartesian(loc1=None, loc2=None):
3882 return game.quadrant * QUADSIZE + game.sector
3884 return game.quadrant * QUADSIZE + loc1
3886 return loc1 * QUADSIZE + loc2
3888 def getcourse(isprobe):
3889 "Get a course and distance from the user."
3891 dquad = copy.copy(game.quadrant)
3892 navmode = "unspecified"
3896 if game.landed and not isprobe:
3897 prout(_("Dummy! You can't leave standard orbit until you"))
3898 proutn(_("are back aboard the ship."))
3901 while navmode == "unspecified":
3902 if damaged(DNAVSYS):
3904 prout(_("Computer damaged; manual navigation only"))
3906 prout(_("Computer damaged; manual movement only"))
3911 key = scanner.nexttok()
3913 proutn(_("Manual or automatic- "))
3916 elif key == "IHALPHA":
3917 if scanner.sees("manual"):
3919 key = scanner.nexttok()
3921 elif scanner.sees("automatic"):
3922 navmode = "automatic"
3923 key = scanner.nexttok()
3931 prout(_("(Manual navigation assumed.)"))
3933 prout(_("(Manual movement assumed.)"))
3937 if navmode == "automatic":
3938 while key == "IHEOL":
3940 proutn(_("Target quadrant or quadrant§or- "))
3942 proutn(_("Destination sector or quadrant§or- "))
3945 key = scanner.nexttok()
3949 xi = int(round(scanner.real))-1
3950 key = scanner.nexttok()
3954 xj = int(round(scanner.real))-1
3955 key = scanner.nexttok()
3957 # both quadrant and sector specified
3958 xk = int(round(scanner.real))-1
3959 key = scanner.nexttok()
3963 xl = int(round(scanner.real))-1
3969 # only one pair of numbers was specified
3971 # only quadrant specified -- go to center of dest quad
3974 dsect.j = dsect.i = 4 # preserves 1-origin behavior
3976 # only sector specified
3980 if not dquad.valid_quadrant() or not dsect.valid_sector():
3987 prout(_("Helmsman Sulu- \"Course locked in for Sector %s.\"") % dsect)
3989 prout(_("Ensign Chekov- \"Course laid in, Captain.\""))
3990 # the actual deltas get computed here
3991 delta.j = dquad.j-game.quadrant.j + (dsect.j-game.sector.j)/(QUADSIZE*1.0)
3992 delta.i = game.quadrant.i-dquad.i + (game.sector.i-dsect.i)/(QUADSIZE*1.0)
3994 while key == "IHEOL":
3995 proutn(_("X and Y displacements- "))
3998 key = scanner.nexttok()
4003 delta.j = scanner.real
4004 key = scanner.nexttok()
4008 delta.i = scanner.real
4009 # Check for zero movement
4010 if delta.i == 0 and delta.j == 0:
4013 if itemp == "verbose" and not isprobe:
4015 prout(_("Helmsman Sulu- \"Aye, Sir.\""))
4017 return course(bearing=delta.bearing(), distance=delta.distance())
4020 def __init__(self, bearing, distance, origin=None):
4021 self.distance = distance
4022 self.bearing = bearing
4024 self.origin = cartesian(game.quadrant, game.sector)
4026 self.origin = origin
4027 # The bearing() code we inherited from FORTRAN is actually computing
4028 # clockface directions!
4029 if self.bearing < 0.0:
4030 self.bearing += 12.0
4031 self.angle = ((15.0 - self.bearing) * 0.5235988)
4032 self.increment = Coord(-math.sin(self.angle), math.cos(self.angle))
4033 bigger = max(abs(self.increment.i), abs(self.increment.j))
4034 self.increment /= bigger
4035 self.moves = int(round(10*self.distance*bigger))
4037 self.final = (self.location + self.moves*self.increment).roundtogrid()
4038 self.location = self.origin
4039 self.nextlocation = None
4041 self.location = self.origin
4044 return self.location.roundtogrid() == self.final
4046 "Next step on course."
4048 self.nextlocation = self.location + self.increment
4049 samequad = (self.location.quadrant() == self.nextlocation.quadrant())
4050 self.location = self.nextlocation
4053 return self.location.quadrant()
4055 return self.location.sector()
4057 return self.distance*(w**3)*(game.shldup+1)
4059 return 10.0*self.distance/w**2
4062 "Move under impulse power."
4064 if damaged(DIMPULS):
4067 prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
4069 if game.energy > 30.0:
4071 icourse = getcourse(isprobe=False)
4074 power = 20.0 + 100.0*icourse.distance
4077 if power >= game.energy:
4078 # Insufficient power for trip
4080 prout(_("First Officer Spock- \"Captain, the impulse engines"))
4081 prout(_("require 20.0 units to engage, plus 100.0 units per"))
4082 if game.energy > 30:
4083 proutn(_("quadrant. We can go, therefore, a maximum of %d") %
4084 int(0.01 * (game.energy-20.0)-0.05))
4085 prout(_(" quadrants.\""))
4087 prout(_("quadrant. They are, therefore, useless.\""))
4090 # Make sure enough time is left for the trip
4091 game.optime = icourse.distance/0.095
4092 if game.optime >= game.state.remtime:
4093 prout(_("First Officer Spock- \"Captain, our speed under impulse"))
4094 prout(_("power is only 0.95 sectors per stardate. Are you sure"))
4095 proutn(_("we dare spend the time?\" "))
4098 # Activate impulse engines and pay the cost
4099 imove(icourse, noattack=False)
4103 power = 20.0 + 100.0*icourse.distance
4104 game.energy -= power
4105 game.optime = icourse.distance/0.095
4106 if game.energy <= 0:
4110 def warp(wcourse, involuntary):
4111 "ove under warp drive."
4112 blooey = False; twarp = False
4113 if not involuntary: # Not WARPX entry
4118 prout(_("Engineer Scott- \"The warp engines can not be used while cloaked, Sir.\""))
4120 if game.damage[DWARPEN] > 10.0:
4123 prout(_("Engineer Scott- \"The warp engines are damaged, Sir.\""))
4125 if damaged(DWARPEN) and game.warpfac > 4.0:
4128 prout(_("Engineer Scott- \"Sorry, Captain. Until this damage"))
4129 prout(_(" is repaired, I can only give you warp 4.\""))
4131 # Read in course and distance
4134 wcourse = getcourse(isprobe=False)
4137 # Make sure starship has enough energy for the trip
4138 # Note: this formula is slightly different from the C version,
4139 # and lets you skate a bit closer to the edge.
4140 if wcourse.power(game.warpfac) >= game.energy:
4141 # Insufficient power for trip
4144 prout(_("Engineering to bridge--"))
4145 if not game.shldup or 0.5*wcourse.power(game.warpfac) > game.energy:
4146 iwarp = (game.energy/(wcourse.distance+0.05)) ** 0.333333333
4148 prout(_("We can't do it, Captain. We don't have enough energy."))
4150 proutn(_("We don't have enough energy, but we could do it at warp %d") % iwarp)
4153 prout(_("if you'll lower the shields."))
4157 prout(_("We haven't the energy to go that far with the shields up."))
4159 # Make sure enough time is left for the trip
4160 game.optime = wcourse.time(game.warpfac)
4161 if game.optime >= 0.8*game.state.remtime:
4163 prout(_("First Officer Spock- \"Captain, I compute that such"))
4164 proutn(_(" a trip would require approximately %2.0f") %
4165 (100.0*game.optime/game.state.remtime))
4166 prout(_(" percent of our"))
4167 proutn(_(" remaining time. Are you sure this is wise?\" "))
4173 if game.warpfac > 6.0:
4174 # Decide if engine damage will occur
4175 # ESR: Seems wrong. Probability of damage goes *down* with distance?
4176 prob = wcourse.distance*(6.0-game.warpfac)**2/66.666666666
4177 if prob > randreal():
4179 wcourse.distance = randreal(wcourse.distance)
4180 # Decide if time warp will occur
4181 if 0.5*wcourse.distance*math.pow(7.0,game.warpfac-10.0) > randreal():
4183 if game.idebug and game.warpfac==10 and not twarp:
4185 proutn("=== Force time warp? ")
4189 # If time warp or engine damage, check path
4190 # If it is obstructed, don't do warp or damage
4191 look = wcourse.moves
4195 w = wcourse.sector()
4196 if not w.valid_sector():
4198 if game.quad[w.i][w.j] != '.':
4202 # Activate Warp Engines and pay the cost
4203 imove(wcourse, noattack=False)
4206 game.energy -= wcourse.power(game.warpfac)
4207 if game.energy <= 0:
4209 game.optime = wcourse.time(game.warpfac)
4213 game.damage[DWARPEN] = game.damfac * randreal(1.0, 4.0)
4215 prout(_("Engineering to bridge--"))
4216 prout(_(" Scott here. The warp engines are damaged."))
4217 prout(_(" We'll have to reduce speed to warp 4."))
4222 "Change the warp factor."
4224 key=scanner.nexttok()
4228 proutn(_("Warp factor- "))
4232 if game.damage[DWARPEN] > 10.0:
4233 prout(_("Warp engines inoperative."))
4235 if damaged(DWARPEN) and scanner.real > 4.0:
4236 prout(_("Engineer Scott- \"I'm doing my best, Captain,"))
4237 prout(_(" but right now we can only go warp 4.\""))
4239 if scanner.real > 10.0:
4240 prout(_("Helmsman Sulu- \"Our top speed is warp 10, Captain.\""))
4242 if scanner.real < 1.0:
4243 prout(_("Helmsman Sulu- \"We can't go below warp 1, Captain.\""))
4245 oldfac = game.warpfac
4246 game.warpfac = scanner.real
4247 if game.warpfac <= oldfac or game.warpfac <= 6.0:
4248 prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\"") %
4251 if game.warpfac < 8.00:
4252 prout(_("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\""))
4254 if game.warpfac == 10.0:
4255 prout(_("Engineer Scott- \"Aye, Captain, we'll try it.\""))
4257 prout(_("Engineer Scott- \"Aye, Captain, but our engines may not take it.\""))
4261 "Cope with being tossed out of quadrant by supernova or yanked by beam."
4263 # is captain on planet?
4265 if damaged(DTRANSP):
4268 prout(_("Scotty rushes to the transporter controls."))
4270 prout(_("But with the shields up it's hopeless."))
4272 prouts(_("His desperate attempt to rescue you . . ."))
4277 prout(_("SUCCEEDS!"))
4280 proutn(_("The crystals mined were "))
4288 # Check to see if captain in shuttle craft
4293 # Inform captain of attempt to reach safety
4297 prouts(_("***RED ALERT! RED ALERT!"))
4299 proutn(_("The %s has stopped in a quadrant containing") % crmshp())
4300 prouts(_(" a supernova."))
4302 prout(_("***Emergency automatic override attempts to hurl ")+crmshp())
4303 prout(_("safely out of quadrant."))
4304 if not damaged(DRADIO):
4305 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
4306 # Try to use warp engines
4307 if damaged(DWARPEN):
4309 prout(_("Warp engines damaged."))
4312 game.warpfac = randreal(6.0, 8.0)
4313 prout(_("Warp factor set to %d") % int(game.warpfac))
4314 power = 0.75*game.energy
4315 dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1))
4316 dist = max(dist, randreal(math.sqrt(2)))
4317 bugout = course(bearing=randreal(12), distance=dist) # How dumb!
4318 game.optime = bugout.time(game.warpfac)
4320 game.inorbit = False
4321 warp(bugout, involuntary=True)
4323 # This is bad news, we didn't leave quadrant.
4327 prout(_("Insufficient energy to leave quadrant."))
4330 # Repeat if another snova
4331 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
4333 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
4334 finish(FWON) # Snova killed remaining enemy.
4337 "Let's do the time warp again."
4338 prout(_("***TIME WARP ENTERED."))
4339 if game.state.snap and withprob(0.5):
4341 prout(_("You are traveling backwards in time %d stardates.") %
4342 int(game.state.date-game.snapsht.date))
4343 game.state = game.snapsht
4344 game.state.snap = False
4345 if len(game.state.kcmdr):
4346 schedule(FTBEAM, expran(game.intime/len(game.state.kcmdr)))
4347 schedule(FBATTAK, expran(0.3*game.intime))
4348 schedule(FSNOVA, expran(0.5*game.intime))
4349 # next snapshot will be sooner
4350 schedule(FSNAP, expran(0.25*game.state.remtime))
4352 if game.state.nscrem:
4353 schedule(FSCMOVE, 0.2777)
4357 game.battle.invalidate()
4358 # Make sure Galileo is consistant -- Snapshot may have been taken
4359 # when on planet, which would give us two Galileos!
4361 for l in range(game.inplan):
4362 if game.state.planets[l].known == "shuttle_down":
4364 if game.iscraft == "onship" and game.ship=='E':
4365 prout(_("Chekov- \"Security reports the Galileo has disappeared, Sir!"))
4366 game.iscraft = "offship"
4367 # Likewise, if in the original time the Galileo was abandoned, but
4368 # was on ship earlier, it would have vanished -- let's restore it.
4369 if game.iscraft == "offship" and not gotit and game.damage[DSHUTTL] >= 0.0:
4370 prout(_("Chekov- \"Security reports the Galileo has reappeared in the dock!\""))
4371 game.iscraft = "onship"
4372 # There used to be code to do the actual reconstrction here,
4373 # but the starchart is now part of the snapshotted galaxy state.
4374 prout(_("Spock has reconstructed a correct star chart from memory"))
4376 # Go forward in time
4377 game.optime = expran(0.5*game.intime)
4378 prout(_("You are traveling forward in time %d stardates.") % int(game.optime))
4379 # cheat to make sure no tractor beams occur during time warp
4380 postpone(FTBEAM, game.optime)
4381 game.damage[DRADIO] += game.optime
4383 events() # Stas Sergeev added this -- do pending events
4386 "Launch deep-space probe."
4387 # New code to launch a deep space probe
4388 if game.nprobes == 0:
4391 if game.ship == 'E':
4392 prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\""))
4394 prout(_("Ye Faerie Queene has no deep space probes."))
4399 prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\""))
4401 if is_scheduled(FDSPROB):
4404 if damaged(DRADIO) and game.condition != "docked":
4405 prout(_("Spock- \"Records show the previous probe has not yet"))
4406 prout(_(" reached its destination.\""))
4408 prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""))
4410 key = scanner.nexttok()
4412 if game.nprobes == 1:
4413 prout(_("1 probe left."))
4415 prout(_("%d probes left") % game.nprobes)
4416 proutn(_("Are you sure you want to fire a probe? "))
4419 game.isarmed = False
4420 if key == "IHALPHA" and scanner.token == "armed":
4422 key = scanner.nexttok()
4423 elif key == "IHEOL":
4424 proutn(_("Arm NOVAMAX warhead? "))
4426 elif key == "IHREAL": # first element of course
4427 scanner.push(scanner.token)
4429 game.probe = getcourse(isprobe=True)
4433 schedule(FDSPROB, 0.01) # Time to move one sector
4434 prout(_("Ensign Chekov- \"The deep space probe is launched, Captain.\""))
4439 "Yell for help from nearest starbase."
4440 # There's more than one way to move in this game!
4442 # Test for conditions which prevent calling for help
4443 if game.condition == "docked":
4444 prout(_("Lt. Uhura- \"But Captain, we're already docked.\""))
4447 prout(_("Subspace radio damaged."))
4449 if not game.state.baseq:
4450 prout(_("Lt. Uhura- \"Captain, I'm not getting any response from Starbase.\""))
4453 prout(_("You must be aboard the %s.") % crmshp())
4455 # OK -- call for help from nearest starbase
4458 # There's one in this quadrant
4459 ddist = (game.base - game.sector).distance()
4461 ibq = None # Force base-quadrant game to persist past loop
4463 for ibq in game.state.baseq:
4464 xdist = QUADSIZE * (ibq - game.quadrant).distance()
4468 prout(_("No starbases remain. You are alone in a hostile galaxy."))
4470 # Since starbase not in quadrant, set up new quadrant
4473 # dematerialize starship
4474 game.quad[game.sector.i][game.sector.j]='.'
4475 proutn(_("Starbase in Quadrant %s responds--%s dematerializes") \
4476 % (game.quadrant, crmshp()))
4477 game.sector.invalidate()
4478 for m in range(1, 5+1):
4479 w = game.base.scatter()
4480 if w.valid_sector() and game.quad[w.i][w.j]=='.':
4481 # found one -- finish up
4484 if not game.sector.is_valid():
4485 prout(_("You have been lost in space..."))
4486 finish(FMATERIALIZE)
4488 # Give starbase three chances to rematerialize starship
4489 probf = math.pow((1.0 - math.pow(0.98,ddist)), 0.33333333)
4490 for m in range(1, 3+1):
4491 if m == 1: proutn(_("1st"))
4492 elif m == 2: proutn(_("2nd"))
4493 elif m == 3: proutn(_("3rd"))
4494 proutn(_(" attempt to re-materialize ") + crmshp())
4495 game.quad[game.sector.i][game.sector.j]=('-','o','O')[m-1]
4498 if randreal() > probf:
4502 curses.delay_output(500)
4504 game.quad[game.sector.i][game.sector.j]='?'
4507 setwnd(message_window)
4508 finish(FMATERIALIZE)
4510 game.quad[game.sector.i][game.sector.j]=game.ship
4512 prout(_("succeeds."))
4516 prout(_("Lt. Uhura- \"Captain, we made it!\""))
4521 if game.condition=="docked":
4523 prout(_("You cannot abandon Ye Faerie Queene."))
4526 # Must take shuttle craft to exit
4527 if game.damage[DSHUTTL]==-1:
4528 prout(_("Ye Faerie Queene has no shuttle craft."))
4530 if game.damage[DSHUTTL]<0:
4531 prout(_("Shuttle craft now serving Big Macs."))
4533 if game.damage[DSHUTTL]>0:
4534 prout(_("Shuttle craft damaged."))
4537 prout(_("You must be aboard the ship."))
4539 if game.iscraft != "onship":
4540 prout(_("Shuttle craft not currently available."))
4542 # Emit abandon ship messages
4544 prouts(_("***ABANDON SHIP! ABANDON SHIP!"))
4546 prouts(_("***ALL HANDS ABANDON SHIP!"))
4548 prout(_("Captain and crew escape in shuttle craft."))
4549 if not game.state.baseq:
4550 # Oops! no place to go...
4553 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
4555 if not (game.options & OPTION_WORLDS) and not damaged(DTRANSP):
4556 prout(_("Remainder of ship's complement beam down"))
4557 prout(_("to nearest habitable planet."))
4558 elif q.planet != None and not damaged(DTRANSP):
4559 prout(_("Remainder of ship's complement beam down to %s.") %
4562 prout(_("Entire crew of %d left to die in outer space.") %
4564 game.casual += game.state.crew
4565 game.abandoned += game.state.crew
4566 # If at least one base left, give 'em the Faerie Queene
4568 game.icrystl = False # crystals are lost
4569 game.nprobes = 0 # No probes
4570 prout(_("You are captured by Klingons and released to"))
4571 prout(_("the Federation in a prisoner-of-war exchange."))
4572 nb = randrange(len(game.state.baseq))
4573 # Set up quadrant and position FQ adjacient to base
4574 if not game.quadrant == game.state.baseq[nb]:
4575 game.quadrant = game.state.baseq[nb]
4576 game.sector.i = game.sector.j = 5
4579 # position next to base by trial and error
4580 game.quad[game.sector.i][game.sector.j] = '.'
4582 for l in range(QUADSIZE):
4583 game.sector = game.base.scatter()
4584 if game.sector.valid_sector() and \
4585 game.quad[game.sector.i][game.sector.j] == '.':
4588 break # found a spot
4589 game.sector.i=QUADSIZE/2
4590 game.sector.j=QUADSIZE/2
4592 # Get new commission
4593 game.quad[game.sector.i][game.sector.j] = game.ship = 'F'
4594 game.state.crew = FULLCREW
4595 prout(_("Starfleet puts you in command of another ship,"))
4596 prout(_("the Faerie Queene, which is antiquated but,"))
4597 prout(_("still useable."))
4599 prout(_("The dilithium crystals have been moved."))
4601 game.iscraft = "offship" # Galileo disappears
4603 game.condition="docked"
4604 for l in range(NDEVICES):
4605 game.damage[l] = 0.0
4606 game.damage[DSHUTTL] = -1
4607 game.energy = game.inenrg = 3000.0
4608 game.shield = game.inshld = 1250.0
4609 game.torps = game.intorps = 6
4610 game.lsupres=game.inlsr=3.0
4613 game.brigfree = game.brigcapacity = 300
4616 # Code from planets.c begins here.
4619 "Abort a lengthy operation if an event interrupts it."
4622 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.justin:
4627 "Report on (uninhabited) planets in the galaxy."
4631 prout(_("Spock- \"Planet report follows, Captain.\""))
4633 for i in range(game.inplan):
4634 if game.state.planets[i].pclass == "destroyed":
4636 if (game.state.planets[i].known != "unknown" \
4637 and not game.state.planets[i].inhabited) \
4640 if game.idebug and game.state.planets[i].known=="unknown":
4641 proutn("(Unknown) ")
4642 proutn(_("Quadrant %s") % game.state.planets[i].quadrant)
4643 proutn(_(" class "))
4644 proutn(game.state.planets[i].pclass)
4646 if game.state.planets[i].crystals != "present":
4648 prout(_("dilithium crystals present."))
4649 if game.state.planets[i].known=="shuttle_down":
4650 prout(_(" Shuttle Craft Galileo on surface."))
4652 prout(_("No information available."))
4655 "Enter standard orbit."
4659 prout(_("Already in standard orbit."))
4661 if damaged(DWARPEN) and damaged(DIMPULS):
4662 prout(_("Both warp and impulse engines damaged."))
4664 if not game.plnet.is_valid():
4665 prout("There is no planet in this sector.")
4667 if abs(game.sector.i-game.plnet.i)>1 or abs(game.sector.j-game.plnet.j)>1:
4668 prout(crmshp() + _(" not adjacent to planet."))
4671 game.optime = randreal(0.02, 0.05)
4672 prout(_("Helmsman Sulu- \"Entering standard orbit, Sir.\""))
4676 game.height = randreal(1400, 8600)
4677 prout(_("Sulu- \"Entered orbit at altitude %.2f kilometers.\"") % game.height)
4682 "Examine planets in this quadrant."
4683 if damaged(DSRSENS):
4684 if game.options & OPTION_TTY:
4685 prout(_("Short range sensors damaged."))
4687 if game.iplnet is None:
4688 if game.options & OPTION_TTY:
4689 prout(_("Spock- \"No planet in this quadrant, Captain.\""))
4691 if game.iplnet.known == "unknown":
4692 prout(_("Spock- \"Sensor scan for Quadrant %s-") % game.quadrant)
4694 prout(_(" Planet at Sector %s is of class %s.") %
4695 (game.plnet, game.iplnet.pclass))
4696 if game.iplnet.known=="shuttle_down":
4697 prout(_(" Sensors show Galileo still on surface."))
4698 proutn(_(" Readings indicate"))
4699 if game.iplnet.crystals != "present":
4701 prout(_(" dilithium crystals present.\""))
4702 if game.iplnet.known == "unknown":
4703 game.iplnet.known = "known"
4704 elif game.iplnet.inhabited:
4705 prout(_("Spock- \"The inhabited planet %s ") % game.iplnet.name)
4706 prout(_(" is located at Sector %s, Captain.\"") % game.plnet)
4709 "Use the transporter."
4713 if damaged(DTRANSP):
4714 prout(_("Transporter damaged."))
4715 if not damaged(DSHUTTL) and (game.iplnet.known=="shuttle_down" or game.iscraft == "onship"):
4717 proutn(_("Spock- \"May I suggest the shuttle craft, Sir?\" "))
4721 if not game.inorbit:
4722 prout(crmshp() + _(" not in standard orbit."))
4725 prout(_("Impossible to transport through shields."))
4727 if game.iplnet.known=="unknown":
4728 prout(_("Spock- \"Captain, we have no information on this planet"))
4729 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4730 prout(_(" you may not go down.\""))
4732 if not game.landed and game.iplnet.crystals=="absent":
4733 prout(_("Spock- \"Captain, I fail to see the logic in"))
4734 prout(_(" exploring a planet with no dilithium crystals."))
4735 proutn(_(" Are you sure this is wise?\" "))
4739 if not (game.options & OPTION_PLAIN):
4740 nrgneed = 50 * game.skill + game.height / 100.0
4741 if nrgneed > game.energy:
4742 prout(_("Engineering to bridge--"))
4743 prout(_(" Captain, we don't have enough energy for transportation."))
4745 if not game.landed and nrgneed * 2 > game.energy:
4746 prout(_("Engineering to bridge--"))
4747 prout(_(" Captain, we have enough energy only to transport you down to"))
4748 prout(_(" the planet, but there wouldn't be an energy for the trip back."))
4749 if game.iplnet.known == "shuttle_down":
4750 prout(_(" Although the Galileo shuttle craft may still be on a surface."))
4751 proutn(_(" Are you sure this is wise?\" "))
4756 # Coming from planet
4757 if game.iplnet.known=="shuttle_down":
4758 proutn(_("Spock- \"Wouldn't you rather take the Galileo?\" "))
4762 prout(_("Your crew hides the Galileo to prevent capture by aliens."))
4763 prout(_("Landing party assembled, ready to beam up."))
4765 prout(_("Kirk whips out communicator..."))
4766 prouts(_("BEEP BEEP BEEP"))
4768 prout(_("\"Kirk to enterprise- Lock on coordinates...energize.\""))
4771 prout(_("Scotty- \"Transporter room ready, Sir.\""))
4773 prout(_("Kirk and landing party prepare to beam down to planet surface."))
4775 prout(_("Kirk- \"Energize.\""))
4778 prouts("WWHOOOIIIIIRRRRREEEE.E.E. . . . . . .")
4780 if not withprob(0.98):
4781 prouts("BOOOIIIOOOIIOOOOIIIOIING . . .")
4783 prout(_("Scotty- \"Oh my God! I've lost them.\""))
4786 prouts(". . . . . . .E.E.EEEERRRRRIIIIIOOOHWW")
4787 game.landed = not game.landed
4788 game.energy -= nrgneed
4790 prout(_("Transport complete."))
4791 if game.landed and game.iplnet.known=="shuttle_down":
4792 prout(_("The shuttle craft Galileo is here!"))
4793 if not game.landed and game.imine:
4800 "Strip-mine a world for dilithium."
4804 prout(_("Mining party not on planet."))
4806 if game.iplnet.crystals == "mined":
4807 prout(_("This planet has already been strip-mined for dilithium."))
4809 elif game.iplnet.crystals == "absent":
4810 prout(_("No dilithium crystals on this planet."))
4813 prout(_("You've already mined enough crystals for this trip."))
4815 if game.icrystl and game.cryprob == 0.05:
4816 prout(_("With all those fresh crystals aboard the ") + crmshp())
4817 prout(_("there's no reason to mine more at this time."))
4819 game.optime = randreal(0.1, 0.3)*(ord(game.iplnet.pclass)-ord("L"))
4822 prout(_("Mining operation complete."))
4823 game.iplnet.crystals = "mined"
4824 game.imine = game.ididit = True
4827 "Use dilithium crystals."
4831 if not game.icrystl:
4832 prout(_("No dilithium crystals available."))
4834 if game.energy >= 1000:
4835 prout(_("Spock- \"Captain, Starfleet Regulations prohibit such an operation"))
4836 prout(_(" except when Condition Yellow exists."))
4838 prout(_("Spock- \"Captain, I must warn you that loading"))
4839 prout(_(" raw dilithium crystals into the ship's power"))
4840 prout(_(" system may risk a severe explosion."))
4841 proutn(_(" Are you sure this is wise?\" "))
4846 prout(_("Engineering Officer Scott- \"(GULP) Aye Sir."))
4847 prout(_(" Mr. Spock and I will try it.\""))
4849 prout(_("Spock- \"Crystals in place, Sir."))
4850 prout(_(" Ready to activate circuit.\""))
4852 prouts(_("Scotty- \"Keep your fingers crossed, Sir!\""))
4854 if withprob(game.cryprob):
4855 prouts(_(" \"Activating now! - - No good! It's***"))
4857 prouts(_("***RED ALERT! RED A*L********************************"))
4860 prouts(_("****************** KA-BOOM!!!! *******************"))
4864 game.energy += randreal(5000.0, 5500.0)
4865 prouts(_(" \"Activating now! - - "))
4866 prout(_("The instruments"))
4867 prout(_(" are going crazy, but I think it's"))
4868 prout(_(" going to work!! Congratulations, Sir!\""))
4873 "Use shuttlecraft for planetary jaunt."
4876 if damaged(DSHUTTL):
4877 if game.damage[DSHUTTL] == -1.0:
4878 if game.inorbit and game.iplnet.known == "shuttle_down":
4879 prout(_("Ye Faerie Queene has no shuttle craft bay to dock it at."))
4881 prout(_("Ye Faerie Queene had no shuttle craft."))
4882 elif game.damage[DSHUTTL] > 0:
4883 prout(_("The Galileo is damaged."))
4884 else: # game.damage[DSHUTTL] < 0
4885 prout(_("Shuttle craft is now serving Big Macs."))
4887 if not game.inorbit:
4888 prout(crmshp() + _(" not in standard orbit."))
4890 if (game.iplnet.known != "shuttle_down") and game.iscraft != "onship":
4891 prout(_("Shuttle craft not currently available."))
4893 if not game.landed and game.iplnet.known=="shuttle_down":
4894 prout(_("You will have to beam down to retrieve the shuttle craft."))
4896 if game.shldup or game.condition == "docked":
4897 prout(_("Shuttle craft cannot pass through shields."))
4899 if game.iplnet.known=="unknown":
4900 prout(_("Spock- \"Captain, we have no information on this planet"))
4901 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4902 prout(_(" you may not fly down.\""))
4904 game.optime = 3.0e-5*game.height
4905 if game.optime >= 0.8*game.state.remtime:
4906 prout(_("First Officer Spock- \"Captain, I compute that such"))
4907 proutn(_(" a maneuver would require approximately %2d%% of our") % \
4908 int(100*game.optime/game.state.remtime))
4909 prout(_("remaining time."))
4910 proutn(_("Are you sure this is wise?\" "))
4916 if game.iscraft == "onship":
4918 if not damaged(DTRANSP):
4919 proutn(_("Spock- \"Would you rather use the transporter?\" "))
4923 proutn(_("Shuttle crew"))
4925 proutn(_("Rescue party"))
4926 prout(_(" boards Galileo and swoops toward planet surface."))
4927 game.iscraft = "offship"
4931 game.iplnet.known="shuttle_down"
4932 prout(_("Trip complete."))
4935 # Ready to go back to ship
4936 prout(_("You and your mining party board the"))
4937 prout(_("shuttle craft for the trip back to the Enterprise."))
4939 prouts(_("The short hop begins . . ."))
4941 game.iplnet.known="known"
4947 game.iscraft = "onship"
4953 prout(_("Trip complete."))
4956 # Kirk on ship and so is Galileo
4957 prout(_("Mining party assembles in the hangar deck,"))
4958 prout(_("ready to board the shuttle craft \"Galileo\"."))
4960 prouts(_("The hangar doors open; the trip begins."))
4963 game.iscraft = "offship"
4966 game.iplnet.known = "shuttle_down"
4969 prout(_("Trip complete."))
4973 "Use the big zapper."
4977 if game.ship != 'E':
4978 prout(_("Ye Faerie Queene has no death ray."))
4980 if len(game.enemies)==0:
4981 prout(_("Sulu- \"But Sir, there are no enemies in this quadrant.\""))
4984 prout(_("Death Ray is damaged."))
4986 prout(_("Spock- \"Captain, the 'Experimental Death Ray'"))
4987 prout(_(" is highly unpredictible. Considering the alternatives,"))
4988 proutn(_(" are you sure this is wise?\" "))
4991 prout(_("Spock- \"Acknowledged.\""))
4994 prouts(_("WHOOEE ... WHOOEE ... WHOOEE ... WHOOEE"))
4996 prout(_("Crew scrambles in emergency preparation."))
4997 prout(_("Spock and Scotty ready the death ray and"))
4998 prout(_("prepare to channel all ship's power to the device."))
5000 prout(_("Spock- \"Preparations complete, sir.\""))
5001 prout(_("Kirk- \"Engage!\""))
5003 prouts(_("WHIRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"))
5006 if game.options & OPTION_PLAIN:
5010 prouts(_("Sulu- \"Captain! It's working!\""))
5012 while len(game.enemies) > 0:
5013 deadkl(game.enemies[1].location, game.quad[game.enemies[1].location.i][game.enemies[1].location.j],game.enemies[1].location)
5014 prout(_("Ensign Chekov- \"Congratulations, Captain!\""))
5015 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
5017 if (game.options & OPTION_PLAIN) == 0:
5018 prout(_("Spock- \"Captain, I believe the `Experimental Death Ray'"))
5020 prout(_(" is still operational.\""))
5022 prout(_(" has been rendered nonfunctional.\""))
5023 game.damage[DDRAY] = 39.95
5025 r = randreal() # Pick failure method
5027 prouts(_("Sulu- \"Captain! It's working!\""))
5029 prouts(_("***RED ALERT! RED ALERT!"))
5031 prout(_("***MATTER-ANTIMATTER IMPLOSION IMMINENT!"))
5033 prouts(_("***RED ALERT! RED A*L********************************"))
5036 prouts(_("****************** KA-BOOM!!!! *******************"))
5041 prouts(_("Sulu- \"Captain! Yagabandaghangrapl, brachriigringlanbla!\""))
5043 prout(_("Lt. Uhura- \"Graaeek! Graaeek!\""))
5045 prout(_("Spock- \"Fascinating! . . . All humans aboard"))
5046 prout(_(" have apparently been transformed into strange mutations."))
5047 prout(_(" Vulcans do not seem to be affected."))
5049 prout(_("Kirk- \"Raauch! Raauch!\""))
5053 prouts(_("Sulu- \"Captain! It's --WHAT?!?!\""))
5055 proutn(_("Spock- \"I believe the word is"))
5056 prouts(_(" *ASTONISHING*"))
5057 prout(_(" Mr. Sulu."))
5058 for i in range(QUADSIZE):
5059 for j in range(QUADSIZE):
5060 if game.quad[i][j] == '.':
5061 game.quad[i][j] = '?'
5062 prout(_(" Captain, our quadrant is now infested with"))
5063 prouts(_(" - - - - - - *THINGS*."))
5065 prout(_(" I have no logical explanation.\""))
5067 prouts(_("Sulu- \"Captain! The Death Ray is creating tribbles!\""))
5069 prout(_("Scotty- \"There are so many tribbles down here"))
5070 prout(_(" in Engineering, we can't move for 'em, Captain.\""))
5074 # Code from reports.c begins here
5076 def attackreport(curt):
5077 "eport status of bases under attack."
5079 if is_scheduled(FCDBAS):
5080 prout(_("Starbase in Quadrant %s is currently under Commander attack.") % game.battle)
5081 prout(_("It can hold out until Stardate %d.") % int(scheduled(FCDBAS)))
5082 elif game.isatb == 1:
5083 prout(_("Starbase in Quadrant %s is under Super-commander attack.") % game.state.kscmdr)
5084 prout(_("It can hold out until Stardate %d.") % int(scheduled(FSCDBAS)))
5086 prout(_("No Starbase is currently under attack."))
5088 if is_scheduled(FCDBAS):
5089 proutn(_("Base in %s attacked by C. Alive until %.1f") % (game.battle, scheduled(FCDBAS)))
5091 proutn(_("Base in %s attacked by S. Alive until %.1f") % (game.state.kscmdr, scheduled(FSCDBAS)))
5095 # report on general game status
5097 s1 = (game.thawed and _("thawed ")) or ""
5098 s2 = {1:"short", 2:"medium", 4:"long"}[game.length]
5099 s3 = (None, _("novice"), _("fair"),
5100 _("good"), _("expert"), _("emeritus"))[game.skill]
5101 prout(_("You %s a %s%s %s game.") % ((_("were playing"), _("are playing"))[game.alldone], s1, s2, s3))
5102 if game.skill>SKILL_GOOD and game.thawed and not game.alldone:
5103 prout(_("No plaque is allowed."))
5105 prout(_("This is tournament game %d.") % game.tourn)
5106 prout(_("Your secret password is \"%s\"") % game.passwd)
5107 proutn(_("%d of %d Klingons have been killed") % (((game.inkling + game.incom + game.inscom) - (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)),
5108 (game.inkling + game.incom + game.inscom)))
5109 if game.incom - len(game.state.kcmdr):
5110 prout(_(", including %d Commander%s.") % (game.incom - len(game.state.kcmdr), (_("s"), "")[(game.incom - len(game.state.kcmdr))==1]))
5111 elif game.inkling - game.state.remkl + (game.inscom - game.state.nscrem) > 0:
5112 prout(_(", but no Commanders."))
5115 if game.skill > SKILL_FAIR:
5116 prout(_("The Super Commander has %sbeen destroyed.") % ("", _("not "))[game.state.nscrem])
5117 if len(game.state.baseq) != game.inbase:
5119 if game.inbase-len(game.state.baseq)==1:
5120 proutn(_("has been 1 base"))
5122 proutn(_("have been %d bases") % (game.inbase-len(game.state.baseq)))
5123 prout(_(" destroyed, %d remaining.") % len(game.state.baseq))
5125 prout(_("There are %d bases.") % game.inbase)
5126 if communicating() or game.iseenit:
5127 # Don't report this if not seen and
5128 # either the radio is dead or not at base!
5132 prout(_("%d casualt%s suffered so far.") % (game.casual, ("y", "ies")[game.casual!=1]))
5133 if game.brigcapacity != game.brigfree:
5134 embriggened = brigcapacity-brigfree
5135 if embriggened == 1:
5136 prout(_("1 Klingon in brig"))
5138 prout(_("%d Klingons in brig.") % embriggened)
5139 if game.kcaptured == 0:
5141 elif game.kcaptured == 1:
5142 prout(_("1 captured Klingon turned in to Starfleet."))
5144 prout(_("%d captured Klingons turned in to Star Fleet.") % game.kcaptured)
5146 prout(_("There were %d call%s for help.") % (game.nhelp, ("" , _("s"))[game.nhelp!=1]))
5147 if game.ship == 'E':
5148 proutn(_("You have "))
5150 proutn("%d" % (game.nprobes))
5153 proutn(_(" deep space probe"))
5157 if communicating() and is_scheduled(FDSPROB):
5159 proutn(_("An armed deep space probe is in "))
5161 proutn(_("A deep space probe is in "))
5162 prout("Quadrant %s." % game.probe.quadrant())
5164 if game.cryprob <= .05:
5165 prout(_("Dilithium crystals aboard ship... not yet used."))
5169 while game.cryprob > ai:
5172 prout(_("Dilithium crystals have been used %d time%s.") % \
5173 (i, (_("s"), "")[i==1]))
5177 "Long-range sensor scan."
5178 if damaged(DLRSENS):
5179 # Now allow base's sensors if docked
5180 if game.condition != "docked":
5182 prout(_("LONG-RANGE SENSORS DAMAGED."))
5185 prout(_("Starbase's long-range scan"))
5187 prout(_("Long-range scan"))
5188 for x in range(game.quadrant.i-1, game.quadrant.i+2):
5191 for y in range(game.quadrant.j-1, game.quadrant.j+2):
5192 if not Coord(x, y).valid_quadrant():
5196 if not damaged(DRADIO):
5197 game.state.galaxy[x][y].charted = True
5198 game.state.chart[x][y].klingons = game.state.galaxy[x][y].klingons
5199 game.state.chart[x][y].starbase = game.state.galaxy[x][y].starbase
5200 game.state.chart[x][y].stars = game.state.galaxy[x][y].stars
5201 if not silent and game.state.galaxy[x][y].supernova:
5204 proutn(" %3d" % (game.state.chart[x][y].klingons*100 + game.state.chart[x][y].starbase * 10 + game.state.chart[x][y].stars))
5212 for i in range(NDEVICES):
5215 prout(_("\tDEVICE\t\t\t-REPAIR TIMES-"))
5216 prout(_("\t\t\tIN FLIGHT\t\tDOCKED"))
5218 prout(" %-26s\t%8.2f\t\t%8.2f" % (device[i],
5219 game.damage[i]+0.05,
5220 DOCKFAC*game.damage[i]+0.005))
5222 prout(_("All devices functional."))
5225 "Update the chart in the Enterprise's computer from galaxy data."
5226 game.lastchart = game.state.date
5227 for i in range(GALSIZE):
5228 for j in range(GALSIZE):
5229 if game.state.galaxy[i][j].charted:
5230 game.state.chart[i][j].klingons = game.state.galaxy[i][j].klingons
5231 game.state.chart[i][j].starbase = game.state.galaxy[i][j].starbase
5232 game.state.chart[i][j].stars = game.state.galaxy[i][j].stars
5235 "Display the star chart."
5237 if (game.options & OPTION_AUTOSCAN):
5239 if not damaged(DRADIO):
5241 if game.lastchart < game.state.date and game.condition == "docked":
5242 prout(_("Spock- \"I revised the Star Chart from the starbase's records.\""))
5244 prout(_(" STAR CHART FOR THE KNOWN GALAXY"))
5245 if game.state.date > game.lastchart:
5246 prout(_("(Last surveillance update %d stardates ago).") % ((int)(game.state.date-game.lastchart)))
5247 prout(" 1 2 3 4 5 6 7 8")
5248 for i in range(GALSIZE):
5249 proutn("%d |" % (i+1))
5250 for j in range(GALSIZE):
5251 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5255 if game.state.galaxy[i][j].supernova:
5257 elif not game.state.galaxy[i][j].charted and game.state.galaxy[i][j].starbase:
5259 elif game.state.galaxy[i][j].charted:
5260 show = "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars)
5264 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5272 def sectscan(goodScan, i, j):
5273 "Light up an individual dot in a sector."
5274 if goodScan or (abs(i-game.sector.i)<= 1 and abs(j-game.sector.j) <= 1):
5275 if game.quad[i][j] in ('E', 'F'):
5276 textcolor({"green":GREEN,
5280 "dead":BROWN}[game.condition])
5282 textcolor({'?':LIGHTMAGENTA,
5288 }.get(game.quad[i][j], DEFAULT))
5291 proutn("%c " % game.quad[i][j])
5297 "Emit status report lines"
5298 if not req or req == 1:
5299 prstat(_("Stardate"), _("%.1f, Time Left %.2f") \
5300 % (game.state.date, game.state.remtime))
5301 if not req or req == 2:
5302 if game.condition != "docked":
5304 prstat(_("Condition"), _("%s, %i DAMAGES") % \
5305 (game.condition.upper(), sum([x > 0 for x in game.damage])))
5307 prout(_(", CLOAKED"))
5308 if not req or req == 3:
5309 prstat(_("Position"), "%s , %s" % (game.quadrant, game.sector))
5310 if not req or req == 4:
5311 if damaged(DLIFSUP):
5312 if game.condition == "docked":
5313 s = _("DAMAGED, Base provides")
5315 s = _("DAMAGED, reserves=%4.2f") % game.lsupres
5318 prstat(_("Life Support"), s)
5319 if not req or req == 5:
5320 prstat(_("Warp Factor"), "%.1f" % game.warpfac)
5321 if not req or req == 6:
5323 if game.icrystl and (game.options & OPTION_SHOWME):
5324 extra = _(" (have crystals)")
5325 prstat(_("Energy"), "%.2f%s" % (game.energy, extra))
5326 if not req or req == 7:
5327 prstat(_("Torpedoes"), "%d" % (game.torps))
5328 if not req or req == 8:
5329 if damaged(DSHIELD):
5335 data = _(" %d%% %.1f units") \
5336 % (int((100.0*game.shield)/game.inshld + 0.5), game.shield)
5337 prstat(_("Shields"), s+data)
5338 if not req or req == 9:
5339 prstat(_("Klingons Left"), "%d" \
5340 % (game.state.remkl+len(game.state.kcmdr)+game.state.nscrem))
5341 if not req or req == 10:
5342 if game.options & OPTION_WORLDS:
5343 plnet = game.state.galaxy[game.quadrant.i][game.quadrant.j].planet
5344 if plnet and plnet.inhabited:
5345 prstat(_("Major system"), plnet.name)
5347 prout(_("Sector is uninhabited"))
5348 elif not req or req == 11:
5349 attackreport(not req)
5352 "Request specified status data, a historical relic from slow TTYs."
5353 requests = ("da","co","po","ls","wa","en","to","sh","kl","sy", "ti")
5354 while scanner.nexttok() == "IHEOL":
5355 proutn(_("Information desired? "))
5357 if scanner.token in requests:
5358 status(requests.index(scanner.token))
5360 prout(_("UNRECOGNIZED REQUEST. Legal requests are:"))
5361 prout((" date, condition, position, lsupport, warpfactor,"))
5362 prout((" energy, torpedoes, shields, klingons, system, time."))
5367 if damaged(DSRSENS):
5368 # Allow base's sensors if docked
5369 if game.condition != "docked":
5370 prout(_(" S.R. SENSORS DAMAGED!"))
5373 prout(_(" [Using Base's sensors]"))
5375 prout(_(" Short-range scan"))
5376 if goodScan and not damaged(DRADIO):
5377 game.state.chart[game.quadrant.i][game.quadrant.j].klingons = game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons
5378 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase
5379 game.state.chart[game.quadrant.i][game.quadrant.j].stars = game.state.galaxy[game.quadrant.i][game.quadrant.j].stars
5380 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
5381 prout(" 1 2 3 4 5 6 7 8 9 10")
5382 if game.condition != "docked":
5384 for i in range(QUADSIZE):
5385 proutn("%2d " % (i+1))
5386 for j in range(QUADSIZE):
5387 sectscan(goodScan, i, j)
5391 "Use computer to get estimated time of arrival for a warp jump."
5392 w1 = Coord(); w2 = Coord()
5394 if damaged(DCOMPTR):
5395 prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR."))
5398 if scanner.nexttok() != "IHREAL":
5401 proutn(_("Destination quadrant and/or sector? "))
5402 if scanner.nexttok()!="IHREAL":
5405 w1.j = int(scanner.real-0.5)
5406 if scanner.nexttok() != "IHREAL":
5409 w1.i = int(scanner.real-0.5)
5410 if scanner.nexttok() == "IHREAL":
5411 w2.j = int(scanner.real-0.5)
5412 if scanner.nexttok() != "IHREAL":
5415 w2.i = int(scanner.real-0.5)
5417 if game.quadrant.j>w1.i:
5421 if game.quadrant.i>w1.j:
5425 if not w1.valid_quadrant() or not w2.valid_sector():
5428 dist = math.sqrt((w1.j-game.quadrant.j+(w2.j-game.sector.j)/(QUADSIZE*1.0))**2+
5429 (w1.i-game.quadrant.i+(w2.i-game.sector.i)/(QUADSIZE*1.0))**2)
5432 prout(_("Answer \"no\" if you don't know the value:"))
5435 proutn(_("Time or arrival date? "))
5436 if scanner.nexttok()=="IHREAL":
5437 ttime = scanner.real
5438 if ttime > game.state.date:
5439 ttime -= game.state.date # Actually a star date
5440 twarp=(math.floor(math.sqrt((10.0*dist)/ttime)*10.0)+1.0)/10.0
5441 if ttime <= 1e-10 or twarp > 10:
5442 prout(_("We'll never make it, sir."))
5449 proutn(_("Warp factor? "))
5450 if scanner.nexttok()== "IHREAL":
5452 twarp = scanner.real
5453 if twarp<1.0 or twarp > 10.0:
5457 prout(_("Captain, certainly you can give me one of these."))
5460 ttime = (10.0*dist)/twarp**2
5461 tpower = dist*twarp*twarp*twarp*(game.shldup+1)
5462 if tpower >= game.energy:
5463 prout(_("Insufficient energy, sir."))
5464 if not game.shldup or tpower > game.energy*2.0:
5467 proutn(_("New warp factor to try? "))
5468 if scanner.nexttok() == "IHREAL":
5470 twarp = scanner.real
5471 if twarp<1.0 or twarp > 10.0:
5479 prout(_("But if you lower your shields,"))
5480 proutn(_("remaining"))
5483 proutn(_("Remaining"))
5484 prout(_(" energy will be %.2f.") % (game.energy-tpower))
5486 prout(_("And we will arrive at stardate %.2f.") % (game.state.date+ttime))
5488 prout(_("Any warp speed is adequate."))
5490 prout(_("Minimum warp needed is %.2f,") % (twarp))
5491 prout(_("and we will arrive at stardate %.2f.") % (game.state.date+ttime))
5492 if game.state.remtime < ttime:
5493 prout(_("Unfortunately, the Federation will be destroyed by then."))
5495 prout(_("You'll be taking risks at that speed, Captain"))
5496 if (game.isatb==1 and game.state.kscmdr == w1 and \
5497 scheduled(FSCDBAS)< ttime+game.state.date) or \
5498 (scheduled(FCDBAS)<ttime+game.state.date and game.battle == w1):
5499 prout(_("The starbase there will be destroyed by then."))
5500 proutn(_("New warp factor to try? "))
5501 if scanner.nexttok() == "IHREAL":
5503 twarp = scanner.real
5504 if twarp<1.0 or twarp > 10.0:
5512 # Code from setup.c begins here
5515 "Issue a historically correct banner."
5517 prout(_("-SUPER- STAR TREK"))
5519 # From the FORTRAN original
5520 # prout(_("Latest update-21 Sept 78"))
5526 scanner.push("emsave.trk")
5527 key = scanner.nexttok()
5529 proutn(_("File name: "))
5530 key = scanner.nexttok()
5531 if key != "IHALPHA":
5534 if '.' not in scanner.token:
5535 scanner.token += ".trk"
5537 fp = open(scanner.token, "wb")
5539 prout(_("Can't freeze game as file %s") % scanner.token)
5541 pickle.dump(game, fp)
5546 "Retrieve saved game."
5549 key = scanner.nexttok()
5551 proutn(_("File name: "))
5552 key = scanner.nexttok()
5553 if key != "IHALPHA":
5556 if '.' not in scanner.token:
5557 scanner.token += ".trk"
5559 fp = open(scanner.token, "rb")
5561 prout(_("Can't thaw game in %s") % scanner.token)
5563 game = pickle.load(fp)
5568 # I used <http://www.memory-alpha.org> to find planets
5569 # with references in ST:TOS. Earth and the Alpha Centauri
5570 # Colony have been omitted.
5572 # Some planets marked Class G and P here will be displayed as class M
5573 # because of the way planets are generated. This is a known bug.
5576 _("Andoria (Fesoan)"), # several episodes
5577 _("Tellar Prime (Miracht)"), # TOS: "Journey to Babel"
5578 _("Vulcan (T'Khasi)"), # many episodes
5579 _("Medusa"), # TOS: "Is There in Truth No Beauty?"
5580 _("Argelius II (Nelphia)"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5581 _("Ardana"), # TOS: "The Cloud Minders"
5582 _("Catulla (Cendo-Prae)"), # TOS: "The Way to Eden"
5583 _("Gideon"), # TOS: "The Mark of Gideon"
5584 _("Aldebaran III"), # TOS: "The Deadly Years"
5585 _("Alpha Majoris I"), # TOS: "Wolf in the Fold"
5586 _("Altair IV"), # TOS: "Amok Time
5587 _("Ariannus"), # TOS: "Let That Be Your Last Battlefield"
5588 _("Benecia"), # TOS: "The Conscience of the King"
5589 _("Beta Niobe I (Sarpeidon)"), # TOS: "All Our Yesterdays"
5590 _("Alpha Carinae II"), # TOS: "The Ultimate Computer"
5591 _("Capella IV (Kohath)"), # TOS: "Friday's Child" (Class G)
5592 _("Daran V"), # TOS: "For the World is Hollow and I Have Touched the Sky"
5593 _("Deneb II"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5594 _("Eminiar VII"), # TOS: "A Taste of Armageddon"
5595 _("Gamma Canaris IV"), # TOS: "Metamorphosis"
5596 _("Gamma Tranguli VI (Vaalel)"), # TOS: "The Apple"
5597 _("Ingraham B"), # TOS: "Operation: Annihilate"
5598 _("Janus IV"), # TOS: "The Devil in the Dark"
5599 _("Makus III"), # TOS: "The Galileo Seven"
5600 _("Marcos XII"), # TOS: "And the Children Shall Lead",
5601 _("Omega IV"), # TOS: "The Omega Glory"
5602 _("Regulus V"), # TOS: "Amok Time
5603 _("Deneva"), # TOS: "Operation -- Annihilate!"
5604 # Worlds from BSD Trek
5605 _("Rigel II"), # TOS: "Shore Leave" ("III" in BSD)
5606 _("Beta III"), # TOS: "The Return of the Archons"
5607 _("Triacus"), # TOS: "And the Children Shall Lead",
5608 _("Exo III"), # TOS: "What Are Little Girls Made Of?" (Class P)
5610 # _("Hansen's Planet"), # TOS: "The Galileo Seven"
5611 # _("Taurus IV"), # TOS: "The Galileo Seven" (class G)
5612 # _("Antos IV (Doraphane)"), # TOS: "Whom Gods Destroy", "Who Mourns for Adonais?"
5613 # _("Izar"), # TOS: "Whom Gods Destroy"
5614 # _("Tiburon"), # TOS: "The Way to Eden"
5615 # _("Merak II"), # TOS: "The Cloud Minders"
5616 # _("Coridan (Desotriana)"), # TOS: "Journey to Babel"
5617 # _("Iotia"), # TOS: "A Piece of the Action"
5621 _("S. R. Sensors"), \
5622 _("L. R. Sensors"), \
5624 _("Photon Tubes"), \
5625 _("Life Support"), \
5626 _("Warp Engines"), \
5627 _("Impulse Engines"), \
5629 _("Subspace Radio"), \
5630 _("Shuttle Craft"), \
5632 _("Navigation System"), \
5634 _("Shield Control"), \
5637 _("Cloaking Device"), \
5641 "Prepare to play, set up cosmos."
5643 # Decide how many of everything
5645 return # frozen game
5646 # Prepare the Enterprise
5647 game.alldone = game.gamewon = game.shldchg = game.shldup = False
5649 game.state.crew = FULLCREW
5650 game.energy = game.inenrg = 5000.0
5651 game.shield = game.inshld = 2500.0
5654 game.quadrant = randplace(GALSIZE)
5655 game.sector = randplace(QUADSIZE)
5656 game.torps = game.intorps = 10
5657 game.nprobes = randrange(2, 5)
5659 for i in range(NDEVICES):
5660 game.damage[i] = 0.0
5661 # Set up assorted game parameters
5662 game.battle = Coord()
5663 game.state.date = game.indate = 100.0 * randreal(20, 51)
5664 game.nkinks = game.nhelp = game.casual = game.abandoned = 0
5665 game.iscate = game.resting = game.imine = game.icrystl = game.icraft = False
5666 game.isatb = game.state.nplankl = 0
5667 game.state.starkl = game.state.basekl = game.state.nworldkl = 0
5668 game.iscraft = "onship"
5673 game.state.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
5675 game.state.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
5677 game.state.planets = [] # Planet information
5678 game.state.baseq = [] # Base quadrant coordinates
5679 game.state.kcmdr = [] # Commander quadrant coordinates
5680 game.statekscmdr = Coord() # Supercommander quadrant coordinates
5682 # Starchart is functional but we've never seen it
5683 game.lastchart = FOREVER
5684 # Put stars in the galaxy
5686 for i in range(GALSIZE):
5687 for j in range(GALSIZE):
5688 # Can't have more stars per quadrant than fit in one decimal digit,
5689 # if we do the chart representation will break.
5690 k = randrange(1, min(10, QUADSIZE**2/10))
5692 game.state.galaxy[i][j].stars = k
5693 # Locate star bases in galaxy
5695 prout("=== Allocating %d bases" % game.inbase)
5696 for i in range(game.inbase):
5699 w = randplace(GALSIZE)
5700 if not game.state.galaxy[w.i][w.j].starbase:
5703 # C version: for (j = i-1; j > 0; j--)
5704 # so it did them in the opposite order.
5705 for j in range(1, i):
5706 # Improved placement algorithm to spread out bases
5707 distq = (w - game.state.baseq[j]).distance()
5708 if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75):
5711 prout("=== Abandoning base #%d at %s" % (i, w))
5713 elif distq < 6.0 * (BASEMAX+1-game.inbase):
5715 prout("=== Saving base #%d, close to #%d" % (i, j))
5719 prout("=== Placing base #%d in quadrant %s" % (i, w))
5720 game.state.baseq.append(w)
5721 game.state.galaxy[w.i][w.j].starbase = game.state.chart[w.i][w.j].starbase = True
5722 # Position ordinary Klingon Battle Cruisers
5724 klumper = 0.25*game.skill*(9.0-game.length)+1.0
5725 if klumper > MAXKLQUAD:
5729 klump = (1.0 - r*r)*klumper
5734 w = randplace(GALSIZE)
5735 if not game.state.galaxy[w.i][w.j].supernova and \
5736 game.state.galaxy[w.i][w.j].klingons + klump <= MAXKLQUAD:
5738 game.state.galaxy[w.i][w.j].klingons += int(klump)
5741 # Position Klingon Commander Ships
5742 for i in range(game.incom):
5744 w = randplace(GALSIZE)
5745 if not welcoming(w) or w in game.state.kcmdr:
5747 if (game.state.galaxy[w.i][w.j].klingons or withprob(0.25)):
5749 game.state.galaxy[w.i][w.j].klingons += 1
5750 game.state.kcmdr.append(w)
5751 # Locate planets in galaxy
5752 for i in range(game.inplan):
5754 w = randplace(GALSIZE)
5755 if game.state.galaxy[w.i][w.j].planet is None:
5759 new.crystals = "absent"
5760 if (game.options & OPTION_WORLDS) and i < NINHAB:
5761 new.pclass = "M" # All inhabited planets are class M
5762 new.crystals = "absent"
5764 new.name = systnames[i]
5765 new.inhabited = True
5767 new.pclass = ("M", "N", "O")[randrange(0, 3)]
5769 new.crystals = "present"
5770 new.known = "unknown"
5771 new.inhabited = False
5772 game.state.galaxy[w.i][w.j].planet = new
5773 game.state.planets.append(new)
5775 for i in range(game.state.nromrem):
5776 w = randplace(GALSIZE)
5777 game.state.galaxy[w.i][w.j].romulans += 1
5778 # Place the Super-Commander if needed
5779 if game.state.nscrem > 0:
5781 w = randplace(GALSIZE)
5784 game.state.kscmdr = w
5785 game.state.galaxy[w.i][w.j].klingons += 1
5786 # Initialize times for extraneous events
5787 schedule(FSNOVA, expran(0.5 * game.intime))
5788 schedule(FTBEAM, expran(1.5 * (game.intime / len(game.state.kcmdr))))
5789 schedule(FSNAP, randreal(1.0, 2.0)) # Force an early snapshot
5790 schedule(FBATTAK, expran(0.3*game.intime))
5792 if game.state.nscrem:
5793 schedule(FSCMOVE, 0.2777)
5798 if (game.options & OPTION_WORLDS) and game.skill >= SKILL_GOOD:
5799 schedule(FDISTR, expran(1.0 + game.intime))
5804 # Place thing (in tournament game, we don't want one!)
5805 # New in SST2K: never place the Thing near a starbase.
5806 # This makes sense and avoids a special case in the old code.
5808 if game.tourn is None:
5810 thing = randplace(GALSIZE)
5811 if thing not in game.state.baseq:
5814 game.state.snap = False
5815 if game.skill == SKILL_NOVICE:
5816 prout(_("It is stardate %d. The Federation is being attacked by") % int(game.state.date))
5817 prout(_("a deadly Klingon invasion force. As captain of the United"))
5818 prout(_("Starship U.S.S. Enterprise, it is your mission to seek out"))
5819 prout(_("and destroy this invasion force of %d battle cruisers.") % ((game.inkling + game.incom + game.inscom)))
5820 prout(_("You have an initial allotment of %d stardates to complete") % int(game.intime))
5821 prout(_("your mission. As you proceed you may be given more time."))
5823 prout(_("You will have %d supporting starbases.") % (game.inbase))
5824 proutn(_("Starbase locations- "))
5826 prout(_("Stardate %d.") % int(game.state.date))
5828 prout(_("%d Klingons.") % (game.inkling + game.incom + game.inscom))
5829 prout(_("An unknown number of Romulans."))
5830 if game.state.nscrem:
5831 prout(_("And one (GULP) Super-Commander."))
5832 prout(_("%d stardates.") % int(game.intime))
5833 proutn(_("%d starbases in ") % game.inbase)
5834 for i in range(game.inbase):
5835 proutn(repr(game.state.baseq[i]))
5838 proutn(_("The Enterprise is currently in Quadrant %s") % game.quadrant)
5839 proutn(_(" Sector %s") % game.sector)
5841 prout(_("Good Luck!"))
5842 if game.state.nscrem:
5843 prout(_(" YOU'LL NEED IT."))
5846 setwnd(message_window)
5848 if len(game.enemies) - (thing == game.quadrant) - (game.tholian != None):
5850 if game.neutz: # bad luck to start in a Romulan Neutral Zone
5851 attack(torps_ok=False)
5854 "Choose your game type."
5856 game.tourn = game.length = 0
5858 game.skill = SKILL_NONE
5860 # if not scanner.inqueue: # Can start with command line options
5861 proutn(_("Would you like a regular, tournament, or saved game? "))
5863 if scanner.sees("tournament"):
5864 while scanner.nexttok() == "IHEOL":
5865 proutn(_("Type in tournament number-"))
5866 if scanner.real == 0:
5868 continue # We don't want a blank entry
5869 game.tourn = int(round(scanner.real))
5870 random.seed(scanner.real)
5872 logfp.write("# random.seed(%d)\n" % scanner.real)
5874 if scanner.sees("saved") or scanner.sees("frozen"):
5878 if game.passwd is None:
5880 if not game.alldone:
5881 game.thawed = True # No plaque if not finished
5885 if scanner.sees("regular"):
5887 proutn(_("What is \"%s\"? ") % scanner.token)
5889 while game.length==0 or game.skill==SKILL_NONE:
5890 if scanner.nexttok() == "IHALPHA":
5891 if scanner.sees("short"):
5893 elif scanner.sees("medium"):
5895 elif scanner.sees("long"):
5897 elif scanner.sees("novice"):
5898 game.skill = SKILL_NOVICE
5899 elif scanner.sees("fair"):
5900 game.skill = SKILL_FAIR
5901 elif scanner.sees("good"):
5902 game.skill = SKILL_GOOD
5903 elif scanner.sees("expert"):
5904 game.skill = SKILL_EXPERT
5905 elif scanner.sees("emeritus"):
5906 game.skill = SKILL_EMERITUS
5908 proutn(_("What is \""))
5909 proutn(scanner.token)
5914 proutn(_("Would you like a Short, Medium, or Long game? "))
5915 elif game.skill == SKILL_NONE:
5916 proutn(_("Are you a Novice, Fair, Good, Expert, or Emeritus player? "))
5917 # Choose game options -- added by ESR for SST2K
5918 if scanner.nexttok() != "IHALPHA":
5920 proutn(_("Choose your game style (plain, almy, fancy or just press enter): "))
5922 if scanner.sees("plain"):
5923 # Approximates the UT FORTRAN version.
5924 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)
5925 game.options |= OPTION_PLAIN
5926 elif scanner.sees("almy"):
5927 # Approximates Tom Almy's version.
5928 game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS | OPTION_COLOR)
5929 game.options |= OPTION_ALMY
5930 elif scanner.sees("fancy") or scanner.sees("\n"):
5932 elif len(scanner.token):
5933 proutn(_("What is \"%s\"?") % scanner.token)
5935 if game.passwd == "debug":
5937 prout("=== Debug mode enabled.")
5938 # Use parameters to generate initial values of things
5939 game.damfac = 0.5 * game.skill
5940 game.inbase = randrange(BASEMIN, BASEMAX+1)
5942 if game.options & OPTION_PLANETS:
5943 game.inplan += randrange(MAXUNINHAB/2, MAXUNINHAB+1)
5944 if game.options & OPTION_WORLDS:
5945 game.inplan += int(NINHAB)
5946 game.state.nromrem = game.inrom = randrange(2 * game.skill)
5947 game.state.nscrem = game.inscom = (game.skill > SKILL_FAIR)
5948 game.state.remtime = 7.0 * game.length
5949 game.intime = game.state.remtime
5950 game.state.remkl = game.inkling = 2.0*game.intime*((game.skill+1 - 2*randreal())*game.skill*0.1+.15)
5951 game.incom = min(MINCMDR, int(game.skill + 0.0625*game.inkling*randreal()))
5952 game.state.remres = (game.inkling+4*game.incom)*game.intime
5953 game.inresor = game.state.remres
5954 if game.inkling > 50:
5958 def dropin(iquad=None):
5959 "Drop a feature on a random dot in the current quadrant."
5961 w = randplace(QUADSIZE)
5962 if game.quad[w.i][w.j] == '.':
5964 if iquad is not None:
5965 game.quad[w.i][w.j] = iquad
5969 "Update our alert status."
5970 game.condition = "green"
5971 if game.energy < 1000.0:
5972 game.condition = "yellow"
5973 if game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons or game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans:
5974 game.condition = "red"
5976 game.condition="dead"
5979 "Drop new Klingon into current quadrant."
5980 return Enemy('K', loc=dropin(), power=randreal(300,450)+25.0*game.skill)
5983 "Sort enemies by distance so 'nearest' is meaningful."
5984 game.enemies.sort(key=lambda x: x.kdist)
5987 "Set up a new state of quadrant, for when we enter or re-enter it."
5990 game.neutz = game.inorbit = game.landed = False
5991 game.ientesc = game.iseenit = game.isviolreported = False
5992 # Create a blank quadrant
5993 game.quad = fill2d(QUADSIZE, lambda i, j: '.')
5995 # Attempt to escape Super-commander, so tbeam back!
5998 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
5999 # cope with supernova
6002 game.klhere = q.klingons
6003 game.irhere = q.romulans
6005 game.quad[game.sector.i][game.sector.j] = game.ship
6008 # Position ordinary Klingons
6009 for _i in range(game.klhere):
6011 # If we need a commander, promote a Klingon
6012 for cmdr in game.state.kcmdr:
6013 if cmdr == game.quadrant:
6014 e = game.enemies[game.klhere-1]
6015 game.quad[e.location.i][e.location.j] = 'C'
6016 e.power = randreal(950,1350) + 50.0*game.skill
6018 # If we need a super-commander, promote a Klingon
6019 if game.quadrant == game.state.kscmdr:
6021 game.quad[e.location.i][e.location.j] = 'S'
6022 e.power = randreal(1175.0, 1575.0) + 125.0*game.skill
6023 game.iscate = (game.state.remkl > 1)
6024 # Put in Romulans if needed
6025 for _i in range(q.romulans):
6026 Enemy('R', loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill)
6027 # If quadrant needs a starbase, put it in
6029 game.base = dropin('B')
6030 # If quadrant needs a planet, put it in
6032 game.iplnet = q.planet
6033 if not q.planet.inhabited:
6034 game.plnet = dropin('P')
6036 game.plnet = dropin('@')
6037 # Check for condition
6040 if game.irhere > 0 and game.klhere == 0:
6042 if not damaged(DRADIO):
6044 prout(_("LT. Uhura- \"Captain, an urgent message."))
6045 prout(_(" I'll put it on audio.\" CLICK"))
6047 prout(_("INTRUDER! YOU HAVE VIOLATED THE ROMULAN NEUTRAL ZONE."))
6048 prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!"))
6049 # Put in THING if needed
6050 if thing == game.quadrant:
6051 Enemy(etype='?', loc=dropin(),
6052 power=randreal(6000,6500.0)+250.0*game.skill)
6053 if not damaged(DSRSENS):
6055 prout(_("Mr. Spock- \"Captain, this is most unusual."))
6056 prout(_(" Please examine your short-range scan.\""))
6057 # Decide if quadrant needs a Tholian; lighten up if skill is low
6058 if game.options & OPTION_THOLIAN:
6059 if (game.skill < SKILL_GOOD and withprob(0.02)) or \
6060 (game.skill == SKILL_GOOD and withprob(0.05)) or \
6061 (game.skill > SKILL_GOOD and withprob(0.08)):
6064 w.i = withprob(0.5) * (QUADSIZE-1)
6065 w.j = withprob(0.5) * (QUADSIZE-1)
6066 if game.quad[w.i][w.j] == '.':
6068 game.tholian = Enemy(etype='T', loc=w,
6069 power=randrange(100, 500) + 25.0*game.skill)
6070 # Reserve unoccupied corners
6071 if game.quad[0][0]=='.':
6072 game.quad[0][0] = 'X'
6073 if game.quad[0][QUADSIZE-1]=='.':
6074 game.quad[0][QUADSIZE-1] = 'X'
6075 if game.quad[QUADSIZE-1][0]=='.':
6076 game.quad[QUADSIZE-1][0] = 'X'
6077 if game.quad[QUADSIZE-1][QUADSIZE-1]=='.':
6078 game.quad[QUADSIZE-1][QUADSIZE-1] = 'X'
6080 # And finally the stars
6081 for _i in range(q.stars):
6083 # Put in a few black holes
6084 for _i in range(1, 3+1):
6087 # Take out X's in corners if Tholian present
6089 if game.quad[0][0]=='X':
6090 game.quad[0][0] = '.'
6091 if game.quad[0][QUADSIZE-1]=='X':
6092 game.quad[0][QUADSIZE-1] = '.'
6093 if game.quad[QUADSIZE-1][0]=='X':
6094 game.quad[QUADSIZE-1][0] = '.'
6095 if game.quad[QUADSIZE-1][QUADSIZE-1]=='X':
6096 game.quad[QUADSIZE-1][QUADSIZE-1] = '.'
6099 "Set the self-destruct password."
6100 if game.options & OPTION_PLAIN:
6103 proutn(_("Please type in a secret password- "))
6105 game.passwd = scanner.token
6106 if game.passwd != None:
6110 game.passwd += chr(ord('a')+randrange(26))
6111 game.passwd += chr(ord('a')+randrange(26))
6112 game.passwd += chr(ord('a')+randrange(26))
6114 # Code from sst.c begins here
6117 ("SRSCAN", OPTION_TTY),
6118 ("STATUS", OPTION_TTY),
6119 ("REQUEST", OPTION_TTY),
6120 ("LRSCAN", OPTION_TTY),
6132 ("SENSORS", OPTION_PLANETS),
6133 ("ORBIT", OPTION_PLANETS),
6134 ("TRANSPORT", OPTION_PLANETS),
6135 ("MINE", OPTION_PLANETS),
6136 ("CRYSTALS", OPTION_PLANETS),
6137 ("SHUTTLE", OPTION_PLANETS),
6138 ("PLANETS", OPTION_PLANETS),
6143 ("PROBE", OPTION_PROBE),
6145 ("FREEZE", 0), # Synonym for SAVE
6149 ("CAPTURE", OPTION_CAPTURE),
6150 ("CLOAK", OPTION_CLOAK),
6153 ("SOS", 0), # Synonym for MAYDAY
6154 ("CALL", 0), # Synonym for MAYDAY
6162 "Generate a list of legal commands."
6163 prout(_("LEGAL COMMANDS ARE:"))
6165 for (key, opt) in commands:
6166 if not opt or (opt & game.options):
6167 proutn("%-12s " % key)
6169 if emitted % 5 == 4:
6174 "Browse on-line help."
6175 key = scanner.nexttok()
6178 setwnd(prompt_window)
6179 proutn(_("Help on what command? "))
6180 key = scanner.nexttok()
6181 setwnd(message_window)
6184 cmds = [x[0] for x in commands]
6185 if scanner.token.upper() in cmds or scanner.token.upper() == "ABBREV":
6192 cmd = scanner.token.upper()
6193 for directory in docpath:
6195 fp = open(os.path.join(directory, "sst.doc"), "r")
6200 prout(_("Spock- \"Captain, that information is missing from the"))
6201 prout(_(" computer. You need to find sst.doc and put it somewhere"))
6202 proutn(_(" in these directories: %s") % ":".join(docpath))
6204 # This used to continue: "You need to find SST.DOC and put
6205 # it in the current directory."
6208 linebuf = fp.readline()
6210 prout(_("Spock- \"Captain, there is no information on that command.\""))
6213 if linebuf[0] == '%' and linebuf[1] == '%' and linebuf[2] == ' ':
6214 linebuf = linebuf[3:].strip()
6215 if cmd.upper() == linebuf:
6218 prout(_("Spock- \"Captain, I've found the following information:\""))
6221 linebuf = fp.readline()
6222 if "******" in linebuf:
6228 "Command-interpretation loop."
6230 if game.irhere and game.state.date >= ALGERON and not game.isviolreported and game.iscloaked:
6231 prout(_("The Romulan ship discovers you are breaking the Treaty of Algeron!"))
6233 game.isviolreported = True
6234 while True: # command loop
6236 while True: # get a command
6238 game.optime = game.justin = False
6240 setwnd(prompt_window)
6243 if scanner.nexttok() == "IHEOL":
6244 if game.options & OPTION_CURSES:
6247 elif scanner.token == "":
6251 setwnd(message_window)
6253 abandon_passed = False
6254 cmd = "" # Force cmd to persist after loop
6255 opt = 0 # Force opt to persist after loop
6256 for (cmd, opt) in commands:
6257 # commands after ABANDON cannot be abbreviated
6258 if cmd == "ABANDON":
6259 abandon_passed = True
6260 if cmd == scanner.token.upper() or (not abandon_passed \
6261 and cmd.startswith(scanner.token.upper())):
6266 elif opt and not (opt & game.options):
6270 if cmd == "SRSCAN": # srscan
6272 elif cmd == "STATUS": # status
6274 elif cmd == "REQUEST": # status request
6276 elif cmd == "LRSCAN": # long range scan
6277 lrscan(silent=False)
6278 elif cmd == "PHASERS": # phasers
6283 elif cmd in ("TORPEDO", "PHOTONS"): # photon torpedos
6288 elif cmd == "MOVE": # move under warp
6289 warp(wcourse=None, involuntary=False)
6290 elif cmd == "SHIELDS": # shields
6291 doshield(shraise=False)
6294 game.shldchg = False
6295 elif cmd == "DOCK": # dock at starbase
6298 attack(torps_ok=False)
6299 elif cmd == "DAMAGES": # damage reports
6301 elif cmd == "CHART": # chart
6303 elif cmd == "IMPULSE": # impulse
6305 elif cmd == "REST": # rest
6309 elif cmd == "WARP": # warp
6311 elif cmd == "SENSORS": # sensors
6313 elif cmd == "ORBIT": # orbit
6317 elif cmd == "TRANSPORT": # transport "beam"
6319 elif cmd == "MINE": # mine
6323 elif cmd == "CRYSTALS": # crystals
6327 elif cmd == "SHUTTLE": # shuttle
6331 elif cmd == "PLANETS": # Planet list
6333 elif cmd == "REPORT": # Game Report
6335 elif cmd == "COMPUTER": # use COMPUTER!
6337 elif cmd == "COMMANDS":
6339 elif cmd == "EMEXIT": # Emergency exit
6340 clrscr() # Hide screen
6341 freeze(True) # forced save
6342 raise SystemExit(1) # And quick exit
6343 elif cmd == "PROBE":
6344 probe() # Launch probe
6347 elif cmd == "ABANDON": # Abandon Ship
6349 elif cmd == "DESTRUCT": # Self Destruct
6351 elif cmd == "SAVE": # Save Game
6354 if game.skill > SKILL_GOOD:
6355 prout(_("WARNING--Saved games produce no plaques!"))
6356 elif cmd == "DEATHRAY": # Try a desparation measure
6360 elif cmd == "CAPTURE":
6362 elif cmd == "DEBUGCMD": # What do we want for debug???
6364 elif cmd == "MAYDAY": # Call for help
6369 game.alldone = True # quit the game
6372 elif cmd == "SCORE":
6373 score() # see current score
6376 break # Game has ended
6377 if game.optime != 0.0:
6380 break # Events did us in
6381 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6384 if hitme and not game.justin:
6385 attack(torps_ok=True)
6388 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6399 "Emit the name of an enemy or feature."
6400 if ch == 'R': s = _("Romulan")
6401 elif ch == 'K': s = _("Klingon")
6402 elif ch == 'C': s = _("Commander")
6403 elif ch == 'S': s = _("Super-commander")
6404 elif ch == '*': s = _("Star")
6405 elif ch == 'P': s = _("Planet")
6406 elif ch == 'B': s = _("Starbase")
6407 elif ch == ' ': s = _("Black hole")
6408 elif ch == 'T': s = _("Tholian")
6409 elif ch == '#': s = _("Tholian web")
6410 elif ch == '?': s = _("Stranger")
6411 elif ch == '@': s = _("Inhabited World")
6412 else: s = "Unknown??"
6415 def crmena(loud, enemy, loctype, w):
6416 "Emit the name of an enemy and his location."
6420 buf += cramen(enemy) + _(" at ")
6421 if loctype == "quadrant":
6422 buf += _("Quadrant ")
6423 elif loctype == "sector":
6425 return buf + repr(w)
6428 "Emit our ship name."
6429 return{'E':_("Enterprise"),'F':_("Faerie Queene")}.get(game.ship,"Ship???")
6432 "Emit a line of stars"
6433 prouts("******************************************************")
6437 return -avrage*math.log(1e-7 + randreal())
6439 def randplace(size):
6440 "Choose a random location."
6442 w.i = randrange(size)
6443 w.j = randrange(size)
6453 # Get a token from the user
6456 # Fill the token quue if nothing here
6457 while not self.inqueue:
6459 if curwnd==prompt_window:
6461 setwnd(message_window)
6468 self.inqueue = sline.lstrip().split() + ["\n"]
6469 # From here on in it's all looking at the queue
6470 self.token = self.inqueue.pop(0)
6471 if self.token == "\n":
6475 self.real = float(self.token)
6476 self.type = "IHREAL"
6481 self.token = self.token.lower()
6482 self.type = "IHALPHA"
6485 def append(self, tok):
6486 self.inqueue.append(tok)
6487 def push(self, tok):
6488 self.inqueue.insert(0, tok)
6492 # Demand input for next scan
6494 self.real = self.token = None
6496 # compares s to item and returns true if it matches to the length of s
6497 return s.startswith(self.token)
6499 # Round token value to nearest integer
6500 return int(round(self.real))
6504 if self.type != "IHREAL":
6509 if self.type != "IHREAL":
6515 return "<sstcanner: token=%s, type=%s, queue=%s>" % (self.token, self.type, self.inqueue)
6518 "Yes-or-no confirmation."
6522 if scanner.token == 'y':
6524 if scanner.token == 'n':
6527 proutn(_("Please answer with \"y\" or \"n\": "))
6530 "Complain about unparseable input."
6533 prout(_("Beg your pardon, Captain?"))
6536 "Access to the internals for debugging."
6537 proutn("Reset levels? ")
6539 if game.energy < game.inenrg:
6540 game.energy = game.inenrg
6541 game.shield = game.inshld
6542 game.torps = game.intorps
6543 game.lsupres = game.inlsr
6544 proutn("Reset damage? ")
6546 for i in range(NDEVICES):
6547 if game.damage[i] > 0.0:
6548 game.damage[i] = 0.0
6549 proutn("Toggle debug flag? ")
6551 game.idebug = not game.idebug
6553 prout("Debug output ON")
6555 prout("Debug output OFF")
6556 proutn("Cause selective damage? ")
6558 for i in range(NDEVICES):
6559 proutn("Kill %s?" % device[i])
6561 key = scanner.nexttok()
6562 if key == "IHALPHA" and scanner.sees("y"):
6563 game.damage[i] = 10.0
6564 proutn("Examine/change events? ")
6569 FSNOVA: "Supernova ",
6572 FBATTAK: "Base Attack ",
6573 FCDBAS: "Base Destroy ",
6574 FSCMOVE: "SC Move ",
6575 FSCDBAS: "SC Base Destroy ",
6576 FDSPROB: "Probe Move ",
6577 FDISTR: "Distress Call ",
6578 FENSLV: "Enslavement ",
6579 FREPRO: "Klingon Build ",
6581 for i in range(1, NEVENTS):
6584 proutn("%.2f" % (scheduled(i)-game.state.date))
6585 if i == FENSLV or i == FREPRO:
6587 proutn(" in %s" % ev.quadrant)
6592 key = scanner.nexttok()
6596 elif key == "IHREAL":
6597 ev = schedule(i, scanner.real)
6598 if i == FENSLV or i == FREPRO:
6600 proutn("In quadrant- ")
6601 key = scanner.nexttok()
6602 # "IHEOL" says to leave coordinates as they are
6605 prout("Event %d canceled, no x coordinate." % (i))
6608 w.i = int(round(scanner.real))
6609 key = scanner.nexttok()
6611 prout("Event %d canceled, no y coordinate." % (i))
6614 w.j = int(round(scanner.real))
6617 proutn("Induce supernova here? ")
6619 game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova = True
6622 if __name__ == '__main__':
6624 #global line, thing, game
6628 game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY)
6629 if os.getenv("TERM"):
6630 game.options |= OPTION_CURSES
6632 game.options |= OPTION_TTY
6633 seed = int(time.time())
6634 (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:txV")
6636 for (switch, val) in options:
6639 replayfp = open(val, "r")
6641 sys.stderr.write("sst: can't open replay file %s\n" % val)
6644 line = replayfp.readline().strip()
6645 (leader, __, seed) = line.split()
6647 sys.stderr.write("sst2k: seed set to %s\n" % seed)
6648 line = replayfp.readline().strip()
6649 arguments += line.split()[2:]
6652 sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
6654 game.options |= OPTION_TTY
6655 game.options &=~ OPTION_CURSES
6656 elif switch == '-s':
6658 elif switch == '-t':
6659 game.options |= OPTION_TTY
6660 game.options &=~ OPTION_CURSES
6661 elif switch == '-x':
6663 elif switch == '-V':
6664 print("SST2K", version)
6667 sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n")
6669 # where to save the input in case of bugs
6670 if "TMPDIR" in os.environ:
6671 tmpdir = os.environ['TMPDIR']
6675 logfp = open(os.path.join(tmpdir, "sst-input.log"), "w")
6677 sys.stderr.write("sst: warning, can't open logfile\n")
6680 logfp.write("# seed %s\n" % seed)
6681 logfp.write("# options %s\n" % " ".join(arguments))
6682 logfp.write("# SST2K version %s\n" % version)
6683 logfp.write("# recorded by %s@%s on %s\n" % \
6684 (getpass.getuser(),socket.gethostname(),time.ctime()))
6686 scanner = sstscanner()
6687 for arg in arguments:
6691 while True: # Play a game
6692 setwnd(fullscreen_window)
6698 game.alldone = False
6706 if game.tourn and game.alldone:
6707 proutn(_("Do you want your score recorded?"))
6713 proutn(_("Do you want to play again? "))
6717 prout(_("May the Great Bird of the Galaxy roost upon your home planet."))
6721 except KeyboardInterrupt: