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.
24 # Prevent lossage under Python 3
32 docpath = (".", "doc/", "/usr/share/doc/sst/")
35 return gettext.gettext(st)
37 GALSIZE = 8 # Galaxy size in quadrants
38 NINHAB = (GALSIZE * GALSIZE // 2) # Number of inhabited worlds
39 MAXUNINHAB = 10 # Maximum uninhabited worlds
40 QUADSIZE = 10 # Quadrant size in sectors
41 BASEMIN = 2 # Minimum starbases
42 BASEMAX = (GALSIZE * GALSIZE // 12) # Maximum starbases
43 MAXKLGAME = 127 # Maximum Klingons per game
44 MAXKLQUAD = 9 # Maximum Klingons per quadrant
45 FULLCREW = 428 # Crew size. BSD Trek was 387, that's wrong
46 FOREVER = 1e30 # Time for the indefinite future
47 MAXBURST = 3 # Max # of torps you can launch in one turn
48 MINCMDR = 10 # Minimum number of Klingon commanders
49 DOCKFAC = 0.25 # Repair faster when docked
50 PHASEFAC = 2.0 # Unclear what this is, it was in the C version
52 ALGERON = 2311 # Date of the Treaty of Algeron
73 class TrekError(Exception):
76 class JumpOut(Exception):
80 def __init__(self, x=None, y=None):
83 def valid_quadrant(self):
84 return self.i >= 0 and self.i < GALSIZE and self.j >= 0 and self.j < GALSIZE
85 def valid_sector(self):
86 return self.i >= 0 and self.i < QUADSIZE and self.j >= 0 and self.j < QUADSIZE
88 self.i = self.j = None
89 def __eq__(self, other):
90 return other != None and self.i == other.i and self.j == other.j
91 def __ne__(self, other):
92 return other is None or self.i != other.i or self.j != other.j
93 def __add__(self, other):
94 return Coord(self.i+other.i, self.j+other.j)
95 def __sub__(self, other):
96 return Coord(self.i-other.i, self.j-other.j)
97 def __mul__(self, other):
98 return Coord(self.i*other, self.j*other)
99 def __rmul__(self, other):
100 return Coord(self.i*other, self.j*other)
101 def __div__(self, other):
102 return Coord(self.i/other, self.j/other)
103 def __mod__(self, other):
104 return Coord(self.i % other, self.j % other)
105 def __rdiv__(self, other):
106 return Coord(self.i/other, self.j/other)
107 def roundtogrid(self):
108 return Coord(int(round(self.i)), int(round(self.j)))
109 def distance(self, other=None):
112 return math.sqrt((self.i - other.i)**2 + (self.j - other.j)**2)
114 return 1.90985*math.atan2(self.j, self.i)
120 s.i = self.i / abs(self.i)
124 s.j = self.j / abs(self.j)
127 #print "Location %s -> %s" % (self, (self / QUADSIZE).roundtogrid())
128 return self.roundtogrid() / QUADSIZE
130 return self.roundtogrid() % QUADSIZE
133 s.i = self.i + randrange(-1, 2)
134 s.j = self.j + randrange(-1, 2)
137 if self.i is None or self.j is None:
139 return "%s - %s" % (self.i+1, self.j+1)
143 "Do not anger the Space Thingy!"
150 return (q.i, q.j) == (self.i, self.j)
154 self.name = None # string-valued if inhabited
155 self.quadrant = Coord() # quadrant located
156 self.pclass = None # could be ""M", "N", "O", or "destroyed"
157 self.crystals = "absent"# could be "mined", "present", "absent"
158 self.known = "unknown" # could be "unknown", "known", "shuttle_down"
159 self.inhabited = False # is it inhabited?
167 self.starbase = False
170 self.supernova = False
172 self.status = "secure" # Could be "secure", "distressed", "enslaved"
174 return "<Quadrant: %(klingons)d>" % self.__dict__
180 self.starbase = False
183 return "<%s,%s,%s>" % (self.klingons, self.starbase, self.stars)
185 def fill2d(size, fillfun):
186 "Fill an empty list in 2D."
188 for i in range(size):
190 for j in range(size):
191 lst[i].append(fillfun(i, j))
196 self.snap = False # snapshot taken
197 self.crew = 0 # crew complement
198 self.nscrem = 0 # remaining super commanders
199 self.starkl = 0 # destroyed stars
200 self.basekl = 0 # destroyed bases
201 self.nromrem = 0 # Romulans remaining
202 self.nplankl = 0 # destroyed uninhabited planets
203 self.nworldkl = 0 # destroyed inhabited planets
204 self.planets = [] # Planet information
205 self.date = 0.0 # stardate
206 self.remres = 0 # remaining resources
207 self.remtime = 0 # remaining time
208 self.baseq = [] # Base quadrant coordinates
209 self.kcmdr = [] # Commander quadrant coordinates
210 self.kscmdr = Coord() # Supercommander quadrant coordinates
212 self.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
214 self.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
216 for i in range(GALSIZE):
217 for j in range(GALSIZE):
218 yield (i, j, self.galaxy[i][j])
222 self.date = None # A real number
223 self.quadrant = None # A coord structure
226 OPTION_ALL = 0xffffffff
227 OPTION_TTY = 0x00000001 # old interface
228 OPTION_CURSES = 0x00000002 # new interface
229 OPTION_IOMODES = 0x00000003 # cover both interfaces
230 OPTION_PLANETS = 0x00000004 # planets and mining
231 OPTION_THOLIAN = 0x00000008 # Tholians and their webs (UT 1979 version)
232 OPTION_THINGY = 0x00000010 # Space Thingy can shoot back (Stas, 2005)
233 OPTION_PROBE = 0x00000020 # deep-space probes (DECUS version, 1980)
234 OPTION_SHOWME = 0x00000040 # bracket Enterprise in chart
235 OPTION_RAMMING = 0x00000080 # enemies may ram Enterprise (Almy)
236 OPTION_MVBADDY = 0x00000100 # more enemies can move (Almy)
237 OPTION_BLKHOLE = 0x00000200 # black hole may timewarp you (Stas, 2005)
238 OPTION_BASE = 0x00000400 # bases have good shields (Stas, 2005)
239 OPTION_WORLDS = 0x00000800 # logic for inhabited worlds (ESR, 2006)
240 OPTION_AUTOSCAN = 0x00001000 # automatic LRSCAN before CHART (ESR, 2006)
241 OPTION_CAPTURE = 0x00002000 # Enable BSD-Trek capture (Almy, 2013).
242 OPTION_CLOAK = 0x80004000 # Enable BSD-Trek capture (Almy, 2013).
243 OPTION_PLAIN = 0x01000000 # user chose plain game
244 OPTION_ALMY = 0x02000000 # user chose Almy variant
245 OPTION_COLOR = 0x04000000 # enable color display (ESR, 2010)
265 NDEVICES = 17 # Number of devices
275 return (game.damage[dev] != 0.0)
277 return not damaged(DRADIO) or game.condition=="docked"
279 # Define future events
280 FSPY = 0 # Spy event happens always (no future[] entry)
281 # can cause SC to tractor beam Enterprise
282 FSNOVA = 1 # Supernova
283 FTBEAM = 2 # Commander tractor beams Enterprise
284 FSNAP = 3 # Snapshot for time warp
285 FBATTAK = 4 # Commander attacks base
286 FCDBAS = 5 # Commander destroys base
287 FSCMOVE = 6 # Supercommander moves (might attack base)
288 FSCDBAS = 7 # Supercommander destroys base
289 FDSPROB = 8 # Move deep space probe
290 FDISTR = 9 # Emit distress call from an inhabited world
291 FENSLV = 10 # Inhabited word is enslaved */
292 FREPRO = 11 # Klingons build a ship in an enslaved system
295 # Abstract out the event handling -- underlying data structures will change
296 # when we implement stateful events
297 def findevent(evtype):
298 return game.future[evtype]
301 def __init__(self, etype=None, loc=None, power=None):
303 self.location = Coord()
308 self.power = power # enemy energy level
309 game.enemies.append(self)
311 motion = (loc != self.location)
312 if self.location.i is not None and self.location.j is not None:
315 game.quad[self.location.i][self.location.j] = '#'
317 game.quad[self.location.i][self.location.j] = '.'
319 self.location = copy.copy(loc)
320 game.quad[self.location.i][self.location.j] = self.type
321 self.kdist = self.kavgd = (game.sector - loc).distance()
323 self.location = Coord()
324 self.kdist = self.kavgd = None
325 # Guard prevents failure on Tholian or thingy
326 if self in game.enemies:
327 game.enemies.remove(self)
330 return "<%s,%s.%f>" % (self.type, self.location, self.power) # For debugging
334 self.options = None # Game options
335 self.state = Snapshot() # A snapshot structure
336 self.snapsht = Snapshot() # Last snapshot taken for time-travel purposes
337 self.quad = None # contents of our quadrant
338 self.damage = [0.0] * NDEVICES # damage encountered
339 self.future = [] # future events
343 self.future.append(Event())
344 self.passwd = None # Self Destruct password
346 self.quadrant = None # where we are in the large
347 self.sector = None # where we are in the small
348 self.tholian = None # Tholian enemy object
349 self.base = None # position of base in current quadrant
350 self.battle = None # base coordinates being attacked
351 self.plnet = None # location of planet in quadrant
352 self.gamewon = False # Finished!
353 self.ididit = False # action taken -- allows enemy to attack
354 self.alive = False # we are alive (not killed)
355 self.justin = False # just entered quadrant
356 self.shldup = False # shields are up
357 self.shldchg = False # shield is changing (affects efficiency)
358 self.iscate = False # super commander is here
359 self.ientesc = False # attempted escape from supercommander
360 self.resting = False # rest time
361 self.icraft = False # Kirk in Galileo
362 self.landed = False # party on planet (true), on ship (false)
363 self.alldone = False # game is now finished
364 self.neutz = False # Romulan Neutral Zone
365 self.isarmed = False # probe is armed
366 self.inorbit = False # orbiting a planet
367 self.imine = False # mining
368 self.icrystl = False # dilithium crystals aboard
369 self.iseenit = False # seen base attack report
370 self.thawed = False # thawed game
371 self.condition = None # "green", "yellow", "red", "docked", "dead"
372 self.iscraft = None # "onship", "offship", "removed"
373 self.skill = None # Player skill level
374 self.inkling = 0 # initial number of klingons
375 self.inbase = 0 # initial number of bases
376 self.incom = 0 # initial number of commanders
377 self.inscom = 0 # initial number of commanders
378 self.inrom = 0 # initial number of commanders
379 self.instar = 0 # initial stars
380 self.intorps = 0 # initial/max torpedoes
381 self.torps = 0 # number of torpedoes
382 self.ship = 0 # ship type -- 'E' is Enterprise
383 self.abandoned = 0 # count of crew abandoned in space
384 self.length = 0 # length of game
385 self.klhere = 0 # klingons here
386 self.casual = 0 # causalties
387 self.nhelp = 0 # calls for help
388 self.nkinks = 0 # count of energy-barrier crossings
389 self.iplnet = None # planet # in quadrant
390 self.inplan = 0 # initial planets
391 self.irhere = 0 # Romulans in quadrant
392 self.isatb = 0 # =2 if super commander is attacking base
393 self.tourn = None # tournament number
394 self.nprobes = 0 # number of probes available
395 self.inresor = 0.0 # initial resources
396 self.intime = 0.0 # initial time
397 self.inenrg = 0.0 # initial/max energy
398 self.inshld = 0.0 # initial/max shield
399 self.inlsr = 0.0 # initial life support resources
400 self.indate = 0.0 # initial date
401 self.energy = 0.0 # energy level
402 self.shield = 0.0 # shield level
403 self.warpfac = 0.0 # warp speed
404 self.lsupres = 0.0 # life support reserves
405 self.optime = 0.0 # time taken by current operation
406 self.damfac = 0.0 # damage factor
407 self.lastchart = 0.0 # time star chart was last updated
408 self.cryprob = 0.0 # probability that crystal will work
409 self.probe = None # object holding probe course info
410 self.height = 0.0 # height of orbit around planet
411 self.score = 0.0 # overall score
412 self.perdate = 0.0 # rate of kills
413 self.idebug = False # Debugging instrumentation enabled?
414 self.statekscmdr = None # No SuperCommander coordinates yet.
415 self.brigcapacity = 400 # Enterprise brig capacity
416 self.brigfree = 400 # How many klingons can we put in the brig?
417 self.kcaptured = 0 # Total Klingons captured, for scoring.
418 self.iscloaked = False # Cloaking device on?
419 self.ncviol = 0 # Algreon treaty violations
420 self.isviolreported = False # We have been warned
422 return sum([q.klingons for (_i, _j, q) in list(self.state.traverse())])
424 # Stas thinks this should be (C expression):
425 # game.remkl() + len(game.state.kcmdr) > 0 ?
426 # game.state.remres/(game.remkl() + 4*len(game.state.kcmdr)) : 99
427 # He says the existing expression is prone to divide-by-zero errors
428 # after killing the last klingon when score is shown -- perhaps also
429 # if the only remaining klingon is SCOM.
430 self.state.remtime = self.state.remres/(self.remkl() + 4*len(self.state.kcmdr))
432 "Are there Klingons remaining?"
433 return self.remkl() + len(self.state.kcmdr) + self.state.nscrem
460 return random.random() < p
462 def randrange(*args):
463 return random.randrange(*args)
468 v *= args[0] # from [0, args[0])
470 v = args[0] + v*(args[1]-args[0]) # from [args[0], args[1])
473 # Code from ai.c begins here
476 "Would this quadrant welcome another Klingon?"
477 return iq.valid_quadrant() and \
478 not game.state.galaxy[iq.i][iq.j].supernova and \
479 game.state.galaxy[iq.i][iq.j].klingons < MAXKLQUAD
481 def tryexit(enemy, look, irun):
482 "A bad guy attempts to bug out."
484 iq.i = game.quadrant.i+(look.i+(QUADSIZE-1))/QUADSIZE - 1
485 iq.j = game.quadrant.j+(look.j+(QUADSIZE-1))/QUADSIZE - 1
486 if not welcoming(iq):
488 if enemy.type == 'R':
489 return False # Romulans cannot escape!
491 # avoid intruding on another commander's territory
492 if enemy.type == 'C':
493 if iq in game.state.kcmdr:
495 # refuse to leave if currently attacking starbase
496 if game.battle == game.quadrant:
498 # don't leave if over 1000 units of energy
499 if enemy.power > 1000.0:
501 oldloc = copy.copy(enemy.location)
502 # handle local matters related to escape
505 if game.condition != "docked":
507 # Handle global matters related to escape
508 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
509 game.state.galaxy[iq.i][iq.j].klingons += 1
510 if enemy.type == 'S':
514 schedule(FSCMOVE, 0.2777)
516 game.state.kscmdr = iq
518 for cmdr in game.state.kcmdr:
519 if cmdr == game.quadrant:
520 game.state.kcmdr.append(iq)
522 # report move out of quadrant.
523 return [(True, enemy, oldloc, iq)]
525 # The bad-guy movement algorithm:
527 # 1. Enterprise has "force" based on condition of phaser and photon torpedoes.
528 # If both are operating full strength, force is 1000. If both are damaged,
529 # force is -1000. Having shields down subtracts an additional 1000.
531 # 2. Enemy has forces equal to the energy of the attacker plus
532 # 100*(K+R) + 500*(C+S) - 400 for novice through good levels OR
533 # 346*K + 400*R + 500*(C+S) - 400 for expert and emeritus.
535 # Attacker Initial energy levels (nominal):
536 # Klingon Romulan Commander Super-Commander
537 # Novice 400 700 1200
539 # Good 450 800 1300 1750
540 # Expert 475 850 1350 1875
541 # Emeritus 500 900 1400 2000
542 # VARIANCE 75 200 200 200
544 # Enemy vessels only move prior to their attack. In Novice - Good games
545 # only commanders move. In Expert games, all enemy vessels move if there
546 # is a commander present. In Emeritus games all enemy vessels move.
548 # 3. If Enterprise is not docked, an aggressive action is taken if enemy
549 # forces are 1000 greater than Enterprise.
551 # Agressive action on average cuts the distance between the ship and
552 # the enemy to 1/4 the original.
554 # 4. At lower energy advantage, movement units are proportional to the
555 # advantage with a 650 advantage being to hold ground, 800 to move forward
556 # 1, 950 for two, 150 for back 4, etc. Variance of 100.
558 # If docked, is reduced by roughly 1.75*game.skill, generally forcing a
559 # retreat, especially at high skill levels.
561 # 5. Motion is limited to skill level, except for SC hi-tailing it out.
563 def movebaddy(enemy):
564 "Tactical movement for the bad guys."
568 # This should probably be just (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
569 if game.skill >= SKILL_EXPERT:
570 nbaddys = (((game.quadrant in game.state.kcmdr)*2 + (game.state.kscmdr==game.quadrant)*2+game.klhere*1.23+game.irhere*1.5)/2.0)
572 nbaddys = (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
573 old_dist = enemy.kdist
574 mdist = int(old_dist + 0.5) # Nearest integer distance
575 # If SC, check with spy to see if should hi-tail it
576 if enemy.type == 'S' and \
577 (enemy.power <= 500.0 or (game.condition=="docked" and not damaged(DPHOTON))):
581 # decide whether to advance, retreat, or hold position
582 forces = enemy.power+100.0*len(game.enemies)+400*(nbaddys-1)
584 forces += 1000 # Good for enemy if shield is down!
585 if not damaged(DPHASER) or not damaged(DPHOTON):
586 if damaged(DPHASER): # phasers damaged
589 forces -= 0.2*(game.energy - 2500.0)
590 if damaged(DPHOTON): # photon torpedoes damaged
593 forces -= 50.0*game.torps
595 # phasers and photon tubes both out!
598 if forces <= 1000.0 and game.condition != "docked": # Typical situation
599 motion = ((forces + randreal(200))/150.0) - 5.0
601 if forces > 1000.0: # Very strong -- move in for kill
602 motion = (1.0 - randreal())**2 * old_dist + 1.0
603 if game.condition == "docked" and (game.options & OPTION_BASE): # protected by base -- back off !
604 motion -= game.skill*(2.0-randreal()**2)
606 proutn("=== MOTION = %d, FORCES = %1.2f, " % (motion, forces))
607 # don't move if no motion
610 # Limit motion according to skill
611 if abs(motion) > game.skill:
616 # calculate preferred number of steps
617 nsteps = abs(int(motion))
618 if motion > 0 and nsteps > mdist:
619 nsteps = mdist # don't overshoot
620 if nsteps > QUADSIZE:
621 nsteps = QUADSIZE # This shouldn't be necessary
623 nsteps = 1 # This shouldn't be necessary
625 proutn("NSTEPS = %d:" % nsteps)
626 # Compute preferred values of delta X and Y
627 m = game.sector - enemy.location
628 if 2.0 * abs(m.i) < abs(m.j):
630 if 2.0 * abs(m.j) < abs(game.sector.i-enemy.location.i):
632 m = (motion * m).sgn()
633 goto = enemy.location
635 for ll in range(nsteps):
637 proutn(" %d" % (ll+1))
638 # Check if preferred position available
649 attempts = 0 # Settle mysterious hang problem
650 while attempts < 20 and not success:
652 if look.i < 0 or look.i >= QUADSIZE:
654 return tryexit(enemy, look, irun)
655 if krawli == m.i or m.j == 0:
657 look.i = goto.i + krawli
659 elif look.j < 0 or look.j >= QUADSIZE:
661 return tryexit(enemy, look, irun)
662 if krawlj == m.j or m.i == 0:
664 look.j = goto.j + krawlj
666 elif (game.options & OPTION_RAMMING) and game.quad[look.i][look.j] != '.':
667 # See if enemy should ram ship
668 if game.quad[look.i][look.j] == game.ship and \
669 (enemy.type == 'C' or enemy.type == 'S'):
670 collision(rammed=True, enemy=enemy)
672 if krawli != m.i and m.j != 0:
673 look.i = goto.i + krawli
675 elif krawlj != m.j and m.i != 0:
676 look.j = goto.j + krawlj
679 break # we have failed
690 # Enemy moved, but is still in sector
691 return [(False, enemy, old_dist, goto)]
694 "Sequence Klingon tactical movement."
697 # Figure out which Klingon is the commander (or Supercommander)
700 if game.quadrant in game.state.kcmdr:
701 for enemy in game.enemies:
702 if enemy.type == 'C':
703 tacmoves += movebaddy(enemy)
704 if game.state.kscmdr == game.quadrant:
705 for enemy in game.enemies:
706 if enemy.type == 'S':
707 tacmoves += movebaddy(enemy)
709 # If skill level is high, move other Klingons and Romulans too!
710 # Move these last so they can base their actions on what the
712 if game.skill >= SKILL_EXPERT and (game.options & OPTION_MVBADDY):
713 for enemy in game.enemies:
714 if enemy.type in ('K', 'R'):
715 tacmoves += movebaddy(enemy)
718 def movescom(iq, avoid):
719 "Supercommander movement helper."
720 # Avoid quadrants with bases if we want to avoid Enterprise
721 if not welcoming(iq) or (avoid and iq in game.state.baseq):
723 if game.justin and not game.iscate:
726 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons -= 1
727 game.state.kscmdr = iq
728 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons += 1
729 if game.state.kscmdr == game.quadrant:
730 # SC has scooted, remove him from current quadrant
735 for enemy in game.enemies:
736 if enemy.type == 'S':
739 if game.condition != "docked":
742 # check for a helpful planet
743 for i in range(game.inplan):
744 if game.state.planets[i].quadrant == game.state.kscmdr and \
745 game.state.planets[i].crystals == "present":
747 game.state.planets[i].pclass = "destroyed"
748 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].planet = None
751 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
752 proutn(_(" a planet in Quadrant %s has been destroyed") % game.state.kscmdr)
753 prout(_(" by the Super-commander.\""))
755 return True # looks good!
757 def supercommander():
758 "Move the Super Commander."
765 prout("== SUPERCOMMANDER")
766 # Decide on being active or passive
767 avoid = ((game.incom - len(game.state.kcmdr) + game.inkling - game.remkl())/(game.state.date+0.01-game.indate) < 0.1*game.skill*(game.skill+1.0) or \
768 (game.state.date-game.indate) < 3.0)
769 if not game.iscate and avoid:
770 # compute move away from Enterprise
771 idelta = game.state.kscmdr-game.quadrant
772 if idelta.distance() > 2.0:
774 idelta.i = game.state.kscmdr.j-game.quadrant.j
775 idelta.j = game.quadrant.i-game.state.kscmdr.i
777 # compute distances to starbases
778 if not game.state.baseq:
782 sc = game.state.kscmdr
783 for (i, base) in enumerate(game.state.baseq):
784 basetbl.append((i, (base - sc).distance()))
785 if game.state.baseq > 1:
786 basetbl.sort(key=lambda x: x[1])
787 # look for nearest base without a commander, no Enterprise, and
788 # without too many Klingons, and not already under attack.
789 ifindit = iwhichb = 0
790 for (i2, base) in enumerate(game.state.baseq):
791 i = basetbl[i2][0] # bug in original had it not finding nearest
792 if base == game.quadrant or base == game.battle or not welcoming(base):
794 # if there is a commander, and no other base is appropriate,
795 # we will take the one with the commander
796 for cmdr in game.state.kcmdr:
797 if base == cmdr and ifindit != 2:
801 else: # no commander -- use this one
806 return # Nothing suitable -- wait until next time
807 ibq = game.state.baseq[iwhichb]
808 # decide how to move toward base
809 idelta = ibq - game.state.kscmdr
810 # Maximum movement is 1 quadrant in either or both axes
811 idelta = idelta.sgn()
812 # try moving in both x and y directions
813 # there was what looked like a bug in the Almy C code here,
814 # but it might be this translation is just wrong.
815 iq = game.state.kscmdr + idelta
816 if not movescom(iq, avoid):
817 # failed -- try some other maneuvers
818 if idelta.i == 0 or idelta.j == 0:
821 iq.j = game.state.kscmdr.j + 1
822 if not movescom(iq, avoid):
823 iq.j = game.state.kscmdr.j - 1
826 iq.i = game.state.kscmdr.i + 1
827 if not movescom(iq, avoid):
828 iq.i = game.state.kscmdr.i - 1
831 # try moving just in x or y
832 iq.j = game.state.kscmdr.j
833 if not movescom(iq, avoid):
834 iq.j = game.state.kscmdr.j + idelta.j
835 iq.i = game.state.kscmdr.i
838 if len(game.state.baseq) == 0:
841 for ibq in game.state.baseq:
842 if ibq == game.state.kscmdr and game.state.kscmdr == game.battle:
845 return # no, don't attack base!
848 schedule(FSCDBAS, randreal(1.0, 3.0))
849 if is_scheduled(FCDBAS):
850 postpone(FSCDBAS, scheduled(FCDBAS)-game.state.date)
851 if not communicating():
855 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") \
857 prout(_(" reports that it is under attack from the Klingon Super-commander."))
858 proutn(_(" It can survive until stardate %d.\"") \
859 % int(scheduled(FSCDBAS)))
862 prout(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
866 game.optime = 0.0 # actually finished
868 # Check for intelligence report
869 if not game.idebug and \
871 (not communicating()) or \
872 not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].charted):
875 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
876 proutn(_(" the Super-commander is in Quadrant %s,") % game.state.kscmdr)
881 if not game.tholian or game.justin:
884 if game.tholian.location.i == 0 and game.tholian.location.j == 0:
887 elif game.tholian.location.i == 0 and game.tholian.location.j == QUADSIZE-1:
890 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == QUADSIZE-1:
893 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == 0:
897 # something is wrong!
898 game.tholian.move(None)
899 prout("***Internal error: Tholian in a bad spot.")
901 # do nothing if we are blocked
902 if game.quad[tid.i][tid.j] not in ('.', '#'):
904 here = copy.copy(game.tholian.location)
905 delta = (tid - game.tholian.location).sgn()
907 while here.i != tid.i:
909 if game.quad[here.i][here.j] == '.':
910 game.tholian.move(here)
912 while here.j != tid.j:
914 if game.quad[here.i][here.j] == '.':
915 game.tholian.move(here)
916 # check to see if all holes plugged
917 for i in range(QUADSIZE):
918 if game.quad[0][i] != '#' and game.quad[0][i] != 'T':
920 if game.quad[QUADSIZE-1][i] != '#' and game.quad[QUADSIZE-1][i] != 'T':
922 if game.quad[i][0] != '#' and game.quad[i][0] != 'T':
924 if game.quad[i][QUADSIZE-1] != '#' and game.quad[i][QUADSIZE-1] != 'T':
926 # All plugged up -- Tholian splits
927 game.quad[game.tholian.location.i][game.tholian.location.j] = '#'
929 prout(crmena(True, 'T', "sector", game.tholian) + _(" completes web."))
930 game.tholian.move(None)
933 # Code from battle.c begins here
936 "Change cloaking-device status."
938 prout(_("Ye Faerie Queene hath no cloaking device."));
941 key = scanner.nexttok()
949 if scanner.sees("on"):
951 prout(_("The cloaking device has already been switched on."))
954 elif scanner.sees("off"):
955 if not game.iscloaked:
956 prout(_("The cloaking device has already been switched off."))
963 if not game.iscloaked:
964 proutn(_("Switch cloaking device on? "))
969 proutn(_("Switch cloaking device off? "))
976 if action == "CLOFF":
977 if game.irhere and game.state.date >= ALGERON and not game.isviolreported:
978 prout(_("Spock- \"Captain, the Treaty of Algeron is in effect.\n Are you sure this is wise?\""))
981 prout("Engineer Scott- \"Aye, Sir.\"");
982 game.iscloaked = False;
983 if game.irhere and game.state.date >= ALGERON and not game.isviolreported:
984 prout(_("The Romulan ship discovers you are breaking the Treaty of Algeron!"))
986 game.isviolreported = True
988 #if (neutz and game.state.date >= ALGERON) finish(FCLOAK);
993 prout(_("Engineer Scott- \"The cloaking device is damaged, Sir.\""))
996 if game.condition == "docked":
997 prout(_("You cannot cloak while docked."))
999 if game.state.date >= ALGERON and not game.isviolreported:
1000 prout(_("Spock- \"Captain, using the cloaking device is a violation"))
1001 prout(_(" of the Treaty of Algeron. Considering the alternatives,"))
1002 proutn(_(" are you sure this is wise? "))
1005 prout(_("Engineer Scott- \"Cloaking device has engaging, Sir...\""))
1007 prout(_("Engineer Scott- \"Cloaking device has engaged, Sir.\""))
1008 game.iscloaked = True
1010 if game.irhere and game.state.date >= ALGERON and not game.isviolreported:
1011 prout(_("The Romulan ship discovers you are breaking the Treaty of Algeron!"))
1013 game.isviolreported = True
1015 def doshield(shraise):
1016 "Change shield status."
1022 key = scanner.nexttok()
1023 if key == "IHALPHA":
1024 if scanner.sees("transfer"):
1027 if damaged(DSHIELD):
1028 prout(_("Shields damaged and down."))
1030 if scanner.sees("up"):
1032 elif scanner.sees("down"):
1034 if action == "NONE":
1035 proutn(_("Do you wish to change shield energy? "))
1038 elif damaged(DSHIELD):
1039 prout(_("Shields damaged and down."))
1042 proutn(_("Shields are up. Do you want them down? "))
1049 proutn(_("Shields are down. Do you want them up? "))
1055 if action == "SHUP": # raise shields
1057 prout(_("Shields already up."))
1061 if game.condition != "docked":
1063 prout(_("Shields raised."))
1064 if game.energy <= 0:
1066 prout(_("Shields raising uses up last of energy."))
1071 elif action == "SHDN":
1073 prout(_("Shields already down."))
1077 prout(_("Shields lowered."))
1080 elif action == "NRG":
1081 while scanner.nexttok() != "IHREAL":
1083 proutn(_("Energy to transfer to shields- "))
1088 if nrg > game.energy:
1089 prout(_("Insufficient ship energy."))
1092 if game.shield+nrg >= game.inshld:
1093 prout(_("Shield energy maximized."))
1094 if game.shield+nrg > game.inshld:
1095 prout(_("Excess energy requested returned to ship energy"))
1096 game.energy -= game.inshld-game.shield
1097 game.shield = game.inshld
1099 if nrg < 0.0 and game.energy-nrg > game.inenrg:
1100 # Prevent shield drain loophole
1102 prout(_("Engineering to bridge--"))
1103 prout(_(" Scott here. Power circuit problem, Captain."))
1104 prout(_(" I can't drain the shields."))
1107 if game.shield+nrg < 0:
1108 prout(_("All shield energy transferred to ship."))
1109 game.energy += game.shield
1112 proutn(_("Scotty- \""))
1114 prout(_("Transferring energy to shields.\""))
1116 prout(_("Draining energy from shields.\""))
1122 "Choose a device to damage, at random."
1124 105, # DSRSENS: short range scanners 10.5%
1125 105, # DLRSENS: long range scanners 10.5%
1126 120, # DPHASER: phasers 12.0%
1127 120, # DPHOTON: photon torpedoes 12.0%
1128 25, # DLIFSUP: life support 2.5%
1129 65, # DWARPEN: warp drive 6.5%
1130 70, # DIMPULS: impulse engines 6.5%
1131 135, # DSHIELD: deflector shields 13.5%
1132 30, # DRADIO: subspace radio 3.0%
1133 45, # DSHUTTL: shuttle 4.5%
1134 15, # DCOMPTR: computer 1.5%
1135 20, # NAVCOMP: navigation system 2.0%
1136 75, # DTRANSP: transporter 7.5%
1137 20, # DSHCTRL: high-speed shield controller 2.0%
1138 10, # DDRAY: death ray 1.0%
1139 30, # DDSP: deep-space probes 3.0%
1140 10, # DCLOAK: the cloaking device 1.0
1142 assert(sum(weights) == 1000)
1143 idx = randrange(1000)
1145 for (i, w) in enumerate(weights):
1149 return None # we should never get here
1151 def collision(rammed, enemy):
1152 "Collision handling for rammong events."
1153 prouts(_("***RED ALERT! RED ALERT!"))
1155 prout(_("***COLLISION IMMINENT."))
1159 hardness = {'R':1.5, 'C':2.0, 'S':2.5, 'T':0.5, '?':4.0}.get(enemy.type, 1.0)
1161 proutn(_(" rammed by "))
1164 proutn(crmena(False, enemy.type, "sector", enemy.location))
1166 proutn(_(" (original position)"))
1168 deadkl(enemy.location, enemy.type, game.sector)
1169 proutn("***" + crmshp() + " heavily damaged.")
1170 icas = randrange(10, 30)
1171 prout(_("***Sickbay reports %d casualties") % icas)
1173 game.state.crew -= icas
1174 # In the pre-SST2K version, all devices got equiprobably damaged,
1175 # which was silly. Instead, pick up to half the devices at
1176 # random according to our weighting table,
1177 ncrits = randrange(NDEVICES/2)
1181 if game.damage[dev] < 0:
1183 extradm = (10.0*hardness*randreal()+1.0)*game.damfac
1184 # Damage for at least time of travel!
1185 game.damage[dev] += game.optime + extradm
1187 prout(_("***Shields are down."))
1195 def torpedo(origin, bearing, dispersion, number, nburst):
1196 "Let a photon torpedo fly"
1197 if not damaged(DSRSENS) or game.condition == "docked":
1198 setwnd(srscan_window)
1200 setwnd(message_window)
1201 ac = bearing + 0.25*dispersion # dispersion is a random variable
1202 bullseye = (15.0 - bearing)*0.5235988
1203 track = course(bearing=ac, distance=QUADSIZE, origin=cartesian(origin))
1204 bumpto = Coord(0, 0)
1205 # Loop to move a single torpedo
1206 setwnd(message_window)
1207 for step in range(1, QUADSIZE*2):
1208 if not track.nexttok():
1211 if not w.valid_sector():
1213 iquad = game.quad[w.i][w.j]
1214 tracktorpedo(w, step, number, nburst, iquad)
1218 setwnd(message_window)
1219 if not damaged(DSRSENS) or game.condition == "docked":
1220 skip(1) # start new line after text track
1221 if iquad in ('E', 'F'): # Hit our ship
1223 prout(_("Torpedo hits %s.") % crmshp())
1224 hit = 700.0 + randreal(100) - \
1225 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1226 newcnd() # we're blown out of dock
1227 if game.landed or game.condition == "docked":
1228 return hit # Cheat if on a planet
1229 # In the C/FORTRAN version, dispersion was 2.5 radians, which
1230 # is 143 degrees, which is almost exactly 4.8 clockface units
1231 displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
1232 displacement.nexttok()
1233 bumpto = displacement.sector()
1234 if not bumpto.valid_sector():
1236 if game.quad[bumpto.i][bumpto.j] == ' ':
1239 if game.quad[bumpto.i][bumpto.j] != '.':
1240 # can't move into object
1242 game.sector = bumpto
1244 game.quad[w.i][w.j] = '.'
1245 game.quad[bumpto.i][bumpto.j] = iquad
1246 prout(_(" displaced by blast to Sector %s ") % bumpto)
1247 for enemy in game.enemies:
1248 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1251 elif iquad in ('C', 'S', 'R', 'K'): # Hit a regular enemy
1253 if iquad in ('C', 'S') and withprob(0.05):
1254 prout(crmena(True, iquad, "sector", w) + _(" uses anti-photon device;"))
1255 prout(_(" torpedo neutralized."))
1257 for enemy in game.enemies:
1258 if w == enemy.location:
1259 kp = math.fabs(enemy.power)
1260 h1 = 700.0 + randrange(100) - \
1261 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1269 if enemy.power == 0:
1272 proutn(crmena(True, iquad, "sector", w))
1273 displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
1274 displacement.nexttok()
1275 bumpto = displacement.sector()
1276 if not bumpto.valid_sector():
1277 prout(_(" damaged but not destroyed."))
1279 if game.quad[bumpto.i][bumpto.j] == ' ':
1280 prout(_(" buffeted into black hole."))
1281 deadkl(w, iquad, bumpto)
1282 if game.quad[bumpto.i][bumpto.j] != '.':
1283 prout(_(" damaged but not destroyed."))
1285 prout(_(" damaged-- displaced by blast to Sector %s ")%bumpto)
1286 enemy.location = bumpto
1287 game.quad[w.i][w.j] = '.'
1288 game.quad[bumpto.i][bumpto.j] = iquad
1289 for enemy in game.enemies:
1290 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1294 prout("Internal error, no enemy where expected!")
1297 elif iquad == 'B': # Hit a base
1299 prout(_("***STARBASE DESTROYED.."))
1300 game.state.baseq = [x for x in game.state.baseq if x != game.quadrant]
1301 game.quad[w.i][w.j] = '.'
1302 game.base.invalidate()
1303 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
1304 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = False
1305 game.state.basekl += 1
1308 elif iquad == 'P': # Hit a planet
1309 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1310 game.state.nplankl += 1
1311 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1312 game.iplnet.pclass = "destroyed"
1314 game.plnet.invalidate()
1315 game.quad[w.i][w.j] = '.'
1317 # captain perishes on planet
1320 elif iquad == '@': # Hit an inhabited world -- very bad!
1321 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1322 game.state.nworldkl += 1
1323 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1324 game.iplnet.pclass = "destroyed"
1326 game.plnet.invalidate()
1327 game.quad[w.i][w.j] = '.'
1329 # captain perishes on planet
1331 prout(_("The torpedo destroyed an inhabited planet."))
1333 elif iquad == '*': # Hit a star
1337 prout(crmena(True, '*', "sector", w) + _(" unaffected by photon blast."))
1339 elif iquad == '?': # Hit a thingy
1340 if not (game.options & OPTION_THINGY) or withprob(0.3):
1342 prouts(_("AAAAIIIIEEEEEEEEAAAAAAAAUUUUUGGGGGHHHHHHHHHHHH!!!"))
1344 prouts(_(" HACK! HACK! HACK! *CHOKE!* "))
1346 proutn(_("Mr. Spock-"))
1347 prouts(_(" \"Fascinating!\""))
1351 # Stas Sergeev added the possibility that
1352 # you can shove the Thingy and piss it off.
1353 # It then becomes an enemy and may fire at you.
1356 elif iquad == ' ': # Black hole
1358 prout(crmena(True, ' ', "sector", w) + _(" swallows torpedo."))
1360 elif iquad == '#': # hit the web
1362 prout(_("***Torpedo absorbed by Tholian web."))
1364 elif iquad == 'T': # Hit a Tholian
1365 h1 = 700.0 + randrange(100) - \
1366 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1369 game.quad[w.i][w.j] = '.'
1374 proutn(crmena(True, 'T', "sector", w))
1376 prout(_(" survives photon blast."))
1378 prout(_(" disappears."))
1379 game.tholian.move(None)
1380 game.quad[w.i][w.j] = '#'
1385 proutn("Don't know how to handle torpedo collision with ")
1386 proutn(crmena(True, iquad, "sector", w))
1391 setwnd(message_window)
1392 prout(_("Torpedo missed."))
1396 "Critical-hit resolution."
1397 if hit < (275.0-25.0*game.skill)*randreal(1.0, 1.5):
1399 ncrit = int(1.0 + hit/(500.0+randreal(100)))
1400 proutn(_("***CRITICAL HIT--"))
1401 # Select devices and cause damage
1406 # Cheat to prevent shuttle damage unless on ship
1407 if not (game.damage[j]<0.0 or (j == DSHUTTL and game.iscraft != "onship") or (j == DCLOAK and game.ship != 'E' or j == DDRAY)):
1410 extradm = (hit*game.damfac)/(ncrit*randreal(75, 100))
1411 game.damage[j] += extradm
1414 for (i, j) in enumerate(cdam):
1416 if skipcount % 3 == 2 and i < len(cdam)-1:
1421 prout(_(" damaged."))
1422 if damaged(DSHIELD) and game.shldup:
1423 prout(_("***Shields knocked down."))
1425 if damaged(DCLOAK) and game.iscloaked:
1426 prout(_("***Cloaking device rendered inoperative."))
1427 game.iscloaked = False
1429 def attack(torps_ok):
1430 # bad guy attacks us
1431 # torps_ok == False forces use of phasers in an attack
1434 # game could be over at this point, check
1444 prout("=== ATTACK!")
1445 # Tholian gets to move before attacking
1448 # if you have just entered the RNZ, you'll get a warning
1449 if game.neutz: # The one chance not to be attacked
1452 # commanders get a chance to tac-move towards you
1453 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:
1454 for (bugout, enemy, old, goto) in moveklings():
1456 # we know about this if either short or long range
1457 # sensors are working
1458 if damaged(DSRSENS) and damaged(DLRSENS) \
1459 and game.condition != "docked":
1460 prout(crmena(True, enemy.type, "sector", old) + \
1461 (_(" escapes to Quadrant %s (and regains strength).") % goto))
1462 else: # Enemy still in-sector
1463 if enemy.move(goto):
1464 if not damaged(DSRSENS) or game.condition == "docked":
1465 proutn(_("*** %s from Sector %s") % (cramen(enemy.type), enemy.location))
1466 if enemy.kdist < old:
1467 proutn(_(" advances to "))
1469 proutn(_(" retreats to "))
1470 prout("Sector %s." % goto)
1472 # if no enemies remain after movement, we're done
1473 if len(game.enemies) == 0 or (len(game.enemies) == 1 and thing.at(game.quadrant) and not thing.angered):
1475 # set up partial hits if attack happens during shield status change
1476 pfac = 1.0/game.inshld
1478 chgfac = 0.25 + randreal(0.5)
1480 # message verbosity control
1481 if game.skill <= SKILL_FAIR:
1483 for enemy in game.enemies:
1485 continue # too weak to attack
1486 # compute hit strength and diminish shield power
1488 # Increase chance of photon torpedos if docked or enemy energy is low
1489 if game.condition == "docked":
1491 if enemy.power < 500:
1493 if enemy.type == 'T' or (enemy.type == '?' and not thing.angered):
1495 # different enemies have different probabilities of throwing a torp
1496 usephasers = not torps_ok or \
1497 (enemy.type == 'K' and r > 0.0005) or \
1498 (enemy.type == 'C' and r > 0.015) or \
1499 (enemy.type == 'R' and r > 0.3) or \
1500 (enemy.type == 'S' and r > 0.07) or \
1501 (enemy.type == '?' and r > 0.05)
1502 if usephasers: # Enemy uses phasers
1503 if game.condition == "docked":
1504 continue # Don't waste the effort!
1505 attempt = True # Attempt to attack
1506 dustfac = randreal(0.8, 0.85)
1507 hit = enemy.power*math.pow(dustfac, enemy.kavgd)
1509 else: # Enemy uses photon torpedo
1510 # We should be able to make the bearing() method work here
1511 pcourse = 1.90985*math.atan2(game.sector.j-enemy.location.j, enemy.location.i-game.sector.i)
1513 proutn(_("***TORPEDO INCOMING"))
1514 if not damaged(DSRSENS):
1515 proutn(_(" From ") + crmena(False, enemy.type, where, enemy.location))
1518 dispersion = (randreal()+randreal())*0.5 - 0.5
1519 dispersion += 0.002*enemy.power*dispersion
1520 hit = torpedo(enemy.location, pcourse, dispersion, number=1, nburst=1)
1521 if game.unwon() == 0:
1522 finish(FWON) # Klingons did themselves in!
1523 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.alldone:
1524 return # Supernova or finished
1527 # incoming phaser or torpedo, shields may dissipate it
1528 if game.shldup or game.shldchg or game.condition == "docked":
1529 # shields will take hits
1530 propor = pfac * game.shield
1531 if game.condition == "docked":
1535 hitsh = propor*chgfac*hit+1.0
1537 if absorb > game.shield:
1538 absorb = game.shield
1539 game.shield -= absorb
1541 # taking a hit blasts us out of a starbase dock
1542 if game.condition == "docked":
1544 # but the shields may take care of it
1545 if propor > 0.1 and hit < 0.005*game.energy:
1547 # hit from this opponent got through shields, so take damage
1549 proutn(_("%d unit hit") % int(hit))
1550 if (damaged(DSRSENS) and usephasers) or game.skill<=SKILL_FAIR:
1551 proutn(_(" on the ") + crmshp())
1552 if not damaged(DSRSENS) and usephasers:
1553 prout(_(" from ") + crmena(False, enemy.type, where, enemy.location))
1555 # Decide if hit is critical
1561 if game.energy <= 0:
1562 # Returning home upon your shield, not with it...
1565 if not attempt and game.condition == "docked":
1566 prout(_("***Enemies decide against attacking your ship."))
1567 percent = 100.0*pfac*game.shield+0.5
1569 # Shields fully protect ship
1570 proutn(_("Enemy attack reduces shield strength to "))
1572 # Emit message if starship suffered hit(s)
1574 proutn(_("Energy left %2d shields ") % int(game.energy))
1577 elif not damaged(DSHIELD):
1580 proutn(_("damaged, "))
1581 prout(_("%d%%, torpedoes left %d") % (percent, game.torps))
1582 # Check if anyone was hurt
1583 if hitmax >= 200 or hittot >= 500:
1584 icas = randrange(int(hittot * 0.015))
1587 prout(_("Mc Coy- \"Sickbay to bridge. We suffered %d casualties") % icas)
1588 prout(_(" in that last attack.\""))
1590 game.state.crew -= icas
1591 # After attack, reset average distance to enemies
1592 for enemy in game.enemies:
1593 enemy.kavgd = enemy.kdist
1597 def deadkl(w, etype, mv):
1598 "Kill a Klingon, Tholian, Romulan, or Thingy."
1599 # Added mv to allow enemy to "move" before dying
1600 proutn(crmena(True, etype, "sector", mv))
1601 # Decide what kind of enemy it is and update appropriately
1603 # Chalk up a Romulan
1604 game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans -= 1
1606 game.state.nromrem -= 1
1615 # Killed some type of Klingon
1616 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
1619 game.state.kcmdr.remove(game.quadrant)
1621 if game.state.kcmdr:
1622 schedule(FTBEAM, expran(1.0*game.incom/len(game.state.kcmdr)))
1623 if is_scheduled(FCDBAS) and game.battle == game.quadrant:
1628 game.state.nscrem -= 1
1629 game.state.kscmdr.invalidate()
1634 # For each kind of enemy, finish message to player
1635 prout(_(" destroyed."))
1636 if game.unwon() == 0:
1639 # Remove enemy ship from arrays describing local conditions
1640 for e in game.enemies:
1647 "Return None if target is invalid, otherwise return a course angle."
1648 if not w.valid_sector():
1652 # C code this was translated from is wacky -- why the sign reversal?
1653 delta.j = (w.j - game.sector.j)
1654 delta.i = (game.sector.i - w.i)
1655 if delta == Coord(0, 0):
1657 prout(_("Spock- \"Bridge to sickbay. Dr. McCoy,"))
1658 prout(_(" I recommend an immediate review of"))
1659 prout(_(" the Captain's psychological profile.\""))
1662 return delta.bearing()
1665 "Launch photon torpedo salvo."
1668 if damaged(DPHOTON):
1669 prout(_("Photon tubes damaged."))
1673 prout(_("No torpedoes left."))
1676 # First, get torpedo count
1679 if scanner.token == "IHALPHA":
1682 elif scanner.token == "IHEOL" or not scanner.waiting():
1683 prout(_("%d torpedoes left.") % game.torps)
1685 proutn(_("Number of torpedoes to fire- "))
1686 continue # Go back around to get a number
1687 else: # key == "IHREAL"
1689 if n <= 0: # abort command
1694 prout(_("Maximum of %d torpedoes per burst.") % MAXBURST)
1697 scanner.chew() # User requested more torps than available
1698 continue # Go back around
1699 break # All is good, go to next stage
1703 key = scanner.nexttok()
1704 if i == 0 and key == "IHEOL":
1705 break # no coordinate waiting, we will try prompting
1706 if i == 1 and key == "IHEOL":
1707 # direct all torpedoes at one target
1709 target.append(target[0])
1710 tcourse.append(tcourse[0])
1713 scanner.push(scanner.token)
1714 target.append(scanner.getcoord())
1715 if target[-1] is None:
1717 tcourse.append(targetcheck(target[-1]))
1718 if tcourse[-1] is None:
1721 if len(target) == 0:
1722 # prompt for each one
1724 proutn(_("Target sector for torpedo number %d- ") % (i+1))
1726 target.append(scanner.getcoord())
1727 if target[-1] is None:
1729 tcourse.append(targetcheck(target[-1]))
1730 if tcourse[-1] is None:
1733 # Loop for moving <n> torpedoes
1735 if game.condition != "docked":
1737 dispersion = (randreal()+randreal())*0.5 -0.5
1738 if math.fabs(dispersion) >= 0.47:
1740 dispersion *= randreal(1.2, 2.2)
1742 prouts(_("***TORPEDO NUMBER %d MISFIRES") % (i+1))
1744 prouts(_("***TORPEDO MISFIRES."))
1747 prout(_(" Remainder of burst aborted."))
1749 prout(_("***Photon tubes damaged by misfire."))
1750 game.damage[DPHOTON] = game.damfac * randreal(1.0, 3.0)
1754 elif game.shldup or game.condition == "docked":
1755 dispersion *= 1.0 + 0.0001*game.shield
1756 torpedo(game.sector, tcourse[i], dispersion, number=i, nburst=n)
1757 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
1763 "Check for phasers overheating."
1765 checkburn = (rpow-1500.0)*0.00038
1766 if withprob(checkburn):
1767 prout(_("Weapons officer Sulu- \"Phasers overheated, sir.\""))
1768 game.damage[DPHASER] = game.damfac* randreal(1.0, 2.0) * (1.0+checkburn)
1770 def checkshctrl(rpow):
1771 "Check shield control."
1774 prout(_("Shields lowered."))
1776 # Something bad has happened
1777 prouts(_("***RED ALERT! RED ALERT!"))
1779 hit = rpow*game.shield/game.inshld
1780 game.energy -= rpow+hit*0.8
1781 game.shield -= hit*0.2
1782 if game.energy <= 0.0:
1783 prouts(_("Sulu- \"Captain! Shield malf***********************\""))
1788 prouts(_("Sulu- \"Captain! Shield malfunction! Phaser fire contained!\""))
1790 prout(_("Lt. Uhura- \"Sir, all decks reporting damage.\""))
1791 icas = randrange(int(hit*0.012))
1796 prout(_("McCoy to bridge- \"Severe radiation burns, Jim."))
1797 prout(_(" %d casualties so far.\"") % icas)
1799 game.state.crew -= icas
1801 prout(_("Phaser energy dispersed by shields."))
1802 prout(_("Enemy unaffected."))
1807 "Register a phaser hit on Klingons and Romulans."
1814 dustfac = randreal(0.9, 1.0)
1815 hit = wham*math.pow(dustfac, game.enemies[kk].kdist)
1816 kpini = game.enemies[kk].power
1817 kp = math.fabs(kpini)
1818 if PHASEFAC*hit < kp:
1820 if game.enemies[kk].power < 0:
1821 game.enemies[kk].power -= -kp
1823 game.enemies[kk].power -= kp
1824 kpow = game.enemies[kk].power
1825 w = game.enemies[kk].location
1827 if not damaged(DSRSENS):
1829 proutn(_("%d unit hit on ") % int(hit))
1831 proutn(_("Very small hit on "))
1832 ienm = game.quad[w.i][w.j]
1835 proutn(crmena(False, ienm, "sector", w))
1844 else: # decide whether or not to emasculate klingon
1845 if kpow > 0 and withprob(0.9) and kpow <= randreal(0.4, 0.8)*kpini:
1846 prout(_("***Mr. Spock- \"Captain, the vessel at Sector %s")%w)
1847 prout(_(" has just lost its firepower.\""))
1848 game.enemies[kk].power = -kpow
1853 "Fire phasers at bad guys."
1857 irec = 0 # Cheating inhibitor
1866 # SR sensors and Computer are needed for automode
1867 if damaged(DSRSENS) or damaged(DCOMPTR):
1869 if game.condition == "docked":
1870 prout(_("Phasers can't be fired through base shields."))
1873 if damaged(DPHASER):
1874 prout(_("Phaser control damaged."))
1878 if damaged(DSHCTRL):
1879 prout(_("High speed shield control damaged."))
1882 if game.energy <= 200.0:
1883 prout(_("Insufficient energy to activate high-speed shield control."))
1886 prout(_("Weapons Officer Sulu- \"High-speed shield control enabled, sir.\""))
1888 # Original code so convoluted, I re-did it all
1889 # (That was Tom Almy talking about the C code, I think -- ESR)
1890 while automode == "NOTSET":
1891 key = scanner.nexttok()
1892 if key == "IHALPHA":
1893 if scanner.sees("manual"):
1894 if len(game.enemies)==0:
1895 prout(_("There is no enemy present to select."))
1898 automode = "AUTOMATIC"
1901 key = scanner.nexttok()
1902 elif scanner.sees("automatic"):
1903 if (not itarg) and len(game.enemies) != 0:
1904 automode = "FORCEMAN"
1906 if len(game.enemies)==0:
1907 prout(_("Energy will be expended into space."))
1908 automode = "AUTOMATIC"
1909 key = scanner.nexttok()
1910 elif scanner.sees("no"):
1915 elif key == "IHREAL":
1916 if len(game.enemies)==0:
1917 prout(_("Energy will be expended into space."))
1918 automode = "AUTOMATIC"
1920 automode = "FORCEMAN"
1922 automode = "AUTOMATIC"
1925 if len(game.enemies)==0:
1926 prout(_("Energy will be expended into space."))
1927 automode = "AUTOMATIC"
1929 automode = "FORCEMAN"
1931 proutn(_("Manual or automatic? "))
1936 if automode == "AUTOMATIC":
1937 if key == "IHALPHA" and scanner.sees("no"):
1939 key = scanner.nexttok()
1940 if key != "IHREAL" and len(game.enemies) != 0:
1941 prout(_("Phasers locked on target. Energy available: %.2f")%avail)
1946 for i in range(len(game.enemies)):
1947 irec += math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))*randreal(1.01, 1.06) + 1.0
1949 proutn(_("%d units required. ") % irec)
1951 proutn(_("Units to fire= "))
1952 key = scanner.nexttok()
1957 proutn(_("Energy available= %.2f") % avail)
1960 if not rpow > avail:
1966 key = scanner.nexttok()
1967 if key == "IHALPHA" and scanner.sees("no"):
1970 game.energy -= 200 # Go and do it!
1971 if checkshctrl(rpow):
1976 if len(game.enemies):
1979 for i in range(len(game.enemies)):
1983 hits[i] = math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))
1984 over = randreal(1.01, 1.06) * hits[i]
1986 powrem -= hits[i] + over
1987 if powrem <= 0 and temp < hits[i]:
1996 if extra > 0 and not game.alldone:
1998 proutn(_("*** Tholian web absorbs "))
1999 if len(game.enemies)>0:
2000 proutn(_("excess "))
2001 prout(_("phaser energy."))
2003 prout(_("%d expended on empty space.") % int(extra))
2004 elif automode == "FORCEMAN":
2007 if damaged(DCOMPTR):
2008 prout(_("Battle computer damaged, manual fire only."))
2011 prouts(_("---WORKING---"))
2013 prout(_("Short-range-sensors-damaged"))
2014 prout(_("Insufficient-data-for-automatic-phaser-fire"))
2015 prout(_("Manual-fire-must-be-used"))
2017 elif automode == "MANUAL":
2019 for k in range(len(game.enemies)):
2020 aim = game.enemies[k].location
2021 ienm = game.quad[aim.i][aim.j]
2023 proutn(_("Energy available= %.2f") % (avail-0.006))
2027 if damaged(DSRSENS) and \
2028 not game.sector.distance(aim)<2**0.5 and ienm in ('C', 'S'):
2029 prout(cramen(ienm) + _(" can't be located without short range scan."))
2032 hits[k] = 0 # prevent overflow -- thanks to Alexei Voitenko
2037 if itarg and k > kz:
2038 irec = (abs(game.enemies[k].power)/(PHASEFAC*math.pow(0.9, game.enemies[k].kdist))) * randreal(1.01, 1.06) + 1.0
2041 if not damaged(DCOMPTR):
2046 proutn(_("units to fire at %s- ") % crmena(False, ienm, "sector", aim))
2047 key = scanner.nexttok()
2048 if key == "IHALPHA" and scanner.sees("no"):
2050 key = scanner.nexttok()
2052 if key == "IHALPHA":
2056 if k == 1: # Let me say I'm baffled by this
2059 if scanner.real < 0:
2063 hits[k] = scanner.real
2064 rpow += scanner.real
2065 # If total requested is too much, inform and start over
2067 prout(_("Available energy exceeded -- try again."))
2070 key = scanner.nexttok() # scan for next value
2073 # zero energy -- abort
2076 if key == "IHALPHA" and scanner.sees("no"):
2081 game.energy -= 200.0
2082 if checkshctrl(rpow):
2086 # Say shield raised or malfunction, if necessary
2093 prout(_("Sulu- \"Sir, the high-speed shield control has malfunctioned . . ."))
2094 prouts(_(" CLICK CLICK POP . . ."))
2095 prout(_(" No response, sir!"))
2098 prout(_("Shields raised."))
2105 game.ididit = False # Nothing if we fail
2108 # Make sure there is room in the brig */
2109 if game.brigfree == 0:
2110 prout(_("Security reports the brig is already full."))
2114 prout(_("Uhura- \"We have no subspace radio communication, sir.\""))
2117 if damaged(DTRANSP):
2118 prout(_("Scotty- \"Transporter damaged, sir.\""))
2121 # find out if there are any at all
2123 prout(_("Uhura- \"Getting no response, sir.\""))
2126 # if there is more than one Klingon, find out which one */
2127 # Cruddy, just takes one at random. Should ask the captain.
2128 # Nah, just select the weakest one since it is most likely to
2129 # surrender (Tom Almy mod)
2130 klingons = [e for e in game.enemies if e.type == 'K']
2131 weakest = sorted(klingons, key=lambda e: e.power)[0]
2132 game.optime = 0.05 # This action will take some time
2133 game.ididit = True # So any others can strike back
2135 # check out that Klingon
2136 # The algorithm isn't that great and could use some more
2137 # intelligent design
2138 # x = 300 + 25*skill;
2139 x = game.energy / (weakest.power * len(klingons))
2140 #prout(_("Stats: energy = %s, kpower = %s, klingons = %s")
2141 # % (game.energy, weakest.power, len(klingons)))
2142 x *= 2.5 # would originally have been equivalent of 1.4,
2143 # but we want command to work more often, more humanely */
2144 #prout(_("Prob = %.4f" % x))
2145 # x = 100; // For testing, of course!
2146 if x < randreal(100):
2147 # guess what, he surrendered!!! */
2148 prout(_("Klingon captain at %s surrenders.") % weakest.location)
2151 prout(_("%d Klingons commit suicide rather than be taken captive.") % (200 - i))
2152 if i > game.brigfree:
2153 prout(_("%d Klingons die because there is no room for them in the brig.") % (i-brigfree))
2156 prout(_("%d captives taken") % i)
2157 deadkl(weakest.location, weakest.type, game.sector)
2162 # big surprise, he refuses to surrender */
2163 prout(_("Fat chance, captain!"))
2165 # Code from events.c begins here.
2167 # This isn't a real event queue a la BSD Trek yet -- you can only have one
2168 # event of each type active at any given time. Mostly these means we can
2169 # only have one FDISTR/FENSLV/FREPRO sequence going at any given time
2170 # BSD Trek, from which we swiped the idea, can have up to 5.
2172 def unschedule(evtype):
2173 "Remove an event from the schedule."
2174 game.future[evtype].date = FOREVER
2175 return game.future[evtype]
2177 def is_scheduled(evtype):
2178 "Is an event of specified type scheduled."
2179 return game.future[evtype].date != FOREVER
2181 def scheduled(evtype):
2182 "When will this event happen?"
2183 return game.future[evtype].date
2185 def schedule(evtype, offset):
2186 "Schedule an event of specified type."
2187 game.future[evtype].date = game.state.date + offset
2188 return game.future[evtype]
2190 def postpone(evtype, offset):
2191 "Postpone a scheduled event."
2192 game.future[evtype].date += offset
2195 "Rest period is interrupted by event."
2198 proutn(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
2200 game.resting = False
2206 "Run through the event queue looking for things to do."
2208 fintim = game.state.date + game.optime
2217 def tractorbeam(yank):
2218 "Tractor-beaming cases merge here."
2220 game.optime = (10.0/(7.5*7.5))*yank # 7.5 is yank rate (warp 7.5)
2222 prout("***" + crmshp() + _(" caught in long range tractor beam--"))
2223 # If Kirk & Co. screwing around on planet, handle
2224 atover(True) # atover(true) is Grab
2227 if game.icraft: # Caught in Galileo?
2230 # Check to see if shuttle is aboard
2231 if game.iscraft == "offship":
2234 prout(_("Galileo, left on the planet surface, is captured"))
2235 prout(_("by aliens and made into a flying McDonald's."))
2236 game.damage[DSHUTTL] = -10
2237 game.iscraft = "removed"
2239 prout(_("Galileo, left on the planet surface, is well hidden."))
2241 game.quadrant = game.state.kscmdr
2243 game.quadrant = game.state.kcmdr[i]
2244 game.sector = randplace(QUADSIZE)
2245 prout(crmshp() + _(" is pulled to Quadrant %s, Sector %s") \
2246 % (game.quadrant, game.sector))
2248 prout(_("(Remainder of rest/repair period cancelled.)"))
2249 game.resting = False
2251 if not damaged(DSHIELD) and game.shield > 0:
2252 doshield(shraise=True) # raise shields
2253 game.shldchg = False
2255 prout(_("(Shields not currently useable.)"))
2257 # Adjust finish time to time of tractor beaming?
2258 # fintim = game.state.date+game.optime
2259 attack(torps_ok=False)
2260 if not game.state.kcmdr:
2263 schedule(FTBEAM, game.optime+expran(1.5*game.intime/len(game.state.kcmdr)))
2266 "Code merges here for any commander destroying a starbase."
2267 # Not perfect, but will have to do
2268 # Handle case where base is in same quadrant as starship
2269 if game.battle == game.quadrant:
2270 game.state.chart[game.battle.i][game.battle.j].starbase = False
2271 game.quad[game.base.i][game.base.j] = '.'
2272 game.base.invalidate()
2275 prout(_("Spock- \"Captain, I believe the starbase has been destroyed.\""))
2276 elif game.state.baseq and communicating():
2277 # Get word via subspace radio
2280 prout(_("Lt. Uhura- \"Captain, Starfleet Command reports that"))
2281 proutn(_(" the starbase in Quadrant %s has been destroyed by") % game.battle)
2283 prout(_("the Klingon Super-Commander"))
2285 prout(_("a Klingon Commander"))
2286 game.state.chart[game.battle.i][game.battle.j].starbase = False
2287 # Remove Starbase from galaxy
2288 game.state.galaxy[game.battle.i][game.battle.j].starbase = False
2289 game.state.baseq = [x for x in game.state.baseq if x != game.battle]
2291 # reinstate a commander's base attack
2295 game.battle.invalidate()
2297 prout("=== EVENTS from %.2f to %.2f:" % (game.state.date, fintim))
2298 for i in range(1, NEVENTS):
2299 if i == FSNOVA: proutn("=== Supernova ")
2300 elif i == FTBEAM: proutn("=== T Beam ")
2301 elif i == FSNAP: proutn("=== Snapshot ")
2302 elif i == FBATTAK: proutn("=== Base Attack ")
2303 elif i == FCDBAS: proutn("=== Base Destroy ")
2304 elif i == FSCMOVE: proutn("=== SC Move ")
2305 elif i == FSCDBAS: proutn("=== SC Base Destroy ")
2306 elif i == FDSPROB: proutn("=== Probe Move ")
2307 elif i == FDISTR: proutn("=== Distress Call ")
2308 elif i == FENSLV: proutn("=== Enslavement ")
2309 elif i == FREPRO: proutn("=== Klingon Build ")
2311 prout("%.2f" % (scheduled(i)))
2314 radio_was_broken = damaged(DRADIO)
2317 # Select earliest extraneous event, evcode==0 if no events
2322 for l in range(1, NEVENTS):
2323 if game.future[l].date < datemin:
2326 prout("== Event %d fires" % evcode)
2327 datemin = game.future[l].date
2328 xtime = datemin-game.state.date
2330 game.energy -= xtime*500.0
2331 if game.energy <= 0:
2334 game.state.date = datemin
2335 # Decrement Federation resources and recompute remaining time
2336 game.state.remres -= (game.remkl()+4*len(game.state.kcmdr))*xtime
2338 if game.state.remtime <= 0:
2341 # Any crew left alive?
2342 if game.state.crew <= 0:
2345 # Is life support adequate?
2346 if damaged(DLIFSUP) and game.condition != "docked":
2347 if game.lsupres < xtime and game.damage[DLIFSUP] > game.lsupres:
2350 game.lsupres -= xtime
2351 if game.damage[DLIFSUP] <= xtime:
2352 game.lsupres = game.inlsr
2355 if game.condition == "docked":
2357 # Don't fix Deathray here
2358 for l in range(NDEVICES):
2359 if game.damage[l] > 0.0 and l != DDRAY:
2360 if game.damage[l]-repair > 0.0:
2361 game.damage[l] -= repair
2363 game.damage[l] = 0.0
2364 # If radio repaired, update star chart and attack reports
2365 if radio_was_broken and not damaged(DRADIO):
2366 prout(_("Lt. Uhura- \"Captain, the sub-space radio is working and"))
2367 prout(_(" surveillance reports are coming in."))
2369 if not game.iseenit:
2373 prout(_(" The star chart is now up to date.\""))
2375 # Cause extraneous event EVCODE to occur
2376 game.optime -= xtime
2377 if evcode == FSNOVA: # Supernova
2380 schedule(FSNOVA, expran(0.5*game.intime))
2381 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2383 elif evcode == FSPY: # Check with spy to see if SC should tractor beam
2384 if game.state.nscrem == 0 or game.iscloaked or \
2385 ictbeam or istract or \
2386 game.condition == "docked" or game.isatb == 1 or game.iscate:
2388 if game.ientesc or \
2389 (game.energy<2000 and game.torps<4 and game.shield < 1250) or \
2390 (damaged(DPHASER) and (damaged(DPHOTON) or game.torps<4)) or \
2391 (damaged(DSHIELD) and \
2392 (game.energy < 2500 or damaged(DPHASER)) and \
2393 (game.torps < 5 or damaged(DPHOTON))):
2395 istract = ictbeam = True
2396 tractorbeam((game.state.kscmdr-game.quadrant).distance())
2399 elif evcode == FTBEAM: # Tractor beam
2400 if not game.state.kcmdr:
2403 i = randrange(len(game.state.kcmdr))
2404 yank = (game.state.kcmdr[i]-game.quadrant).distance()
2405 if istract or game.condition == "docked" or game.iscloaked or yank == 0:
2406 # Drats! Have to reschedule
2408 game.optime + expran(1.5*game.intime/len(game.state.kcmdr)))
2412 elif evcode == FSNAP: # Snapshot of the universe (for time warp)
2413 game.snapsht = copy.deepcopy(game.state)
2414 game.state.snap = True
2415 schedule(FSNAP, expran(0.5 * game.intime))
2416 elif evcode == FBATTAK: # Commander attacks starbase
2417 if not game.state.kcmdr or not game.state.baseq:
2422 ibq = None # Force battle location to persist past loop
2424 for ibq in game.state.baseq:
2425 for cmdr in game.state.kcmdr:
2426 if ibq == cmdr and ibq != game.quadrant and ibq != game.state.kscmdr:
2428 # no match found -- try later
2429 schedule(FBATTAK, expran(0.3*game.intime))
2434 # commander + starbase combination found -- launch attack
2436 schedule(FCDBAS, randreal(1.0, 4.0))
2437 if game.isatb: # extra time if SC already attacking
2438 postpone(FCDBAS, scheduled(FSCDBAS)-game.state.date)
2439 game.future[FBATTAK].date = game.future[FCDBAS].date + expran(0.3*game.intime)
2440 game.iseenit = False
2441 if not communicating():
2442 continue # No warning :-(
2446 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") % game.battle)
2447 prout(_(" reports that it is under attack and that it can"))
2448 prout(_(" hold out only until stardate %d.\"") % (int(scheduled(FCDBAS))))
2451 elif evcode == FSCDBAS: # Supercommander destroys base
2454 if not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].starbase:
2455 continue # WAS RETURN!
2457 game.battle = game.state.kscmdr
2459 elif evcode == FCDBAS: # Commander succeeds in destroying base
2460 if evcode == FCDBAS:
2462 if not game.state.baseq() \
2463 or not game.state.galaxy[game.battle.i][game.battle.j].starbase:
2464 game.battle.invalidate()
2466 # find the lucky pair
2467 for cmdr in game.state.kcmdr:
2468 if cmdr == game.battle:
2471 # No action to take after all
2474 elif evcode == FSCMOVE: # Supercommander moves
2475 schedule(FSCMOVE, 0.2777)
2476 if not game.ientesc and not istract and game.isatb != 1 and \
2477 (not game.iscate or not game.justin):
2479 elif evcode == FDSPROB: # Move deep space probe
2480 schedule(FDSPROB, 0.01)
2481 if not game.probe.nexttok():
2482 if not game.probe.quadrant().valid_quadrant() or \
2483 game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j].supernova:
2484 # Left galaxy or ran into supernova
2488 proutn(_("Lt. Uhura- \"The deep space probe "))
2489 if not game.probe.quadrant().valid_quadrant():
2490 prout(_("has left the galaxy.\""))
2492 prout(_("is no longer transmitting.\""))
2498 prout(_("Lt. Uhura- \"The deep space probe is now in Quadrant %s.\"") % game.probe.quadrant())
2499 pquad = game.probe.quadrant()
2500 pdest = game.state.galaxy[pquad.i][pquad.j]
2502 game.state.chart[pquad.i][pquad.j].klingons = pdest.klingons
2503 game.state.chart[pquad.i][pquad.j].starbase = pdest.starbase
2504 game.state.chart[pquad.i][pquad.j].stars = pdest.stars
2505 pdest.charted = True
2506 game.probe.moves -= 1 # One less to travel
2507 if game.probe.arrived() and game.isarmed and pdest.stars:
2508 supernova(game.probe) # fire in the hole!
2510 if game.state.galaxy[pquad.i][pquad.j].supernova:
2512 elif evcode == FDISTR: # inhabited system issues distress call
2514 # try a whole bunch of times to find something suitable
2515 for i in range(100):
2516 # need a quadrant which is not the current one,
2517 # which has some stars which are inhabited and
2518 # not already under attack, which is not
2519 # supernova'ed, and which has some Klingons in it
2520 w = randplace(GALSIZE)
2521 q = game.state.galaxy[w.i][w.j]
2522 if not (game.quadrant == w or q.planet is None or \
2523 not q.planet.inhabited or \
2524 q.supernova or q.status!="secure" or q.klingons<=0):
2527 # can't seem to find one; ignore this call
2529 prout("=== Couldn't find location for distress event.")
2531 # got one!! Schedule its enslavement
2532 ev = schedule(FENSLV, expran(game.intime))
2534 q.status = "distressed"
2535 # tell the captain about it if we can
2537 prout(_("Uhura- Captain, %s in Quadrant %s reports it is under attack") \
2538 % (q.planet, repr(w)))
2539 prout(_("by a Klingon invasion fleet."))
2542 elif evcode == FENSLV: # starsystem is enslaved
2543 ev = unschedule(FENSLV)
2544 # see if current distress call still active
2545 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2549 q.status = "enslaved"
2551 # play stork and schedule the first baby
2552 ev2 = schedule(FREPRO, expran(2.0 * game.intime))
2553 ev2.quadrant = ev.quadrant
2555 # report the disaster if we can
2557 prout(_("Uhura- We've lost contact with starsystem %s") % \
2559 prout(_("in Quadrant %s.\n") % ev.quadrant)
2560 elif evcode == FREPRO: # Klingon reproduces
2561 # If we ever switch to a real event queue, we'll need to
2562 # explicitly retrieve and restore the x and y.
2563 ev = schedule(FREPRO, expran(1.0 * game.intime))
2564 # see if current distress call still active
2565 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2569 if game.remkl() >= MAXKLGAME:
2570 continue # full right now
2571 # reproduce one Klingon
2574 if game.klhere >= MAXKLQUAD:
2576 # this quadrant not ok, pick an adjacent one
2577 for m.i in range(w.i - 1, w.i + 2):
2578 for m.j in range(w.j - 1, w.j + 2):
2579 if not m.valid_quadrant():
2581 q = game.state.galaxy[m.i][m.j]
2582 # check for this quad ok (not full & no snova)
2583 if q.klingons >= MAXKLQUAD or q.supernova:
2586 # search for eligible quadrant failed
2592 if game.quadrant == w:
2594 game.enemies.append(newkling())
2595 # recompute time left
2598 if game.quadrant == w:
2599 prout(_("Spock- sensors indicate the Klingons have"))
2600 prout(_("launched a warship from %s.") % q.planet)
2602 prout(_("Uhura- Starfleet reports increased Klingon activity"))
2603 if q.planet != None:
2604 proutn(_("near %s ") % q.planet)
2605 prout(_("in Quadrant %s.") % w)
2611 key = scanner.nexttok()
2614 proutn(_("How long? "))
2619 origTime = delay = scanner.real
2622 if delay >= game.state.remtime or len(game.enemies) != 0:
2623 proutn(_("Are you sure? "))
2626 # Alternate resting periods (events) with attacks
2630 game.resting = False
2631 if not game.resting:
2632 prout(_("%d stardates left.") % int(game.state.remtime))
2634 temp = game.optime = delay
2635 if len(game.enemies):
2636 rtime = randreal(1.0, 2.0)
2640 if game.optime < delay:
2641 attack(torps_ok=False)
2649 # Repair Deathray if long rest at starbase
2650 if origTime-delay >= 9.99 and game.condition == "docked":
2651 game.damage[DDRAY] = 0.0
2652 # leave if quadrant supernovas
2653 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2655 game.resting = False
2660 ncourse = (0.0, 10.5, 12.0, 1.5, 9.0, 0.0, 3.0, 7.5, 6.0, 4.5)
2661 newc = Coord(); neighbor = Coord(); bump = Coord(0, 0)
2663 # Wow! We've supernova'ed
2664 supernova(game.quadrant)
2666 # handle initial nova
2667 game.quad[nov.i][nov.j] = '.'
2668 prout(crmena(False, '*', "sector", nov) + _(" novas."))
2669 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2670 game.state.starkl += 1
2671 # Set up queue to recursively trigger adjacent stars
2677 for offset.i in range(-1, 1+1):
2678 for offset.j in range(-1, 1+1):
2679 if offset.j == 0 and offset.i == 0:
2681 neighbor = start + offset
2682 if not neighbor.valid_sector():
2684 iquad = game.quad[neighbor.i][neighbor.j]
2685 # Empty space ends reaction
2686 if iquad in ('.', '?', ' ', 'T', '#'):
2688 elif iquad == '*': # Affect another star
2690 # This star supernovas
2691 supernova(game.quadrant)
2694 hits.append(neighbor)
2695 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2696 game.state.starkl += 1
2697 proutn(crmena(True, '*', "sector", neighbor))
2699 game.quad[neighbor.i][neighbor.j] = '.'
2701 elif iquad in ('P', '@'): # Destroy planet
2702 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
2704 game.state.nplankl += 1
2706 game.state.nworldkl += 1
2707 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2708 game.iplnet.pclass = "destroyed"
2710 game.plnet.invalidate()
2714 game.quad[neighbor.i][neighbor.j] = '.'
2715 elif iquad == 'B': # Destroy base
2716 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
2717 game.state.baseq = [x for x in game.state.baseq if x!= game.quadrant]
2718 game.base.invalidate()
2719 game.state.basekl += 1
2721 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2722 game.quad[neighbor.i][neighbor.j] = '.'
2723 elif iquad in ('E', 'F'): # Buffet ship
2724 prout(_("***Starship buffeted by nova."))
2726 if game.shield >= 2000.0:
2727 game.shield -= 2000.0
2729 diff = 2000.0 - game.shield
2733 prout(_("***Shields knocked out."))
2734 game.damage[DSHIELD] += 0.005*game.damfac*randreal()*diff
2736 game.energy -= 2000.0
2737 if game.energy <= 0:
2740 # add in course nova contributes to kicking starship
2741 bump += (game.sector-hits[-1]).sgn()
2742 elif iquad == 'K': # kill klingon
2743 deadkl(neighbor, iquad, neighbor)
2744 elif iquad in ('C','S','R'): # Damage/destroy big enemies
2746 for ll in range(len(game.enemies)):
2747 if game.enemies[ll].location == neighbor:
2748 target = game.enemies[ll]
2750 if target is not None:
2751 target.power -= 800.0 # If firepower is lost, die
2752 if target.power <= 0.0:
2753 deadkl(neighbor, iquad, neighbor)
2754 continue # neighbor loop
2755 # Else enemy gets flung by the blast wave
2756 newc = neighbor + neighbor - start
2757 proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged"))
2758 if not newc.valid_sector():
2759 # can't leave quadrant
2762 iquad1 = game.quad[newc.i][newc.j]
2764 proutn(_(", blasted into ") + crmena(False, ' ', "sector", newc))
2766 deadkl(neighbor, iquad, newc)
2769 # can't move into something else
2772 proutn(_(", buffeted to Sector %s") % newc)
2773 game.quad[neighbor.i][neighbor.j] = '.'
2774 game.quad[newc.i][newc.j] = iquad
2776 # Starship affected by nova -- kick it away.
2778 direc = ncourse[3*(bump.i+1)+bump.j+2]
2783 scourse = course(bearing=direc, distance=dist)
2784 game.optime = scourse.time(w=4)
2786 prout(_("Force of nova displaces starship."))
2787 imove(scourse, noattack=True)
2788 game.optime = scourse.time(w=4)
2792 "Star goes supernova."
2797 # Scheduled supernova -- select star at random.
2800 for nq.i in range(GALSIZE):
2801 for nq.j in range(GALSIZE):
2802 nstars += game.state.galaxy[nq.i][nq.j].stars
2804 return # nothing to supernova exists
2805 num = randrange(nstars) + 1
2806 for nq.i in range(GALSIZE):
2807 for nq.j in range(GALSIZE):
2808 num -= game.state.galaxy[nq.i][nq.j].stars
2814 proutn("=== Super nova here?")
2817 if not nq == game.quadrant or game.justin:
2818 # it isn't here, or we just entered (treat as enroute)
2821 prout(_("Message from Starfleet Command Stardate %.2f") % game.state.date)
2822 prout(_(" Supernova in Quadrant %s; caution advised.") % nq)
2825 # we are in the quadrant!
2826 num = randrange(game.state.galaxy[nq.i][nq.j].stars) + 1
2827 for ns.i in range(QUADSIZE):
2828 for ns.j in range(QUADSIZE):
2829 if game.quad[ns.i][ns.j]=='*':
2836 prouts(_("***RED ALERT! RED ALERT!"))
2838 prout(_("***Incipient supernova detected at Sector %s") % ns)
2839 if (ns.i-game.sector.i)**2 + (ns.j-game.sector.j)**2 <= 2.1:
2840 proutn(_("Emergency override attempts t"))
2841 prouts("***************")
2845 # destroy any Klingons in supernovaed quadrant
2846 game.state.galaxy[nq.i][nq.j].klingons = 0
2847 if nq == game.state.kscmdr:
2848 # did in the Supercommander!
2849 game.state.nscrem = game.state.kscmdr.i = game.state.kscmdr.j = game.isatb = 0
2853 survivors = filter(lambda w: w != nq, game.state.kcmdr)
2854 comkills = len(game.state.kcmdr) - len(survivors)
2855 game.state.kcmdr = survivors
2856 if not game.state.kcmdr:
2858 # destroy Romulans and planets in supernovaed quadrant
2859 nrmdead = game.state.galaxy[nq.i][nq.j].romulans
2860 game.state.galaxy[nq.i][nq.j].romulans = 0
2861 game.state.nromrem -= nrmdead
2863 for loop in range(game.inplan):
2864 if game.state.planets[loop].quadrant == nq:
2865 game.state.planets[loop].pclass = "destroyed"
2867 # Destroy any base in supernovaed quadrant
2868 game.state.baseq = [x for x in game.state.baseq if x != nq]
2869 # If starship caused supernova, tally up destruction
2871 game.state.starkl += game.state.galaxy[nq.i][nq.j].stars
2872 game.state.basekl += game.state.galaxy[nq.i][nq.j].starbase
2873 game.state.nplankl += npdead
2874 # mark supernova in galaxy and in star chart
2875 if game.quadrant == nq or communicating():
2876 game.state.galaxy[nq.i][nq.j].supernova = True
2877 # If supernova destroys last Klingons give special message
2878 if game.unwon()==0 and not nq == game.quadrant:
2881 prout(_("Lucky you!"))
2882 proutn(_("A supernova in %s has just destroyed the last Klingons.") % nq)
2885 # if some Klingons remain, continue or die in supernova
2890 # Code from finish.c ends here.
2893 "Self-destruct maneuver. Finish with a BANG!"
2895 if damaged(DCOMPTR):
2896 prout(_("Computer damaged; cannot execute destruct sequence."))
2898 prouts(_("---WORKING---")); skip(1)
2899 prouts(_("SELF-DESTRUCT-SEQUENCE-ACTIVATED")); skip(1)
2900 prouts(" 10"); skip(1)
2901 prouts(" 9"); skip(1)
2902 prouts(" 8"); skip(1)
2903 prouts(" 7"); skip(1)
2904 prouts(" 6"); skip(1)
2906 prout(_("ENTER-CORRECT-PASSWORD-TO-CONTINUE-"))
2908 prout(_("SELF-DESTRUCT-SEQUENCE-OTHERWISE-"))
2910 prout(_("SELF-DESTRUCT-SEQUENCE-WILL-BE-ABORTED"))
2913 if game.passwd != scanner.token:
2914 prouts(_("PASSWORD-REJECTED;"))
2916 prouts(_("CONTINUITY-EFFECTED"))
2919 prouts(_("PASSWORD-ACCEPTED")); skip(1)
2920 prouts(" 5"); skip(1)
2921 prouts(" 4"); skip(1)
2922 prouts(" 3"); skip(1)
2923 prouts(" 2"); skip(1)
2924 prouts(" 1"); skip(1)
2926 prouts(_("GOODBYE-CRUEL-WORLD"))
2934 prouts(_("********* Entropy of %s maximized *********") % crmshp())
2938 if len(game.enemies) != 0:
2939 whammo = 25.0 * game.energy
2940 for l in range(len(game.enemies)):
2941 if game.enemies[l].power*game.enemies[l].kdist <= whammo:
2942 deadkl(game.enemies[l].location, game.quad[game.enemies[l].location.i][game.enemies[l].location.j], game.enemies[l].location)
2946 "Compute our rate of kils over time."
2947 elapsed = game.state.date - game.indate
2948 if elapsed == 0: # Avoid divide-by-zero error if calculated on turn 0
2951 starting = (game.inkling + game.incom + game.inscom)
2952 remaining = game.unwon()
2953 return (starting - remaining)/elapsed
2957 badpt = 5.0*game.state.starkl + \
2959 10.0*game.state.nplankl + \
2960 300*game.state.nworldkl + \
2962 100.0*game.state.basekl +\
2963 3.0*game.abandoned +\
2965 if game.ship == 'F':
2967 elif game.ship is None:
2972 # end the game, with appropriate notifications
2976 prout(_("It is stardate %.1f.") % game.state.date)
2978 if ifin == FWON: # Game has been won
2979 if game.state.nromrem != 0:
2980 prout(_("The remaining %d Romulans surrender to Starfleet Command.") %
2983 prout(_("You have smashed the Klingon invasion fleet and saved"))
2984 prout(_("the Federation."))
2985 if game.alive and game.brigcapacity-game.brigfree > 0:
2986 game.kcaptured += game.brigcapacity-game.brigfree
2987 prout(_("The %d captured Klingons are transferred to Star Fleet Command.") % (game.brigcapacity-game.brigfree))
2992 badpt = 0.0 # Close enough!
2993 # killsPerDate >= RateMax
2994 if game.state.date-game.indate < 5.0 or \
2995 killrate() >= 0.1*game.skill*(game.skill+1.0) + 0.1 + 0.008*badpt:
2997 prout(_("In fact, you have done so well that Starfleet Command"))
2998 if game.skill == SKILL_NOVICE:
2999 prout(_("promotes you one step in rank from \"Novice\" to \"Fair\"."))
3000 elif game.skill == SKILL_FAIR:
3001 prout(_("promotes you one step in rank from \"Fair\" to \"Good\"."))
3002 elif game.skill == SKILL_GOOD:
3003 prout(_("promotes you one step in rank from \"Good\" to \"Expert\"."))
3004 elif game.skill == SKILL_EXPERT:
3005 prout(_("promotes you to Commodore Emeritus."))
3007 prout(_("Now that you think you're really good, try playing"))
3008 prout(_("the \"Emeritus\" game. It will splatter your ego."))
3009 elif game.skill == SKILL_EMERITUS:
3011 proutn(_("Computer- "))
3012 prouts(_("ERROR-ERROR-ERROR-ERROR"))
3014 prouts(_(" YOUR-SKILL-HAS-EXCEEDED-THE-CAPACITY-OF-THIS-PROGRAM"))
3016 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
3018 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
3020 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
3022 prouts(_(" THIS-PROGRAM-MUST?- MUST ? - SUR? ? -? VI"))
3024 prout(_("Now you can retire and write your own Star Trek game!"))
3026 elif game.skill >= SKILL_EXPERT:
3027 if game.thawed and not game.idebug:
3028 prout(_("You cannot get a citation, so..."))
3030 proutn(_("Do you want your Commodore Emeritus Citation printed? "))
3034 # Only grant long life if alive (original didn't!)
3036 prout(_("LIVE LONG AND PROSPER."))
3041 elif ifin == FDEPLETE: # Federation Resources Depleted
3042 prout(_("Your time has run out and the Federation has been"))
3043 prout(_("conquered. Your starship is now Klingon property,"))
3044 prout(_("and you are put on trial as a war criminal. On the"))
3045 proutn(_("basis of your record, you are "))
3046 if game.unwon()*3.0 > (game.inkling + game.incom + game.inscom):
3047 prout(_("acquitted."))
3049 prout(_("LIVE LONG AND PROSPER."))
3051 prout(_("found guilty and"))
3052 prout(_("sentenced to death by slow torture."))
3056 elif ifin == FLIFESUP:
3057 prout(_("Your life support reserves have run out, and"))
3058 prout(_("you die of thirst, starvation, and asphyxiation."))
3059 prout(_("Your starship is a derelict in space."))
3061 prout(_("Your energy supply is exhausted."))
3063 prout(_("Your starship is a derelict in space."))
3064 elif ifin == FBATTLE:
3065 prout(_("The %s has been destroyed in battle.") % crmshp())
3067 prout(_("Dulce et decorum est pro patria mori."))
3069 prout(_("You have made three attempts to cross the negative energy"))
3070 prout(_("barrier which surrounds the galaxy."))
3072 prout(_("Your navigation is abominable."))
3075 prout(_("Your starship has been destroyed by a nova."))
3076 prout(_("That was a great shot."))
3078 elif ifin == FSNOVAED:
3079 prout(_("The %s has been fried by a supernova.") % crmshp())
3080 prout(_("...Not even cinders remain..."))
3081 elif ifin == FABANDN:
3082 prout(_("You have been captured by the Klingons. If you still"))
3083 prout(_("had a starbase to be returned to, you would have been"))
3084 prout(_("repatriated and given another chance. Since you have"))
3085 prout(_("no starbases, you will be mercilessly tortured to death."))
3086 elif ifin == FDILITHIUM:
3087 prout(_("Your starship is now an expanding cloud of subatomic particles"))
3088 elif ifin == FMATERIALIZE:
3089 prout(_("Starbase was unable to re-materialize your starship."))
3090 prout(_("Sic transit gloria mundi"))
3091 elif ifin == FPHASER:
3092 prout(_("The %s has been cremated by its own phasers.") % crmshp())
3094 prout(_("You and your landing party have been"))
3095 prout(_("converted to energy, dissipating through space."))
3096 elif ifin == FMINING:
3097 prout(_("You are left with your landing party on"))
3098 prout(_("a wild jungle planet inhabited by primitive cannibals."))
3100 prout(_("They are very fond of \"Captain Kirk\" soup."))
3102 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
3103 elif ifin == FDPLANET:
3104 prout(_("You and your mining party perish."))
3106 prout(_("That was a great shot."))
3109 prout(_("The Galileo is instantly annihilated by the supernova."))
3110 prout(_("You and your mining party are atomized."))
3112 prout(_("Mr. Spock takes command of the %s and") % crmshp())
3113 prout(_("joins the Romulans, wreaking terror on the Federation."))
3114 elif ifin == FPNOVA:
3115 prout(_("You and your mining party are atomized."))
3117 prout(_("Mr. Spock takes command of the %s and") % crmshp())
3118 prout(_("joins the Romulans, wreaking terror on the Federation."))
3119 elif ifin == FSTRACTOR:
3120 prout(_("The shuttle craft Galileo is also caught,"))
3121 prout(_("and breaks up under the strain."))
3123 prout(_("Your debris is scattered for millions of miles."))
3124 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
3126 prout(_("The mutants attack and kill Spock."))
3127 prout(_("Your ship is captured by Klingons, and"))
3128 prout(_("your crew is put on display in a Klingon zoo."))
3129 elif ifin == FTRIBBLE:
3130 prout(_("Tribbles consume all remaining water,"))
3131 prout(_("food, and oxygen on your ship."))
3133 prout(_("You die of thirst, starvation, and asphyxiation."))
3134 prout(_("Your starship is a derelict in space."))
3136 prout(_("Your ship is drawn to the center of the black hole."))
3137 prout(_("You are crushed into extremely dense matter."))
3138 elif ifin == FCLOAK:
3140 prout(_("You have violated the Treaty of Algeron."))
3141 prout(_("The Romulan Empire can never trust you again."))
3143 prout(_("Your last crew member has died."))
3144 if ifin != FWON and ifin != FCLOAK and game.iscloaked:
3145 prout(_("Your ship was cloaked so your subspace radio did not receive anything."))
3146 prout(_("You may have missed some warning messages."))
3148 if game.ship == 'F':
3150 elif game.ship == 'E':
3153 if game.unwon() != 0:
3154 goodies = game.state.remres/game.inresor
3155 baddies = (game.remkl() + 2.0*len(game.state.kcmdr))/(game.inkling+2.0*game.incom)
3156 if goodies/baddies >= randreal(1.0, 1.5):
3157 prout(_("As a result of your actions, a treaty with the Klingon"))
3158 prout(_("Empire has been signed. The terms of the treaty are"))
3159 if goodies/baddies >= randreal(3.0):
3160 prout(_("favorable to the Federation."))
3162 prout(_("Congratulations!"))
3164 prout(_("highly unfavorable to the Federation."))
3166 prout(_("The Federation will be destroyed."))
3168 prout(_("Since you took the last Klingon with you, you are a"))
3169 prout(_("martyr and a hero. Someday maybe they'll erect a"))
3170 prout(_("statue in your memory. Rest in peace, and try not"))
3171 prout(_("to think about pigeons."))
3174 scanner.chew() # Clean up leftovers
3177 "Compute player's score."
3178 timused = game.state.date - game.indate
3179 if (timused == 0 or game.unwon() != 0) and timused < 5.0:
3181 game.perdate = killrate()
3182 ithperd = 500*game.perdate + 0.5
3185 iwon = 100*game.skill
3186 if game.ship == 'E':
3188 elif game.ship == 'F':
3192 game.score = 10*(game.inkling - game.remkl()) \
3193 + 50*(game.incom - len(game.state.kcmdr)) \
3195 + 20*(game.inrom - game.state.nromrem) \
3196 + 200*(game.inscom - game.state.nscrem) \
3197 - game.state.nromrem \
3198 + 3 * game.kcaptured \
3203 prout(_("Your score --"))
3204 if game.inrom - game.state.nromrem:
3205 prout(_("%6d Romulans destroyed %5d") %
3206 (game.inrom - game.state.nromrem, 20*(game.inrom - game.state.nromrem)))
3207 if game.state.nromrem and game.gamewon:
3208 prout(_("%6d Romulans captured %5d") %
3209 (game.state.nromrem, game.state.nromrem))
3210 if game.inkling - game.remkl():
3211 prout(_("%6d ordinary Klingons destroyed %5d") %
3212 (game.inkling - game.remkl(), 10*(game.inkling - game.remkl())))
3213 if game.incom - len(game.state.kcmdr):
3214 prout(_("%6d Klingon commanders destroyed %5d") %
3215 (game.incom - len(game.state.kcmdr), 50*(game.incom - len(game.state.kcmdr))))
3217 prout(_("%d Klingons captured %5d") %
3218 (game.kcaptured, 3 * game.kcaptured))
3219 if game.inscom - game.state.nscrem:
3220 prout(_("%6d Super-Commander destroyed %5d") %
3221 (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem)))
3223 prout(_("%6.2f Klingons per stardate %5d") %
3224 (game.perdate, ithperd))
3225 if game.state.starkl:
3226 prout(_("%6d stars destroyed by your action %5d") %
3227 (game.state.starkl, -5*game.state.starkl))
3228 if game.state.nplankl:
3229 prout(_("%6d planets destroyed by your action %5d") %
3230 (game.state.nplankl, -10*game.state.nplankl))
3231 if (game.options & OPTION_WORLDS) and game.state.nworldkl:
3232 prout(_("%6d inhabited planets destroyed by your action %5d") %
3233 (game.state.nworldkl, -300*game.state.nworldkl))
3234 if game.state.basekl:
3235 prout(_("%6d bases destroyed by your action %5d") %
3236 (game.state.basekl, -100*game.state.basekl))
3238 prout(_("%6d calls for help from starbase %5d") %
3239 (game.nhelp, -45*game.nhelp))
3241 prout(_("%6d casualties incurred %5d") %
3242 (game.casual, -game.casual))
3244 prout(_("%6d crew abandoned in space %5d") %
3245 (game.abandoned, -3*game.abandoned))
3247 prout(_("%6d ship(s) lost or destroyed %5d") %
3248 (klship, -100*klship))
3251 prout(_("1 Treaty of Algeron violation -100"))
3253 prout(_("%6d Treaty of Algeron violations %5d\n") %
3254 (ncviol, -100*ncviol))
3256 prout(_("Penalty for getting yourself killed -200"))
3258 proutn(_("Bonus for winning "))
3259 if game.skill == SKILL_NOVICE: proutn(_("Novice game "))
3260 elif game.skill == SKILL_FAIR: proutn(_("Fair game "))
3261 elif game.skill == SKILL_GOOD: proutn(_("Good game "))
3262 elif game.skill == SKILL_EXPERT: proutn(_("Expert game "))
3263 elif game.skill == SKILL_EMERITUS: proutn(_("Emeritus game"))
3264 prout(" %5d" % iwon)
3266 prout(_("TOTAL SCORE %5d") % game.score)
3269 "Emit winner's commemmorative plaque."
3272 proutn(_("File or device name for your plaque: "))
3275 fp = open(winner, "w")
3278 prout(_("Invalid name."))
3280 proutn(_("Enter name to go on plaque (up to 30 characters): "))
3282 # The 38 below must be 64 for 132-column paper
3283 nskip = 38 - len(winner)/2
3284 # This is where the ASCII art picture was emitted.
3285 # It got garbled somewhere in the chain of transmission to the Almy version.
3286 # We should restore it if we can find old enough FORTRAN sources.
3288 fp.write(_(" U. S. S. ENTERPRISE\n"))
3289 fp.write("\n\n\n\n")
3290 fp.write(_(" For demonstrating outstanding ability as a starship captain\n"))
3292 fp.write(_(" Starfleet Command bestows to you\n"))
3294 fp.write("%*s%s\n\n" % (nskip, "", winner))
3295 fp.write(_(" the rank of\n\n"))
3296 fp.write(_(" \"Commodore Emeritus\"\n\n"))
3298 if game.skill == SKILL_EXPERT:
3299 fp.write(_(" Expert level\n\n"))
3300 elif game.skill == SKILL_EMERITUS:
3301 fp.write(_("Emeritus level\n\n"))
3303 fp.write(_(" Cheat level\n\n"))
3304 timestring = time.ctime()
3305 fp.write(_(" This day of %.6s %.4s, %.8s\n\n") %
3306 (timestring+4, timestring+20, timestring+11))
3307 fp.write(_(" Your score: %d\n\n") % game.score)
3308 fp.write(_(" Klingons per stardate: %.2f\n") % game.perdate)
3311 # Code from io.c begins here
3313 rows = linecount = 0 # for paging
3316 fullscreen_window = None
3317 srscan_window = None # Short range scan
3318 report_window = None # Report legends for status window
3319 status_window = None # The status window itself
3320 lrscan_window = None # Long range scan
3321 message_window = None # Main window for scrolling text
3322 prompt_window = None # Prompt window at bottom of display
3327 # for some recent versions of python2, the following enables UTF8
3328 # for the older ones we probably need to set C locale, and python3
3329 # has no problems at all
3330 if sys.version_info[0] < 3:
3331 locale.setlocale(locale.LC_ALL, "")
3332 gettext.bindtextdomain("sst", "/usr/local/share/locale")
3333 gettext.textdomain("sst")
3334 if not (game.options & OPTION_CURSES):
3335 ln_env = os.getenv("LINES")
3341 stdscr = curses.initscr()
3345 if game.options & OPTION_COLOR:
3346 curses.start_color()
3347 curses.use_default_colors()
3348 curses.init_pair(curses.COLOR_BLACK, curses.COLOR_BLACK, -1)
3349 curses.init_pair(curses.COLOR_GREEN, curses.COLOR_GREEN, -1)
3350 curses.init_pair(curses.COLOR_RED, curses.COLOR_RED, -1)
3351 curses.init_pair(curses.COLOR_CYAN, curses.COLOR_CYAN, -1)
3352 curses.init_pair(curses.COLOR_WHITE, curses.COLOR_WHITE, -1)
3353 curses.init_pair(curses.COLOR_MAGENTA, curses.COLOR_MAGENTA, -1)
3354 curses.init_pair(curses.COLOR_BLUE, curses.COLOR_BLUE, -1)
3355 curses.init_pair(curses.COLOR_YELLOW, curses.COLOR_YELLOW, -1)
3356 global fullscreen_window, srscan_window, report_window, status_window
3357 global lrscan_window, message_window, prompt_window
3358 (rows, _columns) = stdscr.getmaxyx()
3359 fullscreen_window = stdscr
3360 srscan_window = curses.newwin(12, 25, 0, 0)
3361 report_window = curses.newwin(11, 0, 1, 25)
3362 status_window = curses.newwin(10, 0, 1, 39)
3363 lrscan_window = curses.newwin(5, 0, 0, 64)
3364 message_window = curses.newwin(0, 0, 12, 0)
3365 prompt_window = curses.newwin(1, 0, rows-2, 0)
3366 message_window.scrollok(True)
3367 setwnd(fullscreen_window)
3371 if game.options & OPTION_CURSES:
3372 stdscr.keypad(False)
3378 "Wait for user action -- OK to do nothing if on a TTY"
3379 if game.options & OPTION_CURSES:
3384 prouts(_("[ANNOUNCEMENT ARRIVING...]"))
3388 if game.skill > SKILL_FAIR:
3389 prompt = _("[CONTINUE?]")
3391 prompt = _("[PRESS ENTER TO CONTINUE]")
3393 if game.options & OPTION_CURSES:
3395 setwnd(prompt_window)
3396 prompt_window.clear()
3397 prompt_window.addstr(prompt)
3398 prompt_window.getstr()
3399 prompt_window.clear()
3400 prompt_window.refresh()
3401 setwnd(message_window)
3404 sys.stdout.write('\n')
3408 sys.stdout.write('\n' * rows)
3412 "Skip i lines. Pause game if this would cause a scrolling event."
3413 for _dummy in range(i):
3414 if game.options & OPTION_CURSES:
3415 (y, _x) = curwnd.getyx()
3418 except curses.error:
3423 if rows and linecount >= rows:
3426 sys.stdout.write('\n')
3428 def proutn(proutntline):
3429 "Utter a line with no following line feed."
3430 if game.options & OPTION_CURSES:
3431 (y, x) = curwnd.getyx()
3432 (my, _mx) = curwnd.getmaxyx()
3433 if curwnd == message_window and y >= my - 2:
3436 # Uncomment this to debug curses problems
3438 # logfp.write("#curses: at %s proutn(%s)\n" % ((y, x), repr(proutntline)))
3439 curwnd.addstr(proutntline)
3442 sys.stdout.write(proutntline)
3445 def prout(proutline):
3449 def prouts(proutsline):
3451 for c in proutsline:
3452 if not replayfp or replayfp.closed: # Don't slow down replays
3455 if game.options & OPTION_CURSES:
3459 if not replayfp or replayfp.closed:
3463 "Get a line of input."
3464 if game.options & OPTION_CURSES:
3465 linein = curwnd.getstr() + "\n"
3468 if replayfp and not replayfp.closed:
3470 linein = replayfp.readline()
3473 prout("*** Replay finished")
3476 elif linein[0] != "#":
3480 linein = my_input() + "\n"
3489 "Change windows -- OK for this to be a no-op in tty mode."
3491 if game.options & OPTION_CURSES:
3492 # Uncomment this to debug curses problems
3494 if wnd == fullscreen_window:
3495 legend = "fullscreen"
3496 elif wnd == srscan_window:
3498 elif wnd == report_window:
3500 elif wnd == status_window:
3502 elif wnd == lrscan_window:
3504 elif wnd == message_window:
3506 elif wnd == prompt_window:
3510 #logfp.write("#curses: setwnd(%s)\n" % legend)
3512 # Some curses implementations get confused when you try this.
3514 curses.curs_set(wnd in (fullscreen_window, message_window, prompt_window))
3515 except curses.error:
3519 "Clear to end of line -- can be a no-op in tty mode"
3520 if game.options & OPTION_CURSES:
3525 "Clear screen -- can be a no-op in tty mode."
3527 if game.options & OPTION_CURSES:
3533 def textcolor(color=DEFAULT):
3534 if (game.options & OPTION_COLOR) and (game.options & OPTION_CURSES):
3535 if color == DEFAULT:
3537 elif color == BLACK:
3538 curwnd.attron(curses.color_pair(curses.COLOR_BLACK))
3540 curwnd.attron(curses.color_pair(curses.COLOR_BLUE))
3541 elif color == GREEN:
3542 curwnd.attron(curses.color_pair(curses.COLOR_GREEN))
3544 curwnd.attron(curses.color_pair(curses.COLOR_CYAN))
3546 curwnd.attron(curses.color_pair(curses.COLOR_RED))
3547 elif color == MAGENTA:
3548 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA))
3549 elif color == BROWN:
3550 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW))
3551 elif color == LIGHTGRAY:
3552 curwnd.attron(curses.color_pair(curses.COLOR_WHITE))
3553 elif color == DARKGRAY:
3554 curwnd.attron(curses.color_pair(curses.COLOR_BLACK) | curses.A_BOLD)
3555 elif color == LIGHTBLUE:
3556 curwnd.attron(curses.color_pair(curses.COLOR_BLUE) | curses.A_BOLD)
3557 elif color == LIGHTGREEN:
3558 curwnd.attron(curses.color_pair(curses.COLOR_GREEN) | curses.A_BOLD)
3559 elif color == LIGHTCYAN:
3560 curwnd.attron(curses.color_pair(curses.COLOR_CYAN) | curses.A_BOLD)
3561 elif color == LIGHTRED:
3562 curwnd.attron(curses.color_pair(curses.COLOR_RED) | curses.A_BOLD)
3563 elif color == LIGHTMAGENTA:
3564 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA) | curses.A_BOLD)
3565 elif color == YELLOW:
3566 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW) | curses.A_BOLD)
3567 elif color == WHITE:
3568 curwnd.attron(curses.color_pair(curses.COLOR_WHITE) | curses.A_BOLD)
3571 if (game.options & OPTION_COLOR) and (game.options & OPTION_CURSES):
3572 curwnd.attron(curses.A_REVERSE)
3575 # Things past this point have policy implications.
3579 "Hook to be called after moving to redraw maps."
3580 if game.options & OPTION_CURSES:
3583 setwnd(srscan_window)
3587 setwnd(status_window)
3588 status_window.clear()
3589 status_window.move(0, 0)
3590 setwnd(report_window)
3591 report_window.clear()
3592 report_window.move(0, 0)
3594 setwnd(lrscan_window)
3595 lrscan_window.clear()
3596 lrscan_window.move(0, 0)
3597 lrscan(silent=False)
3599 def put_srscan_sym(w, sym):
3600 "Emit symbol for short-range scan."
3601 srscan_window.move(w.i+1, w.j*2+2)
3602 srscan_window.addch(sym)
3603 srscan_window.refresh()
3606 "Enemy fall down, go boom."
3607 if game.options & OPTION_CURSES:
3609 setwnd(srscan_window)
3610 srscan_window.attron(curses.A_REVERSE)
3611 put_srscan_sym(w, game.quad[w.i][w.j])
3615 srscan_window.attroff(curses.A_REVERSE)
3616 put_srscan_sym(w, game.quad[w.i][w.j])
3617 curses.delay_output(500)
3618 setwnd(message_window)
3621 "Sound and visual effects for teleportation."
3622 if game.options & OPTION_CURSES:
3624 setwnd(message_window)
3626 prouts(" . . . . . ")
3627 if game.options & OPTION_CURSES:
3628 #curses.delay_output(1000)
3632 def tracktorpedo(w, step, i, n, iquad):
3633 "Torpedo-track animation."
3634 if not game.options & OPTION_CURSES:
3638 proutn(_("Track for torpedo number %d- ") % (i+1))
3641 proutn(_("Torpedo track- "))
3642 elif step==4 or step==9:
3646 if not damaged(DSRSENS) or game.condition=="docked":
3647 if i != 0 and step == 1:
3650 if (iquad=='.') or (iquad==' '):
3651 put_srscan_sym(w, '+')
3655 put_srscan_sym(w, iquad)
3657 curwnd.attron(curses.A_REVERSE)
3658 put_srscan_sym(w, iquad)
3662 curwnd.attroff(curses.A_REVERSE)
3663 put_srscan_sym(w, iquad)
3668 "Display the current galaxy chart."
3669 if game.options & OPTION_CURSES:
3670 setwnd(message_window)
3671 message_window.clear()
3673 if game.options & OPTION_TTY:
3678 def prstat(txt, data):
3680 if game.options & OPTION_CURSES:
3682 setwnd(status_window)
3684 proutn(" " * (NSYM - len(txt)))
3687 if game.options & OPTION_CURSES:
3688 setwnd(report_window)
3690 # Code from moving.c begins here
3692 def imove(icourse=None, noattack=False):
3693 "Movement execution for warp, impulse, supernova, and tractor-beam events."
3696 def newquadrant(noattack):
3697 # Leaving quadrant -- allow final enemy attack
3698 # Don't set up attack if being pushed by nova or cloaked
3699 if len(game.enemies) != 0 and not noattack and not game.iscloaked:
3701 for enemy in game.enemies:
3702 finald = (w - enemy.location).distance()
3703 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3704 # Stas Sergeev added the condition
3705 # that attacks only happen if Klingons
3706 # are present and your skill is good.
3707 if game.skill > SKILL_GOOD and game.klhere > 0 and not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3708 attack(torps_ok=False)
3711 # check for edge of galaxy
3715 if icourse.final.i < 0:
3716 icourse.final.i = -icourse.final.i
3718 if icourse.final.j < 0:
3719 icourse.final.j = -icourse.final.j
3721 if icourse.final.i >= GALSIZE*QUADSIZE:
3722 icourse.final.i = (GALSIZE*QUADSIZE*2) - icourse.final.i
3724 if icourse.final.j >= GALSIZE*QUADSIZE:
3725 icourse.final.j = (GALSIZE*QUADSIZE*2) - icourse.final.j
3733 if game.nkinks == 3:
3734 # Three strikes -- you're out!
3738 prout(_("YOU HAVE ATTEMPTED TO CROSS THE NEGATIVE ENERGY BARRIER"))
3739 prout(_("AT THE EDGE OF THE GALAXY. THE THIRD TIME YOU TRY THIS,"))
3740 prout(_("YOU WILL BE DESTROYED."))
3741 # Compute final position in new quadrant
3742 if trbeam: # Don't bother if we are to be beamed
3744 game.quadrant = icourse.final.quadrant()
3745 game.sector = icourse.final.sector()
3747 prout(_("Entering Quadrant %s.") % game.quadrant)
3748 game.quad[game.sector.i][game.sector.j] = game.ship
3750 if game.skill>SKILL_NOVICE:
3751 attack(torps_ok=False)
3753 def check_collision(h):
3754 iquad = game.quad[h.i][h.j]
3756 # object encountered in flight path
3757 stopegy = 50.0*icourse.distance/game.optime
3758 if iquad in ('T', 'K', 'C', 'S', 'R', '?'):
3759 for enemy in game.enemies:
3760 if enemy.location == game.sector:
3761 collision(rammed=False, enemy=enemy)
3763 # This should not happen
3764 prout(_("Which way did he go?"))
3768 prouts(_("***RED ALERT! RED ALERT!"))
3770 proutn("***" + crmshp())
3771 proutn(_(" pulled into black hole at Sector %s") % h)
3772 # Getting pulled into a black hole was certain
3773 # death in Almy's original. Stas Sergeev added a
3774 # possibility that you'll get timewarped instead.
3776 for m in range(NDEVICES):
3777 if game.damage[m]>0:
3779 probf=math.pow(1.4,(game.energy+game.shield)/5000.0-1.0)*math.pow(1.3,1.0/(n+1)-1.0)
3780 if (game.options & OPTION_BLKHOLE) and withprob(1-probf):
3790 prout(_(" encounters Tholian web at %s;") % h)
3792 prout(_(" blocked by object at %s;") % h)
3793 proutn(_("Emergency stop required "))
3794 prout(_("%2d units of energy.") % int(stopegy))
3795 game.energy -= stopegy
3796 if game.energy <= 0:
3803 prout(_("Helmsman Sulu- \"Leaving standard orbit.\""))
3804 game.inorbit = False
3805 # If tractor beam is to occur, don't move full distance
3806 if game.state.date+game.optime >= scheduled(FTBEAM):
3808 # We can't be tractor beamed if cloaked,
3809 # so move the event into the future
3810 postpone(FTBEAM, game.optime + expran(1.5*game.intime/len(game.kcmdr)))
3814 game.condition = "red"
3815 icourse.distance = icourse.distance*(scheduled(FTBEAM)-game.state.date)/game.optime + 0.1
3816 game.optime = scheduled(FTBEAM) - game.state.date + 1e-5
3818 game.quad[game.sector.i][game.sector.j] = '.'
3819 for _m in range(icourse.moves):
3821 w = icourse.sector()
3822 if icourse.origin.quadrant() != icourse.location.quadrant():
3823 newquadrant(noattack)
3825 elif check_collision(w):
3826 print("Collision detected")
3830 # We're in destination quadrant -- compute new average enemy distances
3831 game.quad[game.sector.i][game.sector.j] = game.ship
3833 for enemy in game.enemies:
3834 finald = (w-enemy.location).distance()
3835 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3836 enemy.kdist = finald
3838 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3839 attack(torps_ok=False)
3840 for enemy in game.enemies:
3841 enemy.kavgd = enemy.kdist
3844 setwnd(message_window)
3848 "Dock our ship at a starbase."
3850 if game.condition == "docked" and verbose:
3851 prout(_("Already docked."))
3854 prout(_("You must first leave standard orbit."))
3856 if game.base is None or abs(game.sector.i-game.base.i) > 1 or abs(game.sector.j-game.base.j) > 1:
3857 prout(crmshp() + _(" not adjacent to base."))
3860 prout(_("You cannot dock while cloaked."))
3862 game.condition = "docked"
3866 if game.energy < game.inenrg:
3867 game.energy = game.inenrg
3868 game.shield = game.inshld
3869 game.torps = game.intorps
3870 game.lsupres = game.inlsr
3871 game.state.crew = FULLCREW
3872 if game.brigcapacity-game.brigfree > 0:
3873 prout(_("%d captured Klingons transferred to base") % (game.brigcapacity-game.brigfree))
3874 game.kcaptured += game.brigcapacity-game.brigfree
3875 game.brigfree = game.brigcapacity
3876 if communicating() and \
3877 ((is_scheduled(FCDBAS) or game.isatb == 1) and not game.iseenit):
3878 # get attack report from base
3879 prout(_("Lt. Uhura- \"Captain, an important message from the starbase:\""))
3883 def cartesian(loc1=None, loc2=None):
3885 return game.quadrant * QUADSIZE + game.sector
3887 return game.quadrant * QUADSIZE + loc1
3889 return loc1 * QUADSIZE + loc2
3891 def getcourse(isprobe):
3892 "Get a course and distance from the user."
3894 dquad = copy.copy(game.quadrant)
3895 navmode = "unspecified"
3899 if game.landed and not isprobe:
3900 prout(_("Dummy! You can't leave standard orbit until you"))
3901 proutn(_("are back aboard the ship."))
3904 while navmode == "unspecified":
3905 if damaged(DNAVSYS):
3907 prout(_("Computer damaged; manual navigation only"))
3909 prout(_("Computer damaged; manual movement only"))
3914 key = scanner.nexttok()
3916 proutn(_("Manual or automatic- "))
3919 elif key == "IHALPHA":
3920 if scanner.sees("manual"):
3922 key = scanner.nexttok()
3924 elif scanner.sees("automatic"):
3925 navmode = "automatic"
3926 key = scanner.nexttok()
3934 prout(_("(Manual navigation assumed.)"))
3936 prout(_("(Manual movement assumed.)"))
3940 if navmode == "automatic":
3941 while key == "IHEOL":
3943 proutn(_("Target quadrant or quadrant§or- "))
3945 proutn(_("Destination sector or quadrant§or- "))
3948 key = scanner.nexttok()
3952 xi = int(round(scanner.real))-1
3953 key = scanner.nexttok()
3957 xj = int(round(scanner.real))-1
3958 key = scanner.nexttok()
3960 # both quadrant and sector specified
3961 xk = int(round(scanner.real))-1
3962 key = scanner.nexttok()
3966 xl = int(round(scanner.real))-1
3972 # only one pair of numbers was specified
3974 # only quadrant specified -- go to center of dest quad
3977 dsect.j = dsect.i = 4 # preserves 1-origin behavior
3979 # only sector specified
3983 if not dquad.valid_quadrant() or not dsect.valid_sector():
3990 prout(_("Helmsman Sulu- \"Course locked in for Sector %s.\"") % dsect)
3992 prout(_("Ensign Chekov- \"Course laid in, Captain.\""))
3993 # the actual deltas get computed here
3994 delta.j = dquad.j-game.quadrant.j + (dsect.j-game.sector.j)/(QUADSIZE*1.0)
3995 delta.i = game.quadrant.i-dquad.i + (game.sector.i-dsect.i)/(QUADSIZE*1.0)
3997 while key == "IHEOL":
3998 proutn(_("X and Y displacements- "))
4001 key = scanner.nexttok()
4004 delta.j = scanner.real
4008 key = scanner.nexttok()
4010 delta.i = scanner.real
4011 elif key == "IHEOL":
4017 # Check for zero movement
4018 if delta.i == 0 and delta.j == 0:
4021 if itemp == "verbose" and not isprobe:
4023 prout(_("Helmsman Sulu- \"Aye, Sir.\""))
4025 return course(bearing=delta.bearing(), distance=delta.distance())
4028 def __init__(self, bearing, distance, origin=None):
4029 self.distance = distance
4030 self.bearing = bearing
4032 self.origin = cartesian(game.quadrant, game.sector)
4034 self.origin = origin
4035 # The bearing() code we inherited from FORTRAN is actually computing
4036 # clockface directions!
4037 if self.bearing < 0.0:
4038 self.bearing += 12.0
4039 self.angle = ((15.0 - self.bearing) * 0.5235988)
4040 self.increment = Coord(-math.sin(self.angle), math.cos(self.angle))
4041 bigger = max(abs(self.increment.i), abs(self.increment.j))
4042 self.increment /= bigger
4043 self.moves = int(round(10*self.distance*bigger))
4045 self.final = (self.location + self.moves*self.increment).roundtogrid()
4046 self.location = self.origin
4047 self.nextlocation = None
4049 self.location = self.origin
4052 return self.location.roundtogrid() == self.final
4054 "Next step on course."
4056 self.nextlocation = self.location + self.increment
4057 samequad = (self.location.quadrant() == self.nextlocation.quadrant())
4058 self.location = self.nextlocation
4061 return self.location.quadrant()
4063 return self.location.sector()
4065 return self.distance*(w**3)*(game.shldup+1)
4067 return 10.0*self.distance/w**2
4070 "Move under impulse power."
4072 if damaged(DIMPULS):
4075 prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
4077 if game.energy > 30.0:
4079 icourse = getcourse(isprobe=False)
4082 power = 20.0 + 100.0*icourse.distance
4085 if power >= game.energy:
4086 # Insufficient power for trip
4088 prout(_("First Officer Spock- \"Captain, the impulse engines"))
4089 prout(_("require 20.0 units to engage, plus 100.0 units per"))
4090 if game.energy > 30:
4091 proutn(_("quadrant. We can go, therefore, a maximum of %d") %
4092 int(0.01 * (game.energy-20.0)-0.05))
4093 prout(_(" quadrants.\""))
4095 prout(_("quadrant. They are, therefore, useless.\""))
4098 # Make sure enough time is left for the trip
4099 game.optime = icourse.distance/0.095
4100 if game.optime >= game.state.remtime:
4101 prout(_("First Officer Spock- \"Captain, our speed under impulse"))
4102 prout(_("power is only 0.95 sectors per stardate. Are you sure"))
4103 proutn(_("we dare spend the time?\" "))
4106 # Activate impulse engines and pay the cost
4107 imove(icourse, noattack=False)
4111 power = 20.0 + 100.0*icourse.distance
4112 game.energy -= power
4113 game.optime = icourse.distance/0.095
4114 if game.energy <= 0:
4118 def warp(wcourse, involuntary):
4119 "ove under warp drive."
4120 blooey = False; twarp = False
4121 if not involuntary: # Not WARPX entry
4126 prout(_("Engineer Scott- \"The warp engines can not be used while cloaked, Sir.\""))
4128 if game.damage[DWARPEN] > 10.0:
4131 prout(_("Engineer Scott- \"The warp engines are damaged, Sir.\""))
4133 if damaged(DWARPEN) and game.warpfac > 4.0:
4136 prout(_("Engineer Scott- \"Sorry, Captain. Until this damage"))
4137 prout(_(" is repaired, I can only give you warp 4.\""))
4139 # Read in course and distance
4142 wcourse = getcourse(isprobe=False)
4145 # Make sure starship has enough energy for the trip
4146 # Note: this formula is slightly different from the C version,
4147 # and lets you skate a bit closer to the edge.
4148 if wcourse.power(game.warpfac) >= game.energy:
4149 # Insufficient power for trip
4152 prout(_("Engineering to bridge--"))
4153 if not game.shldup or 0.5*wcourse.power(game.warpfac) > game.energy:
4154 iwarp = (game.energy/(wcourse.distance+0.05)) ** 0.333333333
4156 prout(_("We can't do it, Captain. We don't have enough energy."))
4158 proutn(_("We don't have enough energy, but we could do it at warp %d") % iwarp)
4161 prout(_("if you'll lower the shields."))
4165 prout(_("We haven't the energy to go that far with the shields up."))
4167 # Make sure enough time is left for the trip
4168 game.optime = wcourse.time(game.warpfac)
4169 if game.optime >= 0.8*game.state.remtime:
4171 prout(_("First Officer Spock- \"Captain, I compute that such"))
4172 proutn(_(" a trip would require approximately %2.0f") %
4173 (100.0*game.optime/game.state.remtime))
4174 prout(_(" percent of our"))
4175 proutn(_(" remaining time. Are you sure this is wise?\" "))
4181 if game.warpfac > 6.0:
4182 # Decide if engine damage will occur
4183 # ESR: Seems wrong. Probability of damage goes *down* with distance?
4184 prob = wcourse.distance*(6.0-game.warpfac)**2/66.666666666
4185 if prob > randreal():
4187 wcourse.distance = randreal(wcourse.distance)
4188 # Decide if time warp will occur
4189 if 0.5*wcourse.distance*math.pow(7.0,game.warpfac-10.0) > randreal():
4191 if game.idebug and game.warpfac==10 and not twarp:
4193 proutn("=== Force time warp? ")
4197 # If time warp or engine damage, check path
4198 # If it is obstructed, don't do warp or damage
4199 look = wcourse.moves
4203 w = wcourse.sector()
4204 if not w.valid_sector():
4206 if game.quad[w.i][w.j] != '.':
4210 # Activate Warp Engines and pay the cost
4211 imove(wcourse, noattack=False)
4214 game.energy -= wcourse.power(game.warpfac)
4215 if game.energy <= 0:
4217 game.optime = wcourse.time(game.warpfac)
4221 game.damage[DWARPEN] = game.damfac * randreal(1.0, 4.0)
4223 prout(_("Engineering to bridge--"))
4224 prout(_(" Scott here. The warp engines are damaged."))
4225 prout(_(" We'll have to reduce speed to warp 4."))
4230 "Change the warp factor."
4232 key=scanner.nexttok()
4236 proutn(_("Warp factor- "))
4240 if game.damage[DWARPEN] > 10.0:
4241 prout(_("Warp engines inoperative."))
4243 if damaged(DWARPEN) and scanner.real > 4.0:
4244 prout(_("Engineer Scott- \"I'm doing my best, Captain,"))
4245 prout(_(" but right now we can only go warp 4.\""))
4247 if scanner.real > 10.0:
4248 prout(_("Helmsman Sulu- \"Our top speed is warp 10, Captain.\""))
4250 if scanner.real < 1.0:
4251 prout(_("Helmsman Sulu- \"We can't go below warp 1, Captain.\""))
4253 oldfac = game.warpfac
4254 game.warpfac = scanner.real
4255 if game.warpfac <= oldfac or game.warpfac <= 6.0:
4256 prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\"") %
4259 if game.warpfac < 8.00:
4260 prout(_("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\""))
4262 if game.warpfac == 10.0:
4263 prout(_("Engineer Scott- \"Aye, Captain, we'll try it.\""))
4265 prout(_("Engineer Scott- \"Aye, Captain, but our engines may not take it.\""))
4269 "Cope with being tossed out of quadrant by supernova or yanked by beam."
4271 # is captain on planet?
4273 if damaged(DTRANSP):
4276 prout(_("Scotty rushes to the transporter controls."))
4278 prout(_("But with the shields up it's hopeless."))
4280 prouts(_("His desperate attempt to rescue you . . ."))
4285 prout(_("SUCCEEDS!"))
4288 proutn(_("The crystals mined were "))
4296 # Check to see if captain in shuttle craft
4301 # Inform captain of attempt to reach safety
4305 prouts(_("***RED ALERT! RED ALERT!"))
4307 proutn(_("The %s has stopped in a quadrant containing") % crmshp())
4308 prouts(_(" a supernova."))
4310 prout(_("***Emergency automatic override attempts to hurl ")+crmshp())
4311 prout(_("safely out of quadrant."))
4312 if not damaged(DRADIO):
4313 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
4314 # Try to use warp engines
4315 if damaged(DWARPEN):
4317 prout(_("Warp engines damaged."))
4320 game.warpfac = randreal(6.0, 8.0)
4321 prout(_("Warp factor set to %d") % int(game.warpfac))
4322 power = 0.75*game.energy
4323 dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1))
4324 dist = max(dist, randreal(math.sqrt(2)))
4325 bugout = course(bearing=randreal(12), distance=dist) # How dumb!
4326 game.optime = bugout.time(game.warpfac)
4328 game.inorbit = False
4329 warp(bugout, involuntary=True)
4331 # This is bad news, we didn't leave quadrant.
4335 prout(_("Insufficient energy to leave quadrant."))
4338 # Repeat if another snova
4339 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
4342 finish(FWON) # Snova killed remaining enemy.
4345 "Let's do the time warp again."
4346 prout(_("***TIME WARP ENTERED."))
4347 if game.state.snap and withprob(0.5):
4349 prout(_("You are traveling backwards in time %d stardates.") %
4350 int(game.state.date-game.snapsht.date))
4351 game.state = game.snapsht
4352 game.state.snap = False
4353 if len(game.state.kcmdr):
4354 schedule(FTBEAM, expran(game.intime/len(game.state.kcmdr)))
4355 schedule(FBATTAK, expran(0.3*game.intime))
4356 schedule(FSNOVA, expran(0.5*game.intime))
4357 # next snapshot will be sooner
4358 schedule(FSNAP, expran(0.25*game.state.remtime))
4360 if game.state.nscrem:
4361 schedule(FSCMOVE, 0.2777)
4365 game.battle.invalidate()
4366 # Make sure Galileo is consistant -- Snapshot may have been taken
4367 # when on planet, which would give us two Galileos!
4369 for l in range(game.inplan):
4370 if game.state.planets[l].known == "shuttle_down":
4372 if game.iscraft == "onship" and game.ship=='E':
4373 prout(_("Chekov- \"Security reports the Galileo has disappeared, Sir!"))
4374 game.iscraft = "offship"
4375 # Likewise, if in the original time the Galileo was abandoned, but
4376 # was on ship earlier, it would have vanished -- let's restore it.
4377 if game.iscraft == "offship" and not gotit and game.damage[DSHUTTL] >= 0.0:
4378 prout(_("Chekov- \"Security reports the Galileo has reappeared in the dock!\""))
4379 game.iscraft = "onship"
4380 # There used to be code to do the actual reconstrction here,
4381 # but the starchart is now part of the snapshotted galaxy state.
4382 prout(_("Spock has reconstructed a correct star chart from memory"))
4384 # Go forward in time
4385 game.optime = expran(0.5*game.intime)
4386 prout(_("You are traveling forward in time %d stardates.") % int(game.optime))
4387 # cheat to make sure no tractor beams occur during time warp
4388 postpone(FTBEAM, game.optime)
4389 game.damage[DRADIO] += game.optime
4391 events() # Stas Sergeev added this -- do pending events
4394 "Launch deep-space probe."
4395 # New code to launch a deep space probe
4396 if game.nprobes == 0:
4399 if game.ship == 'E':
4400 prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\""))
4402 prout(_("Ye Faerie Queene has no deep space probes."))
4407 prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\""))
4409 if is_scheduled(FDSPROB):
4412 if damaged(DRADIO) and game.condition != "docked":
4413 prout(_("Spock- \"Records show the previous probe has not yet"))
4414 prout(_(" reached its destination.\""))
4416 prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""))
4418 key = scanner.nexttok()
4420 if game.nprobes == 1:
4421 prout(_("1 probe left."))
4423 prout(_("%d probes left") % game.nprobes)
4424 proutn(_("Are you sure you want to fire a probe? "))
4427 game.isarmed = False
4428 if key == "IHALPHA" and scanner.token == "armed":
4430 key = scanner.nexttok()
4431 elif key == "IHEOL":
4432 proutn(_("Arm NOVAMAX warhead? "))
4434 elif key == "IHREAL": # first element of course
4435 scanner.push(scanner.token)
4437 game.probe = getcourse(isprobe=True)
4441 schedule(FDSPROB, 0.01) # Time to move one sector
4442 prout(_("Ensign Chekov- \"The deep space probe is launched, Captain.\""))
4447 "Yell for help from nearest starbase."
4448 # There's more than one way to move in this game!
4450 # Test for conditions which prevent calling for help
4451 if game.condition == "docked":
4452 prout(_("Lt. Uhura- \"But Captain, we're already docked.\""))
4455 prout(_("Subspace radio damaged."))
4457 if not game.state.baseq:
4458 prout(_("Lt. Uhura- \"Captain, I'm not getting any response from Starbase.\""))
4461 prout(_("You must be aboard the %s.") % crmshp())
4463 # OK -- call for help from nearest starbase
4466 # There's one in this quadrant
4467 ddist = (game.base - game.sector).distance()
4469 ibq = None # Force base-quadrant game to persist past loop
4471 for ibq in game.state.baseq:
4472 xdist = QUADSIZE * (ibq - game.quadrant).distance()
4476 prout(_("No starbases remain. You are alone in a hostile galaxy."))
4478 # Since starbase not in quadrant, set up new quadrant
4481 # dematerialize starship
4482 game.quad[game.sector.i][game.sector.j]='.'
4483 proutn(_("Starbase in Quadrant %s responds--%s dematerializes") \
4484 % (game.quadrant, crmshp()))
4485 game.sector.invalidate()
4486 for m in range(1, 5+1):
4487 w = game.base.scatter()
4488 if w.valid_sector() and game.quad[w.i][w.j]=='.':
4489 # found one -- finish up
4492 if game.sector is None:
4493 prout(_("You have been lost in space..."))
4494 finish(FMATERIALIZE)
4496 # Give starbase three chances to rematerialize starship
4497 probf = math.pow((1.0 - math.pow(0.98,ddist)), 0.33333333)
4498 for m in range(1, 3+1):
4499 if m == 1: proutn(_("1st"))
4500 elif m == 2: proutn(_("2nd"))
4501 elif m == 3: proutn(_("3rd"))
4502 proutn(_(" attempt to re-materialize ") + crmshp())
4503 game.quad[game.sector.i][game.sector.j]=('-','o','O')[m-1]
4506 if randreal() > probf:
4510 curses.delay_output(500)
4512 game.quad[game.sector.i][game.sector.j]='?'
4515 setwnd(message_window)
4516 finish(FMATERIALIZE)
4518 game.quad[game.sector.i][game.sector.j]=game.ship
4520 prout(_("succeeds."))
4524 prout(_("Lt. Uhura- \"Captain, we made it!\""))
4529 if game.condition=="docked":
4531 prout(_("You cannot abandon Ye Faerie Queene."))
4534 # Must take shuttle craft to exit
4535 if game.damage[DSHUTTL]==-1:
4536 prout(_("Ye Faerie Queene has no shuttle craft."))
4538 if game.damage[DSHUTTL]<0:
4539 prout(_("Shuttle craft now serving Big Macs."))
4541 if game.damage[DSHUTTL]>0:
4542 prout(_("Shuttle craft damaged."))
4545 prout(_("You must be aboard the ship."))
4547 if game.iscraft != "onship":
4548 prout(_("Shuttle craft not currently available."))
4550 # Emit abandon ship messages
4552 prouts(_("***ABANDON SHIP! ABANDON SHIP!"))
4554 prouts(_("***ALL HANDS ABANDON SHIP!"))
4556 prout(_("Captain and crew escape in shuttle craft."))
4557 if not game.state.baseq:
4558 # Oops! no place to go...
4561 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
4563 if not (game.options & OPTION_WORLDS) and not damaged(DTRANSP):
4564 prout(_("Remainder of ship's complement beam down"))
4565 prout(_("to nearest habitable planet."))
4566 elif q.planet != None and not damaged(DTRANSP):
4567 prout(_("Remainder of ship's complement beam down to %s.") %
4570 prout(_("Entire crew of %d left to die in outer space.") %
4572 game.casual += game.state.crew
4573 game.abandoned += game.state.crew
4574 # If at least one base left, give 'em the Faerie Queene
4576 game.icrystl = False # crystals are lost
4577 game.nprobes = 0 # No probes
4578 prout(_("You are captured by Klingons and released to"))
4579 prout(_("the Federation in a prisoner-of-war exchange."))
4580 nb = randrange(len(game.state.baseq))
4581 # Set up quadrant and position FQ adjacient to base
4582 if not game.quadrant == game.state.baseq[nb]:
4583 game.quadrant = game.state.baseq[nb]
4584 game.sector.i = game.sector.j = 5
4587 # position next to base by trial and error
4588 game.quad[game.sector.i][game.sector.j] = '.'
4590 for l in range(QUADSIZE):
4591 game.sector = game.base.scatter()
4592 if game.sector.valid_sector() and \
4593 game.quad[game.sector.i][game.sector.j] == '.':
4596 break # found a spot
4597 game.sector.i=QUADSIZE/2
4598 game.sector.j=QUADSIZE/2
4600 # Get new commission
4601 game.quad[game.sector.i][game.sector.j] = game.ship = 'F'
4602 game.state.crew = FULLCREW
4603 prout(_("Starfleet puts you in command of another ship,"))
4604 prout(_("the Faerie Queene, which is antiquated but,"))
4605 prout(_("still useable."))
4607 prout(_("The dilithium crystals have been moved."))
4609 game.iscraft = "offship" # Galileo disappears
4611 game.condition="docked"
4612 for l in range(NDEVICES):
4613 game.damage[l] = 0.0
4614 game.damage[DSHUTTL] = -1
4615 game.energy = game.inenrg = 3000.0
4616 game.shield = game.inshld = 1250.0
4617 game.torps = game.intorps = 6
4618 game.lsupres=game.inlsr=3.0
4621 game.brigfree = game.brigcapacity = 300
4624 # Code from planets.c begins here.
4627 "Abort a lengthy operation if an event interrupts it."
4630 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.justin:
4635 "Report on (uninhabited) planets in the galaxy."
4639 prout(_("Spock- \"Planet report follows, Captain.\""))
4641 for i in range(game.inplan):
4642 if game.state.planets[i].pclass == "destroyed":
4644 if (game.state.planets[i].known != "unknown" \
4645 and not game.state.planets[i].inhabited) \
4648 if game.idebug and game.state.planets[i].known=="unknown":
4649 proutn("(Unknown) ")
4650 proutn(_("Quadrant %s") % game.state.planets[i].quadrant)
4651 proutn(_(" class "))
4652 proutn(game.state.planets[i].pclass)
4654 if game.state.planets[i].crystals != "present":
4656 prout(_("dilithium crystals present."))
4657 if game.state.planets[i].known=="shuttle_down":
4658 prout(_(" Shuttle Craft Galileo on surface."))
4660 prout(_("No information available."))
4663 "Enter standard orbit."
4667 prout(_("Already in standard orbit."))
4669 if damaged(DWARPEN) and damaged(DIMPULS):
4670 prout(_("Both warp and impulse engines damaged."))
4672 if game.plnet is None:
4673 prout("There is no planet in this sector.")
4675 if abs(game.sector.i-game.plnet.i)>1 or abs(game.sector.j-game.plnet.j)>1:
4676 prout(crmshp() + _(" not adjacent to planet."))
4679 game.optime = randreal(0.02, 0.05)
4680 prout(_("Helmsman Sulu- \"Entering standard orbit, Sir.\""))
4684 game.height = randreal(1400, 8600)
4685 prout(_("Sulu- \"Entered orbit at altitude %.2f kilometers.\"") % game.height)
4690 "Examine planets in this quadrant."
4691 if damaged(DSRSENS):
4692 if game.options & OPTION_TTY:
4693 prout(_("Short range sensors damaged."))
4695 if game.iplnet is None:
4696 if game.options & OPTION_TTY:
4697 prout(_("Spock- \"No planet in this quadrant, Captain.\""))
4699 if game.iplnet.known == "unknown":
4700 prout(_("Spock- \"Sensor scan for Quadrant %s-") % game.quadrant)
4702 prout(_(" Planet at Sector %s is of class %s.") %
4703 (game.plnet, game.iplnet.pclass))
4704 if game.iplnet.known=="shuttle_down":
4705 prout(_(" Sensors show Galileo still on surface."))
4706 proutn(_(" Readings indicate"))
4707 if game.iplnet.crystals != "present":
4709 prout(_(" dilithium crystals present.\""))
4710 if game.iplnet.known == "unknown":
4711 game.iplnet.known = "known"
4712 elif game.iplnet.inhabited:
4713 prout(_("Spock- \"The inhabited planet %s ") % game.iplnet.name)
4714 prout(_(" is located at Sector %s, Captain.\"") % game.plnet)
4717 "Use the transporter."
4721 if damaged(DTRANSP):
4722 prout(_("Transporter damaged."))
4723 if not damaged(DSHUTTL) and (game.iplnet.known=="shuttle_down" or game.iscraft == "onship"):
4725 proutn(_("Spock- \"May I suggest the shuttle craft, Sir?\" "))
4729 if not game.inorbit:
4730 prout(crmshp() + _(" not in standard orbit."))
4733 prout(_("Impossible to transport through shields."))
4735 if game.iplnet.known=="unknown":
4736 prout(_("Spock- \"Captain, we have no information on this planet"))
4737 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4738 prout(_(" you may not go down.\""))
4740 if not game.landed and game.iplnet.crystals=="absent":
4741 prout(_("Spock- \"Captain, I fail to see the logic in"))
4742 prout(_(" exploring a planet with no dilithium crystals."))
4743 proutn(_(" Are you sure this is wise?\" "))
4747 if not (game.options & OPTION_PLAIN):
4748 nrgneed = 50 * game.skill + game.height / 100.0
4749 if nrgneed > game.energy:
4750 prout(_("Engineering to bridge--"))
4751 prout(_(" Captain, we don't have enough energy for transportation."))
4753 if not game.landed and nrgneed * 2 > game.energy:
4754 prout(_("Engineering to bridge--"))
4755 prout(_(" Captain, we have enough energy only to transport you down to"))
4756 prout(_(" the planet, but there wouldn't be an energy for the trip back."))
4757 if game.iplnet.known == "shuttle_down":
4758 prout(_(" Although the Galileo shuttle craft may still be on a surface."))
4759 proutn(_(" Are you sure this is wise?\" "))
4764 # Coming from planet
4765 if game.iplnet.known=="shuttle_down":
4766 proutn(_("Spock- \"Wouldn't you rather take the Galileo?\" "))
4770 prout(_("Your crew hides the Galileo to prevent capture by aliens."))
4771 prout(_("Landing party assembled, ready to beam up."))
4773 prout(_("Kirk whips out communicator..."))
4774 prouts(_("BEEP BEEP BEEP"))
4776 prout(_("\"Kirk to enterprise- Lock on coordinates...energize.\""))
4779 prout(_("Scotty- \"Transporter room ready, Sir.\""))
4781 prout(_("Kirk and landing party prepare to beam down to planet surface."))
4783 prout(_("Kirk- \"Energize.\""))
4786 prouts("WWHOOOIIIIIRRRRREEEE.E.E. . . . . . .")
4788 if not withprob(0.98):
4789 prouts("BOOOIIIOOOIIOOOOIIIOIING . . .")
4791 prout(_("Scotty- \"Oh my God! I've lost them.\""))
4794 prouts(". . . . . . .E.E.EEEERRRRRIIIIIOOOHWW")
4795 game.landed = not game.landed
4796 game.energy -= nrgneed
4798 prout(_("Transport complete."))
4799 if game.landed and game.iplnet.known=="shuttle_down":
4800 prout(_("The shuttle craft Galileo is here!"))
4801 if not game.landed and game.imine:
4808 "Strip-mine a world for dilithium."
4812 prout(_("Mining party not on planet."))
4814 if game.iplnet.crystals == "mined":
4815 prout(_("This planet has already been strip-mined for dilithium."))
4817 elif game.iplnet.crystals == "absent":
4818 prout(_("No dilithium crystals on this planet."))
4821 prout(_("You've already mined enough crystals for this trip."))
4823 if game.icrystl and game.cryprob == 0.05:
4824 prout(_("With all those fresh crystals aboard the ") + crmshp())
4825 prout(_("there's no reason to mine more at this time."))
4827 game.optime = randreal(0.1, 0.3)*(ord(game.iplnet.pclass)-ord("L"))
4830 prout(_("Mining operation complete."))
4831 game.iplnet.crystals = "mined"
4832 game.imine = game.ididit = True
4835 "Use dilithium crystals."
4839 if not game.icrystl:
4840 prout(_("No dilithium crystals available."))
4842 if game.energy >= 1000:
4843 prout(_("Spock- \"Captain, Starfleet Regulations prohibit such an operation"))
4844 prout(_(" except when Condition Yellow exists."))
4846 prout(_("Spock- \"Captain, I must warn you that loading"))
4847 prout(_(" raw dilithium crystals into the ship's power"))
4848 prout(_(" system may risk a severe explosion."))
4849 proutn(_(" Are you sure this is wise?\" "))
4854 prout(_("Engineering Officer Scott- \"(GULP) Aye Sir."))
4855 prout(_(" Mr. Spock and I will try it.\""))
4857 prout(_("Spock- \"Crystals in place, Sir."))
4858 prout(_(" Ready to activate circuit.\""))
4860 prouts(_("Scotty- \"Keep your fingers crossed, Sir!\""))
4862 if withprob(game.cryprob):
4863 prouts(_(" \"Activating now! - - No good! It's***"))
4865 prouts(_("***RED ALERT! RED A*L********************************"))
4868 prouts(_("****************** KA-BOOM!!!! *******************"))
4872 game.energy += randreal(5000.0, 5500.0)
4873 prouts(_(" \"Activating now! - - "))
4874 prout(_("The instruments"))
4875 prout(_(" are going crazy, but I think it's"))
4876 prout(_(" going to work!! Congratulations, Sir!\""))
4881 "Use shuttlecraft for planetary jaunt."
4884 if damaged(DSHUTTL):
4885 if game.damage[DSHUTTL] == -1.0:
4886 if game.inorbit and game.iplnet.known == "shuttle_down":
4887 prout(_("Ye Faerie Queene has no shuttle craft bay to dock it at."))
4889 prout(_("Ye Faerie Queene had no shuttle craft."))
4890 elif game.damage[DSHUTTL] > 0:
4891 prout(_("The Galileo is damaged."))
4892 else: # game.damage[DSHUTTL] < 0
4893 prout(_("Shuttle craft is now serving Big Macs."))
4895 if not game.inorbit:
4896 prout(crmshp() + _(" not in standard orbit."))
4898 if (game.iplnet.known != "shuttle_down") and game.iscraft != "onship":
4899 prout(_("Shuttle craft not currently available."))
4901 if not game.landed and game.iplnet.known=="shuttle_down":
4902 prout(_("You will have to beam down to retrieve the shuttle craft."))
4904 if game.shldup or game.condition == "docked":
4905 prout(_("Shuttle craft cannot pass through shields."))
4907 if game.iplnet.known=="unknown":
4908 prout(_("Spock- \"Captain, we have no information on this planet"))
4909 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4910 prout(_(" you may not fly down.\""))
4912 game.optime = 3.0e-5*game.height
4913 if game.optime >= 0.8*game.state.remtime:
4914 prout(_("First Officer Spock- \"Captain, I compute that such"))
4915 proutn(_(" a maneuver would require approximately %2d%% of our") % \
4916 int(100*game.optime/game.state.remtime))
4917 prout(_("remaining time."))
4918 proutn(_("Are you sure this is wise?\" "))
4924 if game.iscraft == "onship":
4926 if not damaged(DTRANSP):
4927 proutn(_("Spock- \"Would you rather use the transporter?\" "))
4931 proutn(_("Shuttle crew"))
4933 proutn(_("Rescue party"))
4934 prout(_(" boards Galileo and swoops toward planet surface."))
4935 game.iscraft = "offship"
4939 game.iplnet.known="shuttle_down"
4940 prout(_("Trip complete."))
4943 # Ready to go back to ship
4944 prout(_("You and your mining party board the"))
4945 prout(_("shuttle craft for the trip back to the Enterprise."))
4947 prouts(_("The short hop begins . . ."))
4949 game.iplnet.known="known"
4955 game.iscraft = "onship"
4961 prout(_("Trip complete."))
4964 # Kirk on ship and so is Galileo
4965 prout(_("Mining party assembles in the hangar deck,"))
4966 prout(_("ready to board the shuttle craft \"Galileo\"."))
4968 prouts(_("The hangar doors open; the trip begins."))
4971 game.iscraft = "offship"
4974 game.iplnet.known = "shuttle_down"
4977 prout(_("Trip complete."))
4981 "Use the big zapper."
4985 if game.ship != 'E':
4986 prout(_("Ye Faerie Queene has no death ray."))
4988 if len(game.enemies)==0:
4989 prout(_("Sulu- \"But Sir, there are no enemies in this quadrant.\""))
4992 prout(_("Death Ray is damaged."))
4994 prout(_("Spock- \"Captain, the 'Experimental Death Ray'"))
4995 prout(_(" is highly unpredictible. Considering the alternatives,"))
4996 proutn(_(" are you sure this is wise?\" "))
4999 prout(_("Spock- \"Acknowledged.\""))
5002 prouts(_("WHOOEE ... WHOOEE ... WHOOEE ... WHOOEE"))
5004 prout(_("Crew scrambles in emergency preparation."))
5005 prout(_("Spock and Scotty ready the death ray and"))
5006 prout(_("prepare to channel all ship's power to the device."))
5008 prout(_("Spock- \"Preparations complete, sir.\""))
5009 prout(_("Kirk- \"Engage!\""))
5011 prouts(_("WHIRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"))
5014 if game.options & OPTION_PLAIN:
5018 prouts(_("Sulu- \"Captain! It's working!\""))
5020 while len(game.enemies) > 0:
5021 deadkl(game.enemies[1].location, game.quad[game.enemies[1].location.i][game.enemies[1].location.j],game.enemies[1].location)
5022 prout(_("Ensign Chekov- \"Congratulations, Captain!\""))
5023 if game.unwon() == 0:
5025 if (game.options & OPTION_PLAIN) == 0:
5026 prout(_("Spock- \"Captain, I believe the `Experimental Death Ray'"))
5028 prout(_(" is still operational.\""))
5030 prout(_(" has been rendered nonfunctional.\""))
5031 game.damage[DDRAY] = 39.95
5033 r = randreal() # Pick failure method
5035 prouts(_("Sulu- \"Captain! It's working!\""))
5037 prouts(_("***RED ALERT! RED ALERT!"))
5039 prout(_("***MATTER-ANTIMATTER IMPLOSION IMMINENT!"))
5041 prouts(_("***RED ALERT! RED A*L********************************"))
5044 prouts(_("****************** KA-BOOM!!!! *******************"))
5049 prouts(_("Sulu- \"Captain! Yagabandaghangrapl, brachriigringlanbla!\""))
5051 prout(_("Lt. Uhura- \"Graaeek! Graaeek!\""))
5053 prout(_("Spock- \"Fascinating! . . . All humans aboard"))
5054 prout(_(" have apparently been transformed into strange mutations."))
5055 prout(_(" Vulcans do not seem to be affected."))
5057 prout(_("Kirk- \"Raauch! Raauch!\""))
5061 prouts(_("Sulu- \"Captain! It's --WHAT?!?!\""))
5063 proutn(_("Spock- \"I believe the word is"))
5064 prouts(_(" *ASTONISHING*"))
5065 prout(_(" Mr. Sulu."))
5066 for i in range(QUADSIZE):
5067 for j in range(QUADSIZE):
5068 if game.quad[i][j] == '.':
5069 game.quad[i][j] = '?'
5070 prout(_(" Captain, our quadrant is now infested with"))
5071 prouts(_(" - - - - - - *THINGS*."))
5073 prout(_(" I have no logical explanation.\""))
5075 prouts(_("Sulu- \"Captain! The Death Ray is creating tribbles!\""))
5077 prout(_("Scotty- \"There are so many tribbles down here"))
5078 prout(_(" in Engineering, we can't move for 'em, Captain.\""))
5082 # Code from reports.c begins here
5084 def attackreport(curt):
5085 "eport status of bases under attack."
5087 if is_scheduled(FCDBAS):
5088 prout(_("Starbase in Quadrant %s is currently under Commander attack.") % game.battle)
5089 prout(_("It can hold out until Stardate %d.") % int(scheduled(FCDBAS)))
5090 elif game.isatb == 1:
5091 prout(_("Starbase in Quadrant %s is under Super-commander attack.") % game.state.kscmdr)
5092 prout(_("It can hold out until Stardate %d.") % int(scheduled(FSCDBAS)))
5094 prout(_("No Starbase is currently under attack."))
5096 if is_scheduled(FCDBAS):
5097 proutn(_("Base in %s attacked by C. Alive until %.1f") % (game.battle, scheduled(FCDBAS)))
5099 proutn(_("Base in %s attacked by S. Alive until %.1f") % (game.state.kscmdr, scheduled(FSCDBAS)))
5103 # report on general game status
5105 s1 = (game.thawed and _("thawed ")) or ""
5106 s2 = {1:"short", 2:"medium", 4:"long"}[game.length]
5107 s3 = (None, _("novice"), _("fair"),
5108 _("good"), _("expert"), _("emeritus"))[game.skill]
5109 prout(_("You %s a %s%s %s game.") % ((_("were playing"), _("are playing"))[game.alldone], s1, s2, s3))
5110 if game.skill>SKILL_GOOD and game.thawed and not game.alldone:
5111 prout(_("No plaque is allowed."))
5113 prout(_("This is tournament game %d.") % game.tourn)
5114 prout(_("Your secret password is \"%s\"") % game.passwd)
5115 proutn(_("%d of %d Klingons have been killed") % (((game.inkling + game.incom + game.inscom) - game.unwon()),
5116 (game.inkling + game.incom + game.inscom)))
5117 if game.incom - len(game.state.kcmdr):
5118 prout(_(", including %d Commander%s.") % (game.incom - len(game.state.kcmdr), (_("s"), "")[(game.incom - len(game.state.kcmdr))==1]))
5119 elif game.inkling - game.remkl() + (game.inscom - game.state.nscrem) > 0:
5120 prout(_(", but no Commanders."))
5123 if game.skill > SKILL_FAIR:
5124 prout(_("The Super Commander has %sbeen destroyed.") % ("", _("not "))[game.state.nscrem])
5125 if len(game.state.baseq) != game.inbase:
5127 if game.inbase-len(game.state.baseq)==1:
5128 proutn(_("has been 1 base"))
5130 proutn(_("have been %d bases") % (game.inbase-len(game.state.baseq)))
5131 prout(_(" destroyed, %d remaining.") % len(game.state.baseq))
5133 prout(_("There are %d bases.") % game.inbase)
5134 if communicating() or game.iseenit:
5135 # Don't report this if not seen and
5136 # either the radio is dead or not at base!
5140 prout(_("%d casualt%s suffered so far.") % (game.casual, ("y", "ies")[game.casual!=1]))
5141 if game.brigcapacity != game.brigfree:
5142 embriggened = brigcapacity-brigfree
5143 if embriggened == 1:
5144 prout(_("1 Klingon in brig"))
5146 prout(_("%d Klingons in brig.") % embriggened)
5147 if game.kcaptured == 0:
5149 elif game.kcaptured == 1:
5150 prout(_("1 captured Klingon turned in to Starfleet."))
5152 prout(_("%d captured Klingons turned in to Star Fleet.") % game.kcaptured)
5154 prout(_("There were %d call%s for help.") % (game.nhelp, ("" , _("s"))[game.nhelp!=1]))
5155 if game.ship == 'E':
5156 proutn(_("You have "))
5158 proutn("%d" % (game.nprobes))
5161 proutn(_(" deep space probe"))
5165 if communicating() and is_scheduled(FDSPROB):
5167 proutn(_("An armed deep space probe is in "))
5169 proutn(_("A deep space probe is in "))
5170 prout("Quadrant %s." % game.probe.quadrant())
5172 if game.cryprob <= .05:
5173 prout(_("Dilithium crystals aboard ship... not yet used."))
5177 while game.cryprob > ai:
5180 prout(_("Dilithium crystals have been used %d time%s.") % \
5181 (i, (_("s"), "")[i==1]))
5185 "Long-range sensor scan."
5186 if damaged(DLRSENS):
5187 # Now allow base's sensors if docked
5188 if game.condition != "docked":
5190 prout(_("LONG-RANGE SENSORS DAMAGED."))
5193 prout(_("Starbase's long-range scan"))
5195 prout(_("Long-range scan"))
5196 for x in range(game.quadrant.i-1, game.quadrant.i+2):
5199 for y in range(game.quadrant.j-1, game.quadrant.j+2):
5200 if not Coord(x, y).valid_quadrant():
5204 if not damaged(DRADIO):
5205 game.state.galaxy[x][y].charted = True
5206 game.state.chart[x][y].klingons = game.state.galaxy[x][y].klingons
5207 game.state.chart[x][y].starbase = game.state.galaxy[x][y].starbase
5208 game.state.chart[x][y].stars = game.state.galaxy[x][y].stars
5209 if not silent and game.state.galaxy[x][y].supernova:
5212 cn = " %3d" % (game.state.chart[x][y].klingons*100 + game.state.chart[x][y].starbase * 10 + game.state.chart[x][y].stars)
5213 proutn(((3 - len(cn)) * '.') + cn)
5221 for i in range(NDEVICES):
5224 prout(_("\tDEVICE\t\t\t-REPAIR TIMES-"))
5225 prout(_("\t\t\tIN FLIGHT\t\tDOCKED"))
5227 prout(" %-26s\t%8.2f\t\t%8.2f" % (device[i],
5228 game.damage[i]+0.05,
5229 DOCKFAC*game.damage[i]+0.005))
5231 prout(_("All devices functional."))
5234 "Update the chart in the Enterprise's computer from galaxy data."
5235 game.lastchart = game.state.date
5236 for i in range(GALSIZE):
5237 for j in range(GALSIZE):
5238 if game.state.galaxy[i][j].charted:
5239 game.state.chart[i][j].klingons = game.state.galaxy[i][j].klingons
5240 game.state.chart[i][j].starbase = game.state.galaxy[i][j].starbase
5241 game.state.chart[i][j].stars = game.state.galaxy[i][j].stars
5244 "Display the star chart."
5246 if (game.options & OPTION_AUTOSCAN):
5250 if game.lastchart < game.state.date and game.condition == "docked":
5251 prout(_("Spock- \"I revised the Star Chart from the starbase's records.\""))
5253 prout(_(" STAR CHART FOR THE KNOWN GALAXY"))
5254 if game.state.date > game.lastchart:
5255 prout(_("(Last surveillance update %d stardates ago).") % ((int)(game.state.date-game.lastchart)))
5256 prout(" 1 2 3 4 5 6 7 8")
5257 for i in range(GALSIZE):
5258 proutn("%d |" % (i+1))
5259 for j in range(GALSIZE):
5260 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5264 if game.state.galaxy[i][j].supernova:
5266 elif not game.state.galaxy[i][j].charted and game.state.galaxy[i][j].starbase:
5268 elif game.state.galaxy[i][j].charted:
5269 show = "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars)
5273 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5281 def sectscan(goodScan, i, j):
5282 "Light up an individual dot in a sector."
5283 if goodScan or (abs(i-game.sector.i)<= 1 and abs(j-game.sector.j) <= 1):
5284 if game.quad[i][j] in ('E', 'F'):
5287 textcolor({"green":GREEN,
5291 "dead":BROWN}[game.condition])
5293 textcolor({'?':LIGHTMAGENTA,
5299 }.get(game.quad[i][j], DEFAULT))
5300 proutn("%c " % game.quad[i][j])
5306 "Emit status report lines"
5307 if not req or req == 1:
5308 prstat(_("Stardate"), _("%.1f, Time Left %.2f") \
5309 % (game.state.date, game.state.remtime))
5310 if not req or req == 2:
5311 if game.condition != "docked":
5313 prstat(_("Condition"), _("%s, %i DAMAGES") % \
5314 (game.condition.upper(), sum([x > 0 for x in game.damage])))
5316 prout(_(", CLOAKED"))
5317 if not req or req == 3:
5318 prstat(_("Position"), "%s , %s" % (game.quadrant, game.sector))
5319 if not req or req == 4:
5320 if damaged(DLIFSUP):
5321 if game.condition == "docked":
5322 s = _("DAMAGED, Base provides")
5324 s = _("DAMAGED, reserves=%4.2f") % game.lsupres
5327 prstat(_("Life Support"), s)
5328 if not req or req == 5:
5329 prstat(_("Warp Factor"), "%.1f" % game.warpfac)
5330 if not req or req == 6:
5332 if game.icrystl and (game.options & OPTION_SHOWME):
5333 extra = _(" (have crystals)")
5334 prstat(_("Energy"), "%.2f%s" % (game.energy, extra))
5335 if not req or req == 7:
5336 prstat(_("Torpedoes"), "%d" % (game.torps))
5337 if not req or req == 8:
5338 if damaged(DSHIELD):
5344 data = _(" %d%% %.1f units") \
5345 % (int((100.0*game.shield)/game.inshld + 0.5), game.shield)
5346 prstat(_("Shields"), s+data)
5347 if not req or req == 9:
5348 prstat(_("Klingons Left"), "%d" % game.unwon())
5349 if not req or req == 10:
5350 if game.options & OPTION_WORLDS:
5351 plnet = game.state.galaxy[game.quadrant.i][game.quadrant.j].planet
5352 if plnet and plnet.inhabited:
5353 prstat(_("Major system"), plnet.name)
5355 prout(_("Sector is uninhabited"))
5356 elif not req or req == 11:
5357 attackreport(not req)
5360 "Request specified status data, a historical relic from slow TTYs."
5361 requests = ("da","co","po","ls","wa","en","to","sh","kl","sy", "ti")
5362 while scanner.nexttok() == "IHEOL":
5363 proutn(_("Information desired? "))
5365 if scanner.token in requests:
5366 status(requests.index(scanner.token))
5368 prout(_("UNRECOGNIZED REQUEST. Legal requests are:"))
5369 prout((" date, condition, position, lsupport, warpfactor,"))
5370 prout((" energy, torpedoes, shields, klingons, system, time."))
5375 if damaged(DSRSENS):
5376 # Allow base's sensors if docked
5377 if game.condition != "docked":
5378 prout(_(" S.R. SENSORS DAMAGED!"))
5381 prout(_(" [Using Base's sensors]"))
5383 prout(_(" Short-range scan"))
5384 if goodScan and communicating():
5385 game.state.chart[game.quadrant.i][game.quadrant.j].klingons = game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons
5386 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase
5387 game.state.chart[game.quadrant.i][game.quadrant.j].stars = game.state.galaxy[game.quadrant.i][game.quadrant.j].stars
5388 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
5389 prout(" 1 2 3 4 5 6 7 8 9 10")
5390 if game.condition != "docked":
5392 for i in range(QUADSIZE):
5393 proutn("%2d " % (i+1))
5394 for j in range(QUADSIZE):
5395 sectscan(goodScan, i, j)
5399 "Use computer to get estimated time of arrival for a warp jump."
5400 w1 = Coord(); w2 = Coord()
5402 if damaged(DCOMPTR):
5403 prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR."))
5406 if scanner.nexttok() != "IHREAL":
5409 proutn(_("Destination quadrant and/or sector? "))
5410 if scanner.nexttok()!="IHREAL":
5413 w1.j = int(scanner.real-0.5)
5414 if scanner.nexttok() != "IHREAL":
5417 w1.i = int(scanner.real-0.5)
5418 if scanner.nexttok() == "IHREAL":
5419 w2.j = int(scanner.real-0.5)
5420 if scanner.nexttok() != "IHREAL":
5423 w2.i = int(scanner.real-0.5)
5425 if game.quadrant.j>w1.i:
5429 if game.quadrant.i>w1.j:
5433 if not w1.valid_quadrant() or not w2.valid_sector():
5436 dist = math.sqrt((w1.j-game.quadrant.j+(w2.j-game.sector.j)/(QUADSIZE*1.0))**2+
5437 (w1.i-game.quadrant.i+(w2.i-game.sector.i)/(QUADSIZE*1.0))**2)
5440 prout(_("Answer \"no\" if you don't know the value:"))
5443 proutn(_("Time or arrival date? "))
5444 if scanner.nexttok()=="IHREAL":
5445 ttime = scanner.real
5446 if ttime > game.state.date:
5447 ttime -= game.state.date # Actually a star date
5448 twarp=(math.floor(math.sqrt((10.0*dist)/ttime)*10.0)+1.0)/10.0
5449 if ttime <= 1e-10 or twarp > 10:
5450 prout(_("We'll never make it, sir."))
5457 proutn(_("Warp factor? "))
5458 if scanner.nexttok()== "IHREAL":
5460 twarp = scanner.real
5461 if twarp<1.0 or twarp > 10.0:
5465 prout(_("Captain, certainly you can give me one of these."))
5468 ttime = (10.0*dist)/twarp**2
5469 tpower = dist*twarp*twarp*twarp*(game.shldup+1)
5470 if tpower >= game.energy:
5471 prout(_("Insufficient energy, sir."))
5472 if not game.shldup or tpower > game.energy*2.0:
5475 proutn(_("New warp factor to try? "))
5476 if scanner.nexttok() == "IHREAL":
5478 twarp = scanner.real
5479 if twarp<1.0 or twarp > 10.0:
5487 prout(_("But if you lower your shields,"))
5488 proutn(_("remaining"))
5491 proutn(_("Remaining"))
5492 prout(_(" energy will be %.2f.") % (game.energy-tpower))
5494 prout(_("And we will arrive at stardate %.2f.") % (game.state.date+ttime))
5496 prout(_("Any warp speed is adequate."))
5498 prout(_("Minimum warp needed is %.2f,") % (twarp))
5499 prout(_("and we will arrive at stardate %.2f.") % (game.state.date+ttime))
5500 if game.state.remtime < ttime:
5501 prout(_("Unfortunately, the Federation will be destroyed by then."))
5503 prout(_("You'll be taking risks at that speed, Captain"))
5504 if (game.isatb==1 and game.state.kscmdr == w1 and \
5505 scheduled(FSCDBAS)< ttime+game.state.date) or \
5506 (scheduled(FCDBAS)<ttime+game.state.date and game.battle == w1):
5507 prout(_("The starbase there will be destroyed by then."))
5508 proutn(_("New warp factor to try? "))
5509 if scanner.nexttok() == "IHREAL":
5511 twarp = scanner.real
5512 if twarp<1.0 or twarp > 10.0:
5520 # Code from setup.c begins here
5523 "Issue a historically correct banner."
5525 prout(_("-SUPER- STAR TREK"))
5527 # From the FORTRAN original
5528 # prout(_("Latest update-21 Sept 78"))
5534 scanner.push("emsave.trk")
5535 key = scanner.nexttok()
5537 proutn(_("File name: "))
5538 key = scanner.nexttok()
5539 if key != "IHALPHA":
5542 if '.' not in scanner.token:
5543 scanner.token += ".trk"
5545 fp = open(scanner.token, "wb")
5547 prout(_("Can't freeze game as file %s") % scanner.token)
5549 pickle.dump(game, fp)
5554 "Retrieve saved game."
5557 key = scanner.nexttok()
5559 proutn(_("File name: "))
5560 key = scanner.nexttok()
5561 if key != "IHALPHA":
5564 if '.' not in scanner.token:
5565 scanner.token += ".trk"
5567 fp = open(scanner.token, "rb")
5569 prout(_("Can't thaw game in %s") % scanner.token)
5571 game = pickle.load(fp)
5576 # I used <http://www.memory-alpha.org> to find planets
5577 # with references in ST:TOS. Earth and the Alpha Centauri
5578 # Colony have been omitted.
5580 # Some planets marked Class G and P here will be displayed as class M
5581 # because of the way planets are generated. This is a known bug.
5584 _("Andoria (Fesoan)"), # several episodes
5585 _("Tellar Prime (Miracht)"), # TOS: "Journey to Babel"
5586 _("Vulcan (T'Khasi)"), # many episodes
5587 _("Medusa"), # TOS: "Is There in Truth No Beauty?"
5588 _("Argelius II (Nelphia)"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5589 _("Ardana"), # TOS: "The Cloud Minders"
5590 _("Catulla (Cendo-Prae)"), # TOS: "The Way to Eden"
5591 _("Gideon"), # TOS: "The Mark of Gideon"
5592 _("Aldebaran III"), # TOS: "The Deadly Years"
5593 _("Alpha Majoris I"), # TOS: "Wolf in the Fold"
5594 _("Altair IV"), # TOS: "Amok Time
5595 _("Ariannus"), # TOS: "Let That Be Your Last Battlefield"
5596 _("Benecia"), # TOS: "The Conscience of the King"
5597 _("Beta Niobe I (Sarpeidon)"), # TOS: "All Our Yesterdays"
5598 _("Alpha Carinae II"), # TOS: "The Ultimate Computer"
5599 _("Capella IV (Kohath)"), # TOS: "Friday's Child" (Class G)
5600 _("Daran V"), # TOS: "For the World is Hollow and I Have Touched the Sky"
5601 _("Deneb II"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5602 _("Eminiar VII"), # TOS: "A Taste of Armageddon"
5603 _("Gamma Canaris IV"), # TOS: "Metamorphosis"
5604 _("Gamma Tranguli VI (Vaalel)"), # TOS: "The Apple"
5605 _("Ingraham B"), # TOS: "Operation: Annihilate"
5606 _("Janus IV"), # TOS: "The Devil in the Dark"
5607 _("Makus III"), # TOS: "The Galileo Seven"
5608 _("Marcos XII"), # TOS: "And the Children Shall Lead",
5609 _("Omega IV"), # TOS: "The Omega Glory"
5610 _("Regulus V"), # TOS: "Amok Time
5611 _("Deneva"), # TOS: "Operation -- Annihilate!"
5612 # Worlds from BSD Trek
5613 _("Rigel II"), # TOS: "Shore Leave" ("III" in BSD)
5614 _("Beta III"), # TOS: "The Return of the Archons"
5615 _("Triacus"), # TOS: "And the Children Shall Lead",
5616 _("Exo III"), # TOS: "What Are Little Girls Made Of?" (Class P)
5618 # _("Hansen's Planet"), # TOS: "The Galileo Seven"
5619 # _("Taurus IV"), # TOS: "The Galileo Seven" (class G)
5620 # _("Antos IV (Doraphane)"), # TOS: "Whom Gods Destroy", "Who Mourns for Adonais?"
5621 # _("Izar"), # TOS: "Whom Gods Destroy"
5622 # _("Tiburon"), # TOS: "The Way to Eden"
5623 # _("Merak II"), # TOS: "The Cloud Minders"
5624 # _("Coridan (Desotriana)"), # TOS: "Journey to Babel"
5625 # _("Iotia"), # TOS: "A Piece of the Action"
5629 _("S. R. Sensors"), \
5630 _("L. R. Sensors"), \
5632 _("Photon Tubes"), \
5633 _("Life Support"), \
5634 _("Warp Engines"), \
5635 _("Impulse Engines"), \
5637 _("Subspace Radio"), \
5638 _("Shuttle Craft"), \
5640 _("Navigation System"), \
5642 _("Shield Control"), \
5645 _("Cloaking Device"), \
5649 "Prepare to play, set up cosmos."
5651 # Decide how many of everything
5653 return # frozen game
5654 # Prepare the Enterprise
5655 game.alldone = game.gamewon = game.shldchg = game.shldup = False
5657 game.state.crew = FULLCREW
5658 game.energy = game.inenrg = 5000.0
5659 game.shield = game.inshld = 2500.0
5662 game.quadrant = randplace(GALSIZE)
5663 game.sector = randplace(QUADSIZE)
5664 game.torps = game.intorps = 10
5665 game.nprobes = randrange(2, 5)
5667 for i in range(NDEVICES):
5668 game.damage[i] = 0.0
5669 # Set up assorted game parameters
5670 game.battle = Coord()
5671 game.state.date = game.indate = 100.0 * randreal(20, 51)
5672 game.nkinks = game.nhelp = game.casual = game.abandoned = 0
5673 game.iscate = game.resting = game.imine = game.icrystl = game.icraft = False
5674 game.isatb = game.state.nplankl = 0
5675 game.state.starkl = game.state.basekl = game.state.nworldkl = 0
5676 game.iscraft = "onship"
5681 game.state.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
5683 game.state.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
5685 game.state.planets = [] # Planet information
5686 game.state.baseq = [] # Base quadrant coordinates
5687 game.state.kcmdr = [] # Commander quadrant coordinates
5688 game.statekscmdr = Coord() # Supercommander quadrant coordinates
5690 # Starchart is functional but we've never seen it
5691 game.lastchart = FOREVER
5692 # Put stars in the galaxy
5694 for i in range(GALSIZE):
5695 for j in range(GALSIZE):
5696 # Can't have more stars per quadrant than fit in one decimal digit,
5697 # if we do the chart representation will break.
5698 k = randrange(1, min(10, QUADSIZE**2/10))
5700 game.state.galaxy[i][j].stars = k
5701 # Locate star bases in galaxy
5703 prout("=== Allocating %d bases" % game.inbase)
5704 for i in range(game.inbase):
5707 w = randplace(GALSIZE)
5708 if not game.state.galaxy[w.i][w.j].starbase:
5711 # C version: for (j = i-1; j > 0; j--)
5712 # so it did them in the opposite order.
5713 for j in range(1, i):
5714 # Improved placement algorithm to spread out bases
5715 distq = (w - game.state.baseq[j]).distance()
5716 if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75):
5719 prout("=== Abandoning base #%d at %s" % (i, w))
5721 elif distq < 6.0 * (BASEMAX+1-game.inbase):
5723 prout("=== Saving base #%d, close to #%d" % (i, j))
5727 prout("=== Placing base #%d in quadrant %s" % (i, w))
5728 game.state.baseq.append(w)
5729 game.state.galaxy[w.i][w.j].starbase = game.state.chart[w.i][w.j].starbase = True
5730 # Position ordinary Klingon Battle Cruisers
5732 klumper = 0.25*game.skill*(9.0-game.length)+1.0
5733 if klumper > MAXKLQUAD:
5737 klump = int((1.0 - r*r)*klumper)
5742 w = randplace(GALSIZE)
5743 if not game.state.galaxy[w.i][w.j].supernova and \
5744 game.state.galaxy[w.i][w.j].klingons + klump <= MAXKLQUAD:
5746 game.state.galaxy[w.i][w.j].klingons += klump
5749 # Position Klingon Commander Ships
5750 for i in range(game.incom):
5752 w = randplace(GALSIZE)
5753 if not welcoming(w) or w in game.state.kcmdr:
5755 if (game.state.galaxy[w.i][w.j].klingons or withprob(0.25)):
5757 game.state.galaxy[w.i][w.j].klingons += 1
5758 game.state.kcmdr.append(w)
5759 # Locate planets in galaxy
5760 for i in range(game.inplan):
5762 w = randplace(GALSIZE)
5763 if game.state.galaxy[w.i][w.j].planet is None:
5767 new.crystals = "absent"
5768 if (game.options & OPTION_WORLDS) and i < NINHAB:
5769 new.pclass = "M" # All inhabited planets are class M
5770 new.crystals = "absent"
5772 new.name = systnames[i]
5773 new.inhabited = True
5775 new.pclass = ("M", "N", "O")[randrange(0, 3)]
5777 new.crystals = "present"
5778 new.known = "unknown"
5779 new.inhabited = False
5780 game.state.galaxy[w.i][w.j].planet = new
5781 game.state.planets.append(new)
5783 for i in range(game.state.nromrem):
5784 w = randplace(GALSIZE)
5785 game.state.galaxy[w.i][w.j].romulans += 1
5786 # Place the Super-Commander if needed
5787 if game.state.nscrem > 0:
5789 w = randplace(GALSIZE)
5792 game.state.kscmdr = w
5793 game.state.galaxy[w.i][w.j].klingons += 1
5794 # Initialize times for extraneous events
5795 schedule(FSNOVA, expran(0.5 * game.intime))
5796 schedule(FTBEAM, expran(1.5 * (game.intime / len(game.state.kcmdr))))
5797 schedule(FSNAP, randreal(1.0, 2.0)) # Force an early snapshot
5798 schedule(FBATTAK, expran(0.3*game.intime))
5800 if game.state.nscrem:
5801 schedule(FSCMOVE, 0.2777)
5806 if (game.options & OPTION_WORLDS) and game.skill >= SKILL_GOOD:
5807 schedule(FDISTR, expran(1.0 + game.intime))
5812 # Place thing (in tournament game, we don't want one!)
5813 # New in SST2K: never place the Thing near a starbase.
5814 # This makes sense and avoids a special case in the old code.
5816 if game.tourn is None:
5818 thing = randplace(GALSIZE)
5819 if thing not in game.state.baseq:
5822 game.state.snap = False
5823 if game.skill == SKILL_NOVICE:
5824 prout(_("It is stardate %d. The Federation is being attacked by") % int(game.state.date))
5825 prout(_("a deadly Klingon invasion force. As captain of the United"))
5826 prout(_("Starship U.S.S. Enterprise, it is your mission to seek out"))
5827 prout(_("and destroy this invasion force of %d battle cruisers.") % ((game.inkling + game.incom + game.inscom)))
5828 prout(_("You have an initial allotment of %d stardates to complete") % int(game.intime))
5829 prout(_("your mission. As you proceed you may be given more time."))
5831 prout(_("You will have %d supporting starbases.") % (game.inbase))
5832 proutn(_("Starbase locations- "))
5834 prout(_("Stardate %d.") % int(game.state.date))
5836 prout(_("%d Klingons.") % (game.inkling + game.incom + game.inscom))
5837 prout(_("An unknown number of Romulans."))
5838 if game.state.nscrem:
5839 prout(_("And one (GULP) Super-Commander."))
5840 prout(_("%d stardates.") % int(game.intime))
5841 proutn(_("%d starbases in ") % game.inbase)
5842 for i in range(game.inbase):
5843 proutn(repr(game.state.baseq[i]))
5846 proutn(_("The Enterprise is currently in Quadrant %s") % game.quadrant)
5847 proutn(_(" Sector %s") % game.sector)
5849 prout(_("Good Luck!"))
5850 if game.state.nscrem:
5851 prout(_(" YOU'LL NEED IT."))
5854 setwnd(message_window)
5856 if len(game.enemies) - (thing == game.quadrant) - (game.tholian != None):
5858 if game.neutz: # bad luck to start in a Romulan Neutral Zone
5859 attack(torps_ok=False)
5862 "Choose your game type."
5864 game.tourn = game.length = 0
5866 game.skill = SKILL_NONE
5867 # Do not chew here, we want to use command-line tokens
5868 if not scanner.inqueue: # Can start with command line options
5869 proutn(_("Would you like a regular, tournament, or saved game? "))
5871 if scanner.sees("tournament"):
5872 while scanner.nexttok() == "IHEOL":
5873 proutn(_("Type in tournament number-"))
5874 if scanner.real == 0:
5876 continue # We don't want a blank entry
5877 game.tourn = int(round(scanner.real))
5878 random.seed(scanner.real)
5880 logfp.write("# random.seed(%d)\n" % scanner.real)
5882 if scanner.sees("saved") or scanner.sees("frozen"):
5886 if game.passwd is None:
5888 if not game.alldone:
5889 game.thawed = True # No plaque if not finished
5893 if scanner.sees("regular"):
5895 proutn(_("What is \"%s\"? ") % scanner.token)
5897 while game.length==0 or game.skill==SKILL_NONE:
5898 if scanner.nexttok() == "IHALPHA":
5899 if scanner.sees("short"):
5901 elif scanner.sees("medium"):
5903 elif scanner.sees("long"):
5905 elif scanner.sees("novice"):
5906 game.skill = SKILL_NOVICE
5907 elif scanner.sees("fair"):
5908 game.skill = SKILL_FAIR
5909 elif scanner.sees("good"):
5910 game.skill = SKILL_GOOD
5911 elif scanner.sees("expert"):
5912 game.skill = SKILL_EXPERT
5913 elif scanner.sees("emeritus"):
5914 game.skill = SKILL_EMERITUS
5916 proutn(_("What is \""))
5917 proutn(scanner.token)
5922 proutn(_("Would you like a Short, Medium, or Long game? "))
5923 elif game.skill == SKILL_NONE:
5924 proutn(_("Are you a Novice, Fair, Good, Expert, or Emeritus player? "))
5925 # Choose game options -- added by ESR for SST2K
5926 if scanner.nexttok() != "IHALPHA":
5928 proutn(_("Choose your game style (plain, almy, fancy or just press enter): "))
5930 if scanner.sees("plain"):
5931 # Approximates the UT FORTRAN version.
5932 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)
5933 game.options |= OPTION_PLAIN
5934 elif scanner.sees("almy"):
5935 # Approximates Tom Almy's version.
5936 game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS | OPTION_COLOR)
5937 game.options |= OPTION_ALMY
5938 elif scanner.sees("fancy") or scanner.sees("\n"):
5940 elif len(scanner.token):
5941 proutn(_("What is \"%s\"?") % scanner.token)
5943 if game.passwd == "debug":
5945 prout("=== Debug mode enabled.")
5946 # Use parameters to generate initial values of things
5947 game.damfac = 0.5 * game.skill
5948 game.inbase = randrange(BASEMIN, BASEMAX+1)
5950 if game.options & OPTION_PLANETS:
5951 game.inplan += randrange(MAXUNINHAB/2, MAXUNINHAB+1)
5952 if game.options & OPTION_WORLDS:
5953 game.inplan += int(NINHAB)
5954 game.state.nromrem = game.inrom = randrange(2 * game.skill)
5955 game.state.nscrem = game.inscom = (game.skill > SKILL_FAIR)
5956 game.state.remtime = 7.0 * game.length
5957 game.intime = game.state.remtime
5958 game.inkling = int(2.0*game.intime*((game.skill+1 - 2*randreal())*game.skill*0.1+.15))
5959 game.incom = min(MINCMDR, int(game.skill + 0.0625*game.inkling*randreal()))
5960 game.state.remres = (game.inkling+4*game.incom)*game.intime
5961 game.inresor = game.state.remres
5962 if game.inkling > 50:
5966 def dropin(iquad=None):
5967 "Drop a feature on a random dot in the current quadrant."
5969 w = randplace(QUADSIZE)
5970 if game.quad[w.i][w.j] == '.':
5972 if iquad is not None:
5973 game.quad[w.i][w.j] = iquad
5977 "Update our alert status."
5978 game.condition = "green"
5979 if game.energy < 1000.0:
5980 game.condition = "yellow"
5981 if game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons or game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans:
5982 game.condition = "red"
5984 game.condition="dead"
5987 "Drop new Klingon into current quadrant."
5988 return Enemy('K', loc=dropin(), power=randreal(300,450)+25.0*game.skill)
5991 "Sort enemies by distance so 'nearest' is meaningful."
5992 game.enemies.sort(key=lambda x: x.kdist)
5995 "Set up a new state of quadrant, for when we enter or re-enter it."
5998 game.neutz = game.inorbit = game.landed = False
5999 game.ientesc = game.iseenit = game.isviolreported = False
6000 # Create a blank quadrant
6001 game.quad = fill2d(QUADSIZE, lambda i, j: '.')
6003 # Attempt to escape Super-commander, so tbeam back!
6006 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
6007 # cope with supernova
6010 game.klhere = q.klingons
6011 game.irhere = q.romulans
6013 game.quad[game.sector.i][game.sector.j] = game.ship
6016 # Position ordinary Klingons
6017 for _i in range(game.klhere):
6019 # If we need a commander, promote a Klingon
6020 for cmdr in game.state.kcmdr:
6021 if cmdr == game.quadrant:
6022 e = game.enemies[game.klhere-1]
6023 game.quad[e.location.i][e.location.j] = 'C'
6024 e.power = randreal(950,1350) + 50.0*game.skill
6026 # If we need a super-commander, promote a Klingon
6027 if game.quadrant == game.state.kscmdr:
6029 game.quad[e.location.i][e.location.j] = 'S'
6030 e.power = randreal(1175.0, 1575.0) + 125.0*game.skill
6031 game.iscate = (game.remkl() > 1)
6032 # Put in Romulans if needed
6033 for _i in range(q.romulans):
6034 Enemy('R', loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill)
6035 # If quadrant needs a starbase, put it in
6037 game.base = dropin('B')
6038 # If quadrant needs a planet, put it in
6040 game.iplnet = q.planet
6041 if not q.planet.inhabited:
6042 game.plnet = dropin('P')
6044 game.plnet = dropin('@')
6045 # Check for condition
6048 if game.irhere > 0 and game.klhere == 0:
6050 if not damaged(DRADIO):
6052 prout(_("LT. Uhura- \"Captain, an urgent message."))
6053 prout(_(" I'll put it on audio.\" CLICK"))
6055 prout(_("INTRUDER! YOU HAVE VIOLATED THE ROMULAN NEUTRAL ZONE."))
6056 prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!"))
6057 # Put in THING if needed
6058 if thing == game.quadrant:
6059 Enemy(etype='?', loc=dropin(),
6060 power=randreal(6000,6500.0)+250.0*game.skill)
6061 if not damaged(DSRSENS):
6063 prout(_("Mr. Spock- \"Captain, this is most unusual."))
6064 prout(_(" Please examine your short-range scan.\""))
6065 # Decide if quadrant needs a Tholian; lighten up if skill is low
6066 if game.options & OPTION_THOLIAN:
6067 if (game.skill < SKILL_GOOD and withprob(0.02)) or \
6068 (game.skill == SKILL_GOOD and withprob(0.05)) or \
6069 (game.skill > SKILL_GOOD and withprob(0.08)):
6072 w.i = withprob(0.5) * (QUADSIZE-1)
6073 w.j = withprob(0.5) * (QUADSIZE-1)
6074 if game.quad[w.i][w.j] == '.':
6076 game.tholian = Enemy(etype='T', loc=w,
6077 power=randrange(100, 500) + 25.0*game.skill)
6078 # Reserve unoccupied corners
6079 if game.quad[0][0]=='.':
6080 game.quad[0][0] = 'X'
6081 if game.quad[0][QUADSIZE-1]=='.':
6082 game.quad[0][QUADSIZE-1] = 'X'
6083 if game.quad[QUADSIZE-1][0]=='.':
6084 game.quad[QUADSIZE-1][0] = 'X'
6085 if game.quad[QUADSIZE-1][QUADSIZE-1]=='.':
6086 game.quad[QUADSIZE-1][QUADSIZE-1] = 'X'
6088 # And finally the stars
6089 for _i in range(q.stars):
6091 # Put in a few black holes
6092 for _i in range(1, 3+1):
6095 # Take out X's in corners if Tholian present
6097 if game.quad[0][0]=='X':
6098 game.quad[0][0] = '.'
6099 if game.quad[0][QUADSIZE-1]=='X':
6100 game.quad[0][QUADSIZE-1] = '.'
6101 if game.quad[QUADSIZE-1][0]=='X':
6102 game.quad[QUADSIZE-1][0] = '.'
6103 if game.quad[QUADSIZE-1][QUADSIZE-1]=='X':
6104 game.quad[QUADSIZE-1][QUADSIZE-1] = '.'
6105 # This should guarantee that replay games don't lose info about the chart
6106 if (game.options & OPTION_AUTOSCAN) or replayfp:
6110 "Set the self-destruct password."
6111 if game.options & OPTION_PLAIN:
6114 proutn(_("Please type in a secret password- "))
6116 game.passwd = scanner.token
6117 if game.passwd != None:
6121 game.passwd += chr(ord('a')+randrange(26))
6122 game.passwd += chr(ord('a')+randrange(26))
6123 game.passwd += chr(ord('a')+randrange(26))
6125 # Code from sst.c begins here
6128 ("SRSCAN", OPTION_TTY),
6129 ("STATUS", OPTION_TTY),
6130 ("REQUEST", OPTION_TTY),
6131 ("LRSCAN", OPTION_TTY),
6143 ("SENSORS", OPTION_PLANETS),
6144 ("ORBIT", OPTION_PLANETS),
6145 ("TRANSPORT", OPTION_PLANETS),
6146 ("MINE", OPTION_PLANETS),
6147 ("CRYSTALS", OPTION_PLANETS),
6148 ("SHUTTLE", OPTION_PLANETS),
6149 ("PLANETS", OPTION_PLANETS),
6154 ("PROBE", OPTION_PROBE),
6156 ("FREEZE", 0), # Synonym for SAVE
6160 ("CAPTURE", OPTION_CAPTURE),
6161 ("CLOAK", OPTION_CLOAK),
6164 ("SOS", 0), # Synonym for MAYDAY
6165 ("CALL", 0), # Synonym for MAYDAY
6174 "Generate a list of legal commands."
6175 prout(_("LEGAL COMMANDS ARE:"))
6177 for (key, opt) in commands:
6178 if not opt or (opt & game.options):
6179 proutn("%-12s " % key)
6181 if emitted % 5 == 4:
6186 "Browse on-line help."
6187 key = scanner.nexttok()
6190 setwnd(prompt_window)
6191 proutn(_("Help on what command? "))
6192 key = scanner.nexttok()
6193 setwnd(message_window)
6196 cmds = [x[0] for x in commands]
6197 if scanner.token.upper() in cmds or scanner.token.upper() == "ABBREV":
6204 cmd = scanner.token.upper()
6205 for directory in docpath:
6207 fp = open(os.path.join(directory, "sst.doc"), "r")
6212 prout(_("Spock- \"Captain, that information is missing from the"))
6213 prout(_(" computer. You need to find sst.doc and put it somewhere"))
6214 proutn(_(" in these directories: %s") % ":".join(docpath))
6216 # This used to continue: "You need to find SST.DOC and put
6217 # it in the current directory."
6220 linebuf = fp.readline()
6222 prout(_("Spock- \"Captain, there is no information on that command.\""))
6225 if linebuf[0] == '%' and linebuf[1] == '%' and linebuf[2] == ' ':
6226 linebuf = linebuf[3:].strip()
6227 if cmd.upper() == linebuf:
6230 prout(_("Spock- \"Captain, I've found the following information:\""))
6233 linebuf = fp.readline()
6234 if "******" in linebuf:
6240 "Command-interpretation loop."
6242 if game.irhere and game.state.date >= ALGERON and not game.isviolreported and game.iscloaked:
6243 prout(_("The Romulan ship discovers you are breaking the Treaty of Algeron!"))
6245 game.isviolreported = True
6246 while True: # command loop
6248 while True: # get a command
6250 game.optime = game.justin = False
6252 setwnd(prompt_window)
6255 if scanner.nexttok() == "IHEOL":
6256 if game.options & OPTION_CURSES:
6259 elif scanner.token == "":
6263 setwnd(message_window)
6265 abandon_passed = False
6266 cmd = "" # Force cmd to persist after loop
6267 opt = 0 # Force opt to persist after loop
6268 for (cmd, opt) in commands:
6269 # commands after ABANDON cannot be abbreviated
6270 if cmd == "ABANDON":
6271 abandon_passed = True
6272 if cmd == scanner.token.upper() or (not abandon_passed \
6273 and cmd.startswith(scanner.token.upper())):
6278 elif opt and not (opt & game.options):
6282 if game.options & OPTION_CURSES:
6283 prout("COMMAND> %s" % cmd)
6284 if cmd == "SRSCAN": # srscan
6286 elif cmd == "STATUS": # status
6288 elif cmd == "REQUEST": # status request
6290 elif cmd == "LRSCAN": # long range scan
6291 lrscan(silent=False)
6292 elif cmd == "PHASERS": # phasers
6297 elif cmd in ("TORPEDO", "PHOTONS"): # photon torpedos
6302 elif cmd == "MOVE": # move under warp
6303 warp(wcourse=None, involuntary=False)
6304 elif cmd == "SHIELDS": # shields
6305 doshield(shraise=False)
6308 game.shldchg = False
6309 elif cmd == "DOCK": # dock at starbase
6312 attack(torps_ok=False)
6313 elif cmd == "DAMAGES": # damage reports
6315 elif cmd == "CHART": # chart
6317 elif cmd == "IMPULSE": # impulse
6319 elif cmd == "REST": # rest
6323 elif cmd == "WARP": # warp
6325 elif cmd == "SENSORS": # sensors
6327 elif cmd == "ORBIT": # orbit
6331 elif cmd == "TRANSPORT": # transport "beam"
6333 elif cmd == "MINE": # mine
6337 elif cmd == "CRYSTALS": # crystals
6341 elif cmd == "SHUTTLE": # shuttle
6345 elif cmd == "PLANETS": # Planet list
6347 elif cmd == "REPORT": # Game Report
6349 elif cmd == "COMPUTER": # use COMPUTER!
6351 elif cmd == "COMMANDS":
6353 elif cmd == "EMEXIT": # Emergency exit
6354 clrscr() # Hide screen
6355 freeze(True) # forced save
6356 raise SystemExit(1) # And quick exit
6357 elif cmd == "PROBE":
6358 probe() # Launch probe
6361 elif cmd == "ABANDON": # Abandon Ship
6363 elif cmd == "DESTRUCT": # Self Destruct
6365 elif cmd == "SAVE": # Save Game
6368 if game.skill > SKILL_GOOD:
6369 prout(_("WARNING--Saved games produce no plaques!"))
6370 elif cmd == "DEATHRAY": # Try a desparation measure
6374 elif cmd == "CAPTURE":
6376 elif cmd == "CLOAK":
6378 elif cmd == "DEBUGCMD": # What do we want for debug???
6380 elif cmd == "MAYDAY": # Call for help
6385 game.alldone = True # quit the game
6388 elif cmd == "SCORE":
6389 score() # see current score
6390 elif cmd == "CURSES":
6391 game.options |= (OPTION_CURSES | OPTION_COLOR)
6395 break # Game has ended
6396 if game.optime != 0.0:
6399 break # Events did us in
6400 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6403 if hitme and not game.justin:
6404 attack(torps_ok=True)
6407 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6418 "Emit the name of an enemy or feature."
6419 if ch == 'R': s = _("Romulan")
6420 elif ch == 'K': s = _("Klingon")
6421 elif ch == 'C': s = _("Commander")
6422 elif ch == 'S': s = _("Super-commander")
6423 elif ch == '*': s = _("Star")
6424 elif ch == 'P': s = _("Planet")
6425 elif ch == 'B': s = _("Starbase")
6426 elif ch == ' ': s = _("Black hole")
6427 elif ch == 'T': s = _("Tholian")
6428 elif ch == '#': s = _("Tholian web")
6429 elif ch == '?': s = _("Stranger")
6430 elif ch == '@': s = _("Inhabited World")
6431 else: s = "Unknown??"
6434 def crmena(loud, enemy, loctype, w):
6435 "Emit the name of an enemy and his location."
6439 buf += cramen(enemy) + _(" at ")
6440 if loctype == "quadrant":
6441 buf += _("Quadrant ")
6442 elif loctype == "sector":
6444 return buf + repr(w)
6447 "Emit our ship name."
6448 return{'E':_("Enterprise"),'F':_("Faerie Queene")}.get(game.ship,"Ship???")
6451 "Emit a line of stars"
6452 prouts("******************************************************")
6456 return -avrage*math.log(1e-7 + randreal())
6458 def randplace(size):
6459 "Choose a random location."
6461 w.i = randrange(size)
6462 w.j = randrange(size)
6472 # Get a token from the user
6475 # Fill the token quue if nothing here
6476 while not self.inqueue:
6478 if curwnd==prompt_window:
6480 setwnd(message_window)
6487 self.inqueue = sline.lstrip().split() + ["\n"]
6488 # From here on in it's all looking at the queue
6489 self.token = self.inqueue.pop(0)
6490 if self.token == "\n":
6494 self.real = float(self.token)
6495 self.type = "IHREAL"
6500 self.token = self.token.lower()
6501 self.type = "IHALPHA"
6504 def append(self, tok):
6505 self.inqueue.append(tok)
6506 def push(self, tok):
6507 self.inqueue.insert(0, tok)
6511 # Demand input for next scan
6513 self.real = self.token = None
6515 # compares s to item and returns true if it matches to the length of s
6516 return s.startswith(self.token)
6518 # Round token value to nearest integer
6519 return int(round(self.real))
6523 if self.type != "IHREAL":
6528 if self.type != "IHREAL":
6534 return "<sstcanner: token=%s, type=%s, queue=%s>" % (self.token, self.type, self.inqueue)
6537 "Yes-or-no confirmation."
6541 if scanner.token == 'y':
6543 if scanner.token == 'n':
6546 proutn(_("Please answer with \"y\" or \"n\": "))
6549 "Complain about unparseable input."
6552 prout(_("Beg your pardon, Captain?"))
6555 "Access to the internals for debugging."
6556 proutn("Reset levels? ")
6558 if game.energy < game.inenrg:
6559 game.energy = game.inenrg
6560 game.shield = game.inshld
6561 game.torps = game.intorps
6562 game.lsupres = game.inlsr
6563 proutn("Reset damage? ")
6565 for i in range(NDEVICES):
6566 if game.damage[i] > 0.0:
6567 game.damage[i] = 0.0
6568 proutn("Toggle debug flag? ")
6570 game.idebug = not game.idebug
6572 prout("Debug output ON")
6574 prout("Debug output OFF")
6575 proutn("Cause selective damage? ")
6577 for i in range(NDEVICES):
6578 proutn("Kill %s?" % device[i])
6580 key = scanner.nexttok()
6581 if key == "IHALPHA" and scanner.sees("y"):
6582 game.damage[i] = 10.0
6583 proutn("Examine/change events? ")
6588 FSNOVA: "Supernova ",
6591 FBATTAK: "Base Attack ",
6592 FCDBAS: "Base Destroy ",
6593 FSCMOVE: "SC Move ",
6594 FSCDBAS: "SC Base Destroy ",
6595 FDSPROB: "Probe Move ",
6596 FDISTR: "Distress Call ",
6597 FENSLV: "Enslavement ",
6598 FREPRO: "Klingon Build ",
6600 for i in range(1, NEVENTS):
6603 proutn("%.2f" % (scheduled(i)-game.state.date))
6604 if i == FENSLV or i == FREPRO:
6606 proutn(" in %s" % ev.quadrant)
6611 key = scanner.nexttok()
6615 elif key == "IHREAL":
6616 ev = schedule(i, scanner.real)
6617 if i == FENSLV or i == FREPRO:
6619 proutn("In quadrant- ")
6620 key = scanner.nexttok()
6621 # "IHEOL" says to leave coordinates as they are
6624 prout("Event %d canceled, no x coordinate." % (i))
6627 w.i = int(round(scanner.real))
6628 key = scanner.nexttok()
6630 prout("Event %d canceled, no y coordinate." % (i))
6633 w.j = int(round(scanner.real))
6636 proutn("Induce supernova here? ")
6638 game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova = True
6641 if __name__ == '__main__':
6643 #global line, thing, game
6647 game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY)
6648 if os.getenv("TERM"):
6649 game.options |= OPTION_CURSES
6651 game.options |= OPTION_TTY
6652 seed = int(time.time())
6653 (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:txV")
6655 for (switch, val) in options:
6658 replayfp = open(val, "r")
6660 sys.stderr.write("sst: can't open replay file %s\n" % val)
6663 line = replayfp.readline().strip()
6664 (leader, __, seed) = line.split()
6666 sys.stderr.write("sst2k: seed set to %s\n" % seed)
6667 line = replayfp.readline().strip()
6668 arguments += line.split()[2:]
6671 sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
6673 game.options |= OPTION_TTY
6674 game.options &=~ OPTION_CURSES
6675 elif switch == '-s':
6677 elif switch == '-t':
6678 game.options |= OPTION_TTY
6679 game.options &=~ OPTION_CURSES
6680 elif switch == '-x':
6682 elif switch == '-V':
6683 print("SST2K", version)
6686 sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n")
6688 # where to save the input in case of bugs
6689 if "TMPDIR" in os.environ:
6690 tmpdir = os.environ['TMPDIR']
6694 logfp = open(os.path.join(tmpdir, "sst-input.log"), "w")
6696 sys.stderr.write("sst: warning, can't open logfile\n")
6699 logfp.write("# seed %s\n" % seed)
6700 logfp.write("# options %s\n" % " ".join(arguments))
6701 logfp.write("# SST2K version %s\n" % version)
6702 logfp.write("# recorded by %s@%s on %s\n" % \
6703 (getpass.getuser(),socket.gethostname(),time.ctime()))
6705 scanner = sstscanner()
6706 for arg in arguments:
6710 while True: # Play a game
6711 setwnd(fullscreen_window)
6717 game.alldone = False
6725 if game.tourn and game.alldone:
6726 proutn(_("Do you want your score recorded?"))
6732 proutn(_("Do you want to play again? "))
6736 prout(_("May the Great Bird of the Galaxy roost upon your home planet."))
6740 except KeyboardInterrupt: