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
90 return self.i != None and self.j != None
91 def __eq__(self, other):
92 return other != None and self.i == other.i and self.j == other.j
93 def __ne__(self, other):
94 return other is None or self.i != other.i or self.j != other.j
95 def __add__(self, other):
96 return Coord(self.i+other.i, self.j+other.j)
97 def __sub__(self, other):
98 return Coord(self.i-other.i, self.j-other.j)
99 def __mul__(self, other):
100 return Coord(self.i*other, self.j*other)
101 def __rmul__(self, other):
102 return Coord(self.i*other, self.j*other)
103 def __div__(self, other):
104 return Coord(self.i/other, self.j/other)
105 def __mod__(self, other):
106 return Coord(self.i % other, self.j % other)
107 def __rdiv__(self, other):
108 return Coord(self.i/other, self.j/other)
109 def roundtogrid(self):
110 return Coord(int(round(self.i)), int(round(self.j)))
111 def distance(self, other=None):
114 return math.sqrt((self.i - other.i)**2 + (self.j - other.j)**2)
116 return 1.90985*math.atan2(self.j, self.i)
122 s.i = self.i / abs(self.i)
126 s.j = self.j / abs(self.j)
129 #print "Location %s -> %s" % (self, (self / QUADSIZE).roundtogrid())
130 return self.roundtogrid() / QUADSIZE
132 return self.roundtogrid() % QUADSIZE
135 s.i = self.i + randrange(-1, 2)
136 s.j = self.j + randrange(-1, 2)
139 if self.i is None or self.j is None:
141 return "%s - %s" % (self.i+1, self.j+1)
145 "Do not anger the Space Thingy!"
152 return (q.i, q.j) == (self.i, self.j)
156 self.name = None # string-valued if inhabited
157 self.quadrant = Coord() # quadrant located
158 self.pclass = None # could be ""M", "N", "O", or "destroyed"
159 self.crystals = "absent"# could be "mined", "present", "absent"
160 self.known = "unknown" # could be "unknown", "known", "shuttle_down"
161 self.inhabited = False # is it inhabited?
169 self.starbase = False
172 self.supernova = False
174 self.status = "secure" # Could be "secure", "distressed", "enslaved"
176 return "<Quadrant: %(klingons)d>" % self.__dict__
182 self.starbase = False
185 return "<%s,%s,%s>" % (self.klingons, self.starbase, self.stars)
187 def fill2d(size, fillfun):
188 "Fill an empty list in 2D."
190 for i in range(size):
192 for j in range(size):
193 lst[i].append(fillfun(i, j))
198 self.snap = False # snapshot taken
199 self.crew = 0 # crew complement
200 self.nscrem = 0 # remaining super commanders
201 self.starkl = 0 # destroyed stars
202 self.basekl = 0 # destroyed bases
203 self.nromrem = 0 # Romulans remaining
204 self.nplankl = 0 # destroyed uninhabited planets
205 self.nworldkl = 0 # destroyed inhabited planets
206 self.planets = [] # Planet information
207 self.date = 0.0 # stardate
208 self.remres = 0 # remaining resources
209 self.remtime = 0 # remaining time
210 self.baseq = [] # Base quadrant coordinates
211 self.kcmdr = [] # Commander quadrant coordinates
212 self.kscmdr = Coord() # Supercommander quadrant coordinates
214 self.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
216 self.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
218 for i in range(GALSIZE):
219 for j in range(GALSIZE):
220 yield (i, j, self.galaxy[i][j])
224 self.date = None # A real number
225 self.quadrant = None # A coord structure
228 OPTION_ALL = 0xffffffff
229 OPTION_TTY = 0x00000001 # old interface
230 OPTION_CURSES = 0x00000002 # new interface
231 OPTION_IOMODES = 0x00000003 # cover both interfaces
232 OPTION_PLANETS = 0x00000004 # planets and mining
233 OPTION_THOLIAN = 0x00000008 # Tholians and their webs (UT 1979 version)
234 OPTION_THINGY = 0x00000010 # Space Thingy can shoot back (Stas, 2005)
235 OPTION_PROBE = 0x00000020 # deep-space probes (DECUS version, 1980)
236 OPTION_SHOWME = 0x00000040 # bracket Enterprise in chart
237 OPTION_RAMMING = 0x00000080 # enemies may ram Enterprise (Almy)
238 OPTION_MVBADDY = 0x00000100 # more enemies can move (Almy)
239 OPTION_BLKHOLE = 0x00000200 # black hole may timewarp you (Stas, 2005)
240 OPTION_BASE = 0x00000400 # bases have good shields (Stas, 2005)
241 OPTION_WORLDS = 0x00000800 # logic for inhabited worlds (ESR, 2006)
242 OPTION_AUTOSCAN = 0x00001000 # automatic LRSCAN before CHART (ESR, 2006)
243 OPTION_CAPTURE = 0x00002000 # Enable BSD-Trek capture (Almy, 2013).
244 OPTION_CLOAK = 0x80004000 # Enable BSD-Trek capture (Almy, 2013).
245 OPTION_PLAIN = 0x01000000 # user chose plain game
246 OPTION_ALMY = 0x02000000 # user chose Almy variant
247 OPTION_COLOR = 0x04000000 # enable color display (ESR, 2010)
267 NDEVICES = 17 # Number of devices
277 return (game.damage[dev] != 0.0)
279 return not damaged(DRADIO) or game.condition=="docked"
281 # Define future events
282 FSPY = 0 # Spy event happens always (no future[] entry)
283 # can cause SC to tractor beam Enterprise
284 FSNOVA = 1 # Supernova
285 FTBEAM = 2 # Commander tractor beams Enterprise
286 FSNAP = 3 # Snapshot for time warp
287 FBATTAK = 4 # Commander attacks base
288 FCDBAS = 5 # Commander destroys base
289 FSCMOVE = 6 # Supercommander moves (might attack base)
290 FSCDBAS = 7 # Supercommander destroys base
291 FDSPROB = 8 # Move deep space probe
292 FDISTR = 9 # Emit distress call from an inhabited world
293 FENSLV = 10 # Inhabited word is enslaved */
294 FREPRO = 11 # Klingons build a ship in an enslaved system
297 # Abstract out the event handling -- underlying data structures will change
298 # when we implement stateful events
299 def findevent(evtype):
300 return game.future[evtype]
303 def __init__(self, etype=None, loc=None, power=None):
305 self.location = Coord()
310 self.power = power # enemy energy level
311 game.enemies.append(self)
313 motion = (loc != self.location)
314 if self.location.i is not None and self.location.j is not None:
317 game.quad[self.location.i][self.location.j] = '#'
319 game.quad[self.location.i][self.location.j] = '.'
321 self.location = copy.copy(loc)
322 game.quad[self.location.i][self.location.j] = self.type
323 self.kdist = self.kavgd = (game.sector - loc).distance()
325 self.location = Coord()
326 self.kdist = self.kavgd = None
327 # Guard prevents failure on Tholian or thingy
328 if self in game.enemies:
329 game.enemies.remove(self)
332 return "<%s,%s.%f>" % (self.type, self.location, self.power) # For debugging
336 self.options = None # Game options
337 self.state = Snapshot() # A snapshot structure
338 self.snapsht = Snapshot() # Last snapshot taken for time-travel purposes
339 self.quad = None # contents of our quadrant
340 self.damage = [0.0] * NDEVICES # damage encountered
341 self.future = [] # future events
345 self.future.append(Event())
346 self.passwd = None # Self Destruct password
348 self.quadrant = None # where we are in the large
349 self.sector = None # where we are in the small
350 self.tholian = None # Tholian enemy object
351 self.base = None # position of base in current quadrant
352 self.battle = None # base coordinates being attacked
353 self.plnet = None # location of planet in quadrant
354 self.gamewon = False # Finished!
355 self.ididit = False # action taken -- allows enemy to attack
356 self.alive = False # we are alive (not killed)
357 self.justin = False # just entered quadrant
358 self.shldup = False # shields are up
359 self.shldchg = False # shield is changing (affects efficiency)
360 self.iscate = False # super commander is here
361 self.ientesc = False # attempted escape from supercommander
362 self.resting = False # rest time
363 self.icraft = False # Kirk in Galileo
364 self.landed = False # party on planet (true), on ship (false)
365 self.alldone = False # game is now finished
366 self.neutz = False # Romulan Neutral Zone
367 self.isarmed = False # probe is armed
368 self.inorbit = False # orbiting a planet
369 self.imine = False # mining
370 self.icrystl = False # dilithium crystals aboard
371 self.iseenit = False # seen base attack report
372 self.thawed = False # thawed game
373 self.condition = None # "green", "yellow", "red", "docked", "dead"
374 self.iscraft = None # "onship", "offship", "removed"
375 self.skill = None # Player skill level
376 self.inkling = 0 # initial number of klingons
377 self.inbase = 0 # initial number of bases
378 self.incom = 0 # initial number of commanders
379 self.inscom = 0 # initial number of commanders
380 self.inrom = 0 # initial number of commanders
381 self.instar = 0 # initial stars
382 self.intorps = 0 # initial/max torpedoes
383 self.torps = 0 # number of torpedoes
384 self.ship = 0 # ship type -- 'E' is Enterprise
385 self.abandoned = 0 # count of crew abandoned in space
386 self.length = 0 # length of game
387 self.klhere = 0 # klingons here
388 self.casual = 0 # causalties
389 self.nhelp = 0 # calls for help
390 self.nkinks = 0 # count of energy-barrier crossings
391 self.iplnet = None # planet # in quadrant
392 self.inplan = 0 # initial planets
393 self.irhere = 0 # Romulans in quadrant
394 self.isatb = 0 # =2 if super commander is attacking base
395 self.tourn = None # tournament number
396 self.nprobes = 0 # number of probes available
397 self.inresor = 0.0 # initial resources
398 self.intime = 0.0 # initial time
399 self.inenrg = 0.0 # initial/max energy
400 self.inshld = 0.0 # initial/max shield
401 self.inlsr = 0.0 # initial life support resources
402 self.indate = 0.0 # initial date
403 self.energy = 0.0 # energy level
404 self.shield = 0.0 # shield level
405 self.warpfac = 0.0 # warp speed
406 self.lsupres = 0.0 # life support reserves
407 self.optime = 0.0 # time taken by current operation
408 self.damfac = 0.0 # damage factor
409 self.lastchart = 0.0 # time star chart was last updated
410 self.cryprob = 0.0 # probability that crystal will work
411 self.probe = None # object holding probe course info
412 self.height = 0.0 # height of orbit around planet
413 self.score = 0.0 # overall score
414 self.perdate = 0.0 # rate of kills
415 self.idebug = False # Debugging instrumentation enabled?
416 self.statekscmdr = None # No SuperCommander coordinates yet.
417 self.brigcapacity = 400 # Enterprise brig capacity
418 self.brigfree = 400 # How many klingons can we put in the brig?
419 self.kcaptured = 0 # Total Klingons captured, for scoring.
420 self.iscloaked = False # Cloaking device on?
421 self.ncviol = 0 # Algreon treaty violations
422 self.isviolreported = False # We have been warned
424 return sum([q.klingons for (_i, _j, q) in list(self.state.traverse())])
426 # Stas thinks this should be (C expression):
427 # game.remkl() + len(game.state.kcmdr) > 0 ?
428 # game.state.remres/(game.remkl() + 4*len(game.state.kcmdr)) : 99
429 # He says the existing expression is prone to divide-by-zero errors
430 # after killing the last klingon when score is shown -- perhaps also
431 # if the only remaining klingon is SCOM.
432 self.state.remtime = self.state.remres/(self.remkl() + 4*len(self.state.kcmdr))
434 "Are there Klingons remaining?"
435 return self.remkl() + len(self.state.kcmdr) + self.state.nscrem
462 return random.random() < p
464 def randrange(*args):
465 return random.randrange(*args)
470 v *= args[0] # from [0, args[0])
472 v = args[0] + v*(args[1]-args[0]) # from [args[0], args[1])
475 # Code from ai.c begins here
478 "Would this quadrant welcome another Klingon?"
479 return iq.valid_quadrant() and \
480 not game.state.galaxy[iq.i][iq.j].supernova and \
481 game.state.galaxy[iq.i][iq.j].klingons < MAXKLQUAD
483 def tryexit(enemy, look, irun):
484 "A bad guy attempts to bug out."
486 iq.i = game.quadrant.i+(look.i+(QUADSIZE-1))/QUADSIZE - 1
487 iq.j = game.quadrant.j+(look.j+(QUADSIZE-1))/QUADSIZE - 1
488 if not welcoming(iq):
490 if enemy.type == 'R':
491 return False # Romulans cannot escape!
493 # avoid intruding on another commander's territory
494 if enemy.type == 'C':
495 if iq in game.state.kcmdr:
497 # refuse to leave if currently attacking starbase
498 if game.battle == game.quadrant:
500 # don't leave if over 1000 units of energy
501 if enemy.power > 1000.0:
503 oldloc = copy.copy(enemy.location)
504 # handle local matters related to escape
507 if game.condition != "docked":
509 # Handle global matters related to escape
510 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
511 game.state.galaxy[iq.i][iq.j].klingons += 1
512 if enemy.type == 'S':
516 schedule(FSCMOVE, 0.2777)
518 game.state.kscmdr = iq
520 for cmdr in game.state.kcmdr:
521 if cmdr == game.quadrant:
522 game.state.kcmdr.append(iq)
524 # report move out of quadrant.
525 return [(True, enemy, oldloc, iq)]
527 # The bad-guy movement algorithm:
529 # 1. Enterprise has "force" based on condition of phaser and photon torpedoes.
530 # If both are operating full strength, force is 1000. If both are damaged,
531 # force is -1000. Having shields down subtracts an additional 1000.
533 # 2. Enemy has forces equal to the energy of the attacker plus
534 # 100*(K+R) + 500*(C+S) - 400 for novice through good levels OR
535 # 346*K + 400*R + 500*(C+S) - 400 for expert and emeritus.
537 # Attacker Initial energy levels (nominal):
538 # Klingon Romulan Commander Super-Commander
539 # Novice 400 700 1200
541 # Good 450 800 1300 1750
542 # Expert 475 850 1350 1875
543 # Emeritus 500 900 1400 2000
544 # VARIANCE 75 200 200 200
546 # Enemy vessels only move prior to their attack. In Novice - Good games
547 # only commanders move. In Expert games, all enemy vessels move if there
548 # is a commander present. In Emeritus games all enemy vessels move.
550 # 3. If Enterprise is not docked, an aggressive action is taken if enemy
551 # forces are 1000 greater than Enterprise.
553 # Agressive action on average cuts the distance between the ship and
554 # the enemy to 1/4 the original.
556 # 4. At lower energy advantage, movement units are proportional to the
557 # advantage with a 650 advantage being to hold ground, 800 to move forward
558 # 1, 950 for two, 150 for back 4, etc. Variance of 100.
560 # If docked, is reduced by roughly 1.75*game.skill, generally forcing a
561 # retreat, especially at high skill levels.
563 # 5. Motion is limited to skill level, except for SC hi-tailing it out.
565 def movebaddy(enemy):
566 "Tactical movement for the bad guys."
570 # This should probably be just (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
571 if game.skill >= SKILL_EXPERT:
572 nbaddys = (((game.quadrant in game.state.kcmdr)*2 + (game.state.kscmdr==game.quadrant)*2+game.klhere*1.23+game.irhere*1.5)/2.0)
574 nbaddys = (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
575 old_dist = enemy.kdist
576 mdist = int(old_dist + 0.5) # Nearest integer distance
577 # If SC, check with spy to see if should hi-tail it
578 if enemy.type == 'S' and \
579 (enemy.power <= 500.0 or (game.condition=="docked" and not damaged(DPHOTON))):
583 # decide whether to advance, retreat, or hold position
584 forces = enemy.power+100.0*len(game.enemies)+400*(nbaddys-1)
586 forces += 1000 # Good for enemy if shield is down!
587 if not damaged(DPHASER) or not damaged(DPHOTON):
588 if damaged(DPHASER): # phasers damaged
591 forces -= 0.2*(game.energy - 2500.0)
592 if damaged(DPHOTON): # photon torpedoes damaged
595 forces -= 50.0*game.torps
597 # phasers and photon tubes both out!
600 if forces <= 1000.0 and game.condition != "docked": # Typical situation
601 motion = ((forces + randreal(200))/150.0) - 5.0
603 if forces > 1000.0: # Very strong -- move in for kill
604 motion = (1.0 - randreal())**2 * old_dist + 1.0
605 if game.condition == "docked" and (game.options & OPTION_BASE): # protected by base -- back off !
606 motion -= game.skill*(2.0-randreal()**2)
608 proutn("=== MOTION = %d, FORCES = %1.2f, " % (motion, forces))
609 # don't move if no motion
612 # Limit motion according to skill
613 if abs(motion) > game.skill:
618 # calculate preferred number of steps
619 nsteps = abs(int(motion))
620 if motion > 0 and nsteps > mdist:
621 nsteps = mdist # don't overshoot
622 if nsteps > QUADSIZE:
623 nsteps = QUADSIZE # This shouldn't be necessary
625 nsteps = 1 # This shouldn't be necessary
627 proutn("NSTEPS = %d:" % nsteps)
628 # Compute preferred values of delta X and Y
629 m = game.sector - enemy.location
630 if 2.0 * abs(m.i) < abs(m.j):
632 if 2.0 * abs(m.j) < abs(game.sector.i-enemy.location.i):
634 m = (motion * m).sgn()
635 goto = enemy.location
637 for ll in range(nsteps):
639 proutn(" %d" % (ll+1))
640 # Check if preferred position available
651 attempts = 0 # Settle mysterious hang problem
652 while attempts < 20 and not success:
654 if look.i < 0 or look.i >= QUADSIZE:
656 return tryexit(enemy, look, irun)
657 if krawli == m.i or m.j == 0:
659 look.i = goto.i + krawli
661 elif look.j < 0 or look.j >= QUADSIZE:
663 return tryexit(enemy, look, irun)
664 if krawlj == m.j or m.i == 0:
666 look.j = goto.j + krawlj
668 elif (game.options & OPTION_RAMMING) and game.quad[look.i][look.j] != '.':
669 # See if enemy should ram ship
670 if game.quad[look.i][look.j] == game.ship and \
671 (enemy.type == 'C' or enemy.type == 'S'):
672 collision(rammed=True, enemy=enemy)
674 if krawli != m.i and m.j != 0:
675 look.i = goto.i + krawli
677 elif krawlj != m.j and m.i != 0:
678 look.j = goto.j + krawlj
681 break # we have failed
692 # Enemy moved, but is still in sector
693 return [(False, enemy, old_dist, goto)]
696 "Sequence Klingon tactical movement."
699 # Figure out which Klingon is the commander (or Supercommander)
702 if game.quadrant in game.state.kcmdr:
703 for enemy in game.enemies:
704 if enemy.type == 'C':
705 tacmoves += movebaddy(enemy)
706 if game.state.kscmdr == game.quadrant:
707 for enemy in game.enemies:
708 if enemy.type == 'S':
709 tacmoves += movebaddy(enemy)
711 # If skill level is high, move other Klingons and Romulans too!
712 # Move these last so they can base their actions on what the
714 if game.skill >= SKILL_EXPERT and (game.options & OPTION_MVBADDY):
715 for enemy in game.enemies:
716 if enemy.type in ('K', 'R'):
717 tacmoves += movebaddy(enemy)
720 def movescom(iq, avoid):
721 "Supercommander movement helper."
722 # Avoid quadrants with bases if we want to avoid Enterprise
723 if not welcoming(iq) or (avoid and iq in game.state.baseq):
725 if game.justin and not game.iscate:
728 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons -= 1
729 game.state.kscmdr = iq
730 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons += 1
731 if game.state.kscmdr == game.quadrant:
732 # SC has scooted, remove him from current quadrant
737 for enemy in game.enemies:
738 if enemy.type == 'S':
741 if game.condition != "docked":
744 # check for a helpful planet
745 for i in range(game.inplan):
746 if game.state.planets[i].quadrant == game.state.kscmdr and \
747 game.state.planets[i].crystals == "present":
749 game.state.planets[i].pclass = "destroyed"
750 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].planet = None
753 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
754 proutn(_(" a planet in Quadrant %s has been destroyed") % game.state.kscmdr)
755 prout(_(" by the Super-commander.\""))
757 return True # looks good!
759 def supercommander():
760 "Move the Super Commander."
767 prout("== SUPERCOMMANDER")
768 # Decide on being active or passive
769 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 \
770 (game.state.date-game.indate) < 3.0)
771 if not game.iscate and avoid:
772 # compute move away from Enterprise
773 idelta = game.state.kscmdr-game.quadrant
774 if idelta.distance() > 2.0:
776 idelta.i = game.state.kscmdr.j-game.quadrant.j
777 idelta.j = game.quadrant.i-game.state.kscmdr.i
779 # compute distances to starbases
780 if not game.state.baseq:
784 sc = game.state.kscmdr
785 for (i, base) in enumerate(game.state.baseq):
786 basetbl.append((i, (base - sc).distance()))
787 if game.state.baseq > 1:
788 basetbl.sort(key=lambda x: x[1])
789 # look for nearest base without a commander, no Enterprise, and
790 # without too many Klingons, and not already under attack.
791 ifindit = iwhichb = 0
792 for (i2, base) in enumerate(game.state.baseq):
793 i = basetbl[i2][0] # bug in original had it not finding nearest
794 if base == game.quadrant or base == game.battle or not welcoming(base):
796 # if there is a commander, and no other base is appropriate,
797 # we will take the one with the commander
798 for cmdr in game.state.kcmdr:
799 if base == cmdr and ifindit != 2:
803 else: # no commander -- use this one
808 return # Nothing suitable -- wait until next time
809 ibq = game.state.baseq[iwhichb]
810 # decide how to move toward base
811 idelta = ibq - game.state.kscmdr
812 # Maximum movement is 1 quadrant in either or both axes
813 idelta = idelta.sgn()
814 # try moving in both x and y directions
815 # there was what looked like a bug in the Almy C code here,
816 # but it might be this translation is just wrong.
817 iq = game.state.kscmdr + idelta
818 if not movescom(iq, avoid):
819 # failed -- try some other maneuvers
820 if idelta.i == 0 or idelta.j == 0:
823 iq.j = game.state.kscmdr.j + 1
824 if not movescom(iq, avoid):
825 iq.j = game.state.kscmdr.j - 1
828 iq.i = game.state.kscmdr.i + 1
829 if not movescom(iq, avoid):
830 iq.i = game.state.kscmdr.i - 1
833 # try moving just in x or y
834 iq.j = game.state.kscmdr.j
835 if not movescom(iq, avoid):
836 iq.j = game.state.kscmdr.j + idelta.j
837 iq.i = game.state.kscmdr.i
840 if len(game.state.baseq) == 0:
843 for ibq in game.state.baseq:
844 if ibq == game.state.kscmdr and game.state.kscmdr == game.battle:
847 return # no, don't attack base!
850 schedule(FSCDBAS, randreal(1.0, 3.0))
851 if is_scheduled(FCDBAS):
852 postpone(FSCDBAS, scheduled(FCDBAS)-game.state.date)
853 if not communicating():
857 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") \
859 prout(_(" reports that it is under attack from the Klingon Super-commander."))
860 proutn(_(" It can survive until stardate %d.\"") \
861 % int(scheduled(FSCDBAS)))
864 prout(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
868 game.optime = 0.0 # actually finished
870 # Check for intelligence report
871 if not game.idebug and \
873 (not communicating()) or \
874 not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].charted):
877 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
878 proutn(_(" the Super-commander is in Quadrant %s,") % game.state.kscmdr)
883 if not game.tholian or game.justin:
886 if game.tholian.location.i == 0 and game.tholian.location.j == 0:
889 elif game.tholian.location.i == 0 and game.tholian.location.j == QUADSIZE-1:
892 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == QUADSIZE-1:
895 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == 0:
899 # something is wrong!
900 game.tholian.move(None)
901 prout("***Internal error: Tholian in a bad spot.")
903 # do nothing if we are blocked
904 if game.quad[tid.i][tid.j] not in ('.', '#'):
906 here = copy.copy(game.tholian.location)
907 delta = (tid - game.tholian.location).sgn()
909 while here.i != tid.i:
911 if game.quad[here.i][here.j] == '.':
912 game.tholian.move(here)
914 while here.j != tid.j:
916 if game.quad[here.i][here.j] == '.':
917 game.tholian.move(here)
918 # check to see if all holes plugged
919 for i in range(QUADSIZE):
920 if game.quad[0][i] != '#' and game.quad[0][i] != 'T':
922 if game.quad[QUADSIZE-1][i] != '#' and game.quad[QUADSIZE-1][i] != 'T':
924 if game.quad[i][0] != '#' and game.quad[i][0] != 'T':
926 if game.quad[i][QUADSIZE-1] != '#' and game.quad[i][QUADSIZE-1] != 'T':
928 # All plugged up -- Tholian splits
929 game.quad[game.tholian.location.i][game.tholian.location.j] = '#'
931 prout(crmena(True, 'T', "sector", game.tholian) + _(" completes web."))
932 game.tholian.move(None)
935 # Code from battle.c begins here
938 "Change cloaking-device status."
940 prout(_("Ye Faerie Queene hath no cloaking device."));
943 key = scanner.nexttok()
951 if scanner.sees("on"):
953 prout(_("The cloaking device has already been switched on."))
956 elif scanner.sees("off"):
957 if not game.iscloaked:
958 prout(_("The cloaking device has already been switched off."))
965 if not game.iscloaked:
966 proutn(_("Switch cloaking device on? "))
971 proutn(_("Switch cloaking device off? "))
978 if action == "CLOFF":
979 if game.irhere and game.state.date >= ALGERON and not game.isviolreported:
980 prout(_("Spock- \"Captain, the Treaty of Algeron is in effect.\n Are you sure this is wise?\""))
983 prout("Engineer Scott- \"Aye, Sir.\"");
984 game.iscloaked = False;
985 if game.irhere and game.state.date >= ALGERON and not game.isviolreported:
986 prout(_("The Romulan ship discovers you are breaking the Treaty of Algeron!"))
988 game.isviolreported = True
990 #if (neutz and game.state.date >= ALGERON) finish(FCLOAK);
995 prout(_("Engineer Scott- \"The cloaking device is damaged, Sir.\""))
998 if game.condition == "docked":
999 prout(_("You cannot cloak while docked."))
1001 if game.state.date >= ALGERON and not game.isviolreported:
1002 prout(_("Spock- \"Captain, using the cloaking device is a violation"))
1003 prout(_(" of the Treaty of Algeron. Considering the alternatives,"))
1004 proutn(_(" are you sure this is wise? "))
1007 prout(_("Engineer Scott- \"Cloaking device has engaging, Sir...\""))
1009 prout(_("Engineer Scott- \"Cloaking device has engaged, Sir.\""))
1010 game.iscloaked = True
1012 if game.irhere and game.state.date >= ALGERON and not game.isviolreported:
1013 prout(_("The Romulan ship discovers you are breaking the Treaty of Algeron!"))
1015 game.isviolreported = True
1017 def doshield(shraise):
1018 "Change shield status."
1024 key = scanner.nexttok()
1025 if key == "IHALPHA":
1026 if scanner.sees("transfer"):
1029 if damaged(DSHIELD):
1030 prout(_("Shields damaged and down."))
1032 if scanner.sees("up"):
1034 elif scanner.sees("down"):
1036 if action == "NONE":
1037 proutn(_("Do you wish to change shield energy? "))
1040 elif damaged(DSHIELD):
1041 prout(_("Shields damaged and down."))
1044 proutn(_("Shields are up. Do you want them down? "))
1051 proutn(_("Shields are down. Do you want them up? "))
1057 if action == "SHUP": # raise shields
1059 prout(_("Shields already up."))
1063 if game.condition != "docked":
1065 prout(_("Shields raised."))
1066 if game.energy <= 0:
1068 prout(_("Shields raising uses up last of energy."))
1073 elif action == "SHDN":
1075 prout(_("Shields already down."))
1079 prout(_("Shields lowered."))
1082 elif action == "NRG":
1083 while scanner.nexttok() != "IHREAL":
1085 proutn(_("Energy to transfer to shields- "))
1090 if nrg > game.energy:
1091 prout(_("Insufficient ship energy."))
1094 if game.shield+nrg >= game.inshld:
1095 prout(_("Shield energy maximized."))
1096 if game.shield+nrg > game.inshld:
1097 prout(_("Excess energy requested returned to ship energy"))
1098 game.energy -= game.inshld-game.shield
1099 game.shield = game.inshld
1101 if nrg < 0.0 and game.energy-nrg > game.inenrg:
1102 # Prevent shield drain loophole
1104 prout(_("Engineering to bridge--"))
1105 prout(_(" Scott here. Power circuit problem, Captain."))
1106 prout(_(" I can't drain the shields."))
1109 if game.shield+nrg < 0:
1110 prout(_("All shield energy transferred to ship."))
1111 game.energy += game.shield
1114 proutn(_("Scotty- \""))
1116 prout(_("Transferring energy to shields.\""))
1118 prout(_("Draining energy from shields.\""))
1124 "Choose a device to damage, at random."
1126 105, # DSRSENS: short range scanners 10.5%
1127 105, # DLRSENS: long range scanners 10.5%
1128 120, # DPHASER: phasers 12.0%
1129 120, # DPHOTON: photon torpedoes 12.0%
1130 25, # DLIFSUP: life support 2.5%
1131 65, # DWARPEN: warp drive 6.5%
1132 70, # DIMPULS: impulse engines 6.5%
1133 135, # DSHIELD: deflector shields 13.5%
1134 30, # DRADIO: subspace radio 3.0%
1135 45, # DSHUTTL: shuttle 4.5%
1136 15, # DCOMPTR: computer 1.5%
1137 20, # NAVCOMP: navigation system 2.0%
1138 75, # DTRANSP: transporter 7.5%
1139 20, # DSHCTRL: high-speed shield controller 2.0%
1140 10, # DDRAY: death ray 1.0%
1141 30, # DDSP: deep-space probes 3.0%
1142 10, # DCLOAK: the cloaking device 1.0
1144 assert(sum(weights) == 1000)
1145 idx = randrange(1000)
1147 for (i, w) in enumerate(weights):
1151 return None # we should never get here
1153 def collision(rammed, enemy):
1154 "Collision handling for rammong events."
1155 prouts(_("***RED ALERT! RED ALERT!"))
1157 prout(_("***COLLISION IMMINENT."))
1161 hardness = {'R':1.5, 'C':2.0, 'S':2.5, 'T':0.5, '?':4.0}.get(enemy.type, 1.0)
1163 proutn(_(" rammed by "))
1166 proutn(crmena(False, enemy.type, "sector", enemy.location))
1168 proutn(_(" (original position)"))
1170 deadkl(enemy.location, enemy.type, game.sector)
1171 proutn("***" + crmshp() + " heavily damaged.")
1172 icas = randrange(10, 30)
1173 prout(_("***Sickbay reports %d casualties") % icas)
1175 game.state.crew -= icas
1176 # In the pre-SST2K version, all devices got equiprobably damaged,
1177 # which was silly. Instead, pick up to half the devices at
1178 # random according to our weighting table,
1179 ncrits = randrange(NDEVICES/2)
1183 if game.damage[dev] < 0:
1185 extradm = (10.0*hardness*randreal()+1.0)*game.damfac
1186 # Damage for at least time of travel!
1187 game.damage[dev] += game.optime + extradm
1189 prout(_("***Shields are down."))
1197 def torpedo(origin, bearing, dispersion, number, nburst):
1198 "Let a photon torpedo fly"
1199 if not damaged(DSRSENS) or game.condition == "docked":
1200 setwnd(srscan_window)
1202 setwnd(message_window)
1203 ac = bearing + 0.25*dispersion # dispersion is a random variable
1204 bullseye = (15.0 - bearing)*0.5235988
1205 track = course(bearing=ac, distance=QUADSIZE, origin=cartesian(origin))
1206 bumpto = Coord(0, 0)
1207 # Loop to move a single torpedo
1208 setwnd(message_window)
1209 for step in range(1, QUADSIZE*2):
1210 if not track.nexttok():
1213 if not w.valid_sector():
1215 iquad = game.quad[w.i][w.j]
1216 tracktorpedo(w, step, number, nburst, iquad)
1220 setwnd(message_window)
1221 if not damaged(DSRSENS) or game.condition == "docked":
1222 skip(1) # start new line after text track
1223 if iquad in ('E', 'F'): # Hit our ship
1225 prout(_("Torpedo hits %s.") % crmshp())
1226 hit = 700.0 + randreal(100) - \
1227 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1228 newcnd() # we're blown out of dock
1229 if game.landed or game.condition == "docked":
1230 return hit # Cheat if on a planet
1231 # In the C/FORTRAN version, dispersion was 2.5 radians, which
1232 # is 143 degrees, which is almost exactly 4.8 clockface units
1233 displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
1234 displacement.nexttok()
1235 bumpto = displacement.sector()
1236 if not bumpto.valid_sector():
1238 if game.quad[bumpto.i][bumpto.j] == ' ':
1241 if game.quad[bumpto.i][bumpto.j] != '.':
1242 # can't move into object
1244 game.sector = bumpto
1246 game.quad[w.i][w.j] = '.'
1247 game.quad[bumpto.i][bumpto.j] = iquad
1248 prout(_(" displaced by blast to Sector %s ") % bumpto)
1249 for enemy in game.enemies:
1250 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1253 elif iquad in ('C', 'S', 'R', 'K'): # Hit a regular enemy
1255 if iquad in ('C', 'S') and withprob(0.05):
1256 prout(crmena(True, iquad, "sector", w) + _(" uses anti-photon device;"))
1257 prout(_(" torpedo neutralized."))
1259 for enemy in game.enemies:
1260 if w == enemy.location:
1261 kp = math.fabs(enemy.power)
1262 h1 = 700.0 + randrange(100) - \
1263 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1271 if enemy.power == 0:
1274 proutn(crmena(True, iquad, "sector", w))
1275 displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
1276 displacement.nexttok()
1277 bumpto = displacement.sector()
1278 if not bumpto.valid_sector():
1279 prout(_(" damaged but not destroyed."))
1281 if game.quad[bumpto.i][bumpto.j] == ' ':
1282 prout(_(" buffeted into black hole."))
1283 deadkl(w, iquad, bumpto)
1284 if game.quad[bumpto.i][bumpto.j] != '.':
1285 prout(_(" damaged but not destroyed."))
1287 prout(_(" damaged-- displaced by blast to Sector %s ")%bumpto)
1288 enemy.location = bumpto
1289 game.quad[w.i][w.j] = '.'
1290 game.quad[bumpto.i][bumpto.j] = iquad
1291 for enemy in game.enemies:
1292 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1296 prout("Internal error, no enemy where expected!")
1299 elif iquad == 'B': # Hit a base
1301 prout(_("***STARBASE DESTROYED.."))
1302 game.state.baseq = [x for x in game.state.baseq if x != game.quadrant]
1303 game.quad[w.i][w.j] = '.'
1304 game.base.invalidate()
1305 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
1306 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = False
1307 game.state.basekl += 1
1310 elif iquad == 'P': # Hit a planet
1311 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1312 game.state.nplankl += 1
1313 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1314 game.iplnet.pclass = "destroyed"
1316 game.plnet.invalidate()
1317 game.quad[w.i][w.j] = '.'
1319 # captain perishes on planet
1322 elif iquad == '@': # Hit an inhabited world -- very bad!
1323 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1324 game.state.nworldkl += 1
1325 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1326 game.iplnet.pclass = "destroyed"
1328 game.plnet.invalidate()
1329 game.quad[w.i][w.j] = '.'
1331 # captain perishes on planet
1333 prout(_("The torpedo destroyed an inhabited planet."))
1335 elif iquad == '*': # Hit a star
1339 prout(crmena(True, '*', "sector", w) + _(" unaffected by photon blast."))
1341 elif iquad == '?': # Hit a thingy
1342 if not (game.options & OPTION_THINGY) or withprob(0.3):
1344 prouts(_("AAAAIIIIEEEEEEEEAAAAAAAAUUUUUGGGGGHHHHHHHHHHHH!!!"))
1346 prouts(_(" HACK! HACK! HACK! *CHOKE!* "))
1348 proutn(_("Mr. Spock-"))
1349 prouts(_(" \"Fascinating!\""))
1353 # Stas Sergeev added the possibility that
1354 # you can shove the Thingy and piss it off.
1355 # It then becomes an enemy and may fire at you.
1358 elif iquad == ' ': # Black hole
1360 prout(crmena(True, ' ', "sector", w) + _(" swallows torpedo."))
1362 elif iquad == '#': # hit the web
1364 prout(_("***Torpedo absorbed by Tholian web."))
1366 elif iquad == 'T': # Hit a Tholian
1367 h1 = 700.0 + randrange(100) - \
1368 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1371 game.quad[w.i][w.j] = '.'
1376 proutn(crmena(True, 'T', "sector", w))
1378 prout(_(" survives photon blast."))
1380 prout(_(" disappears."))
1381 game.tholian.move(None)
1382 game.quad[w.i][w.j] = '#'
1387 proutn("Don't know how to handle torpedo collision with ")
1388 proutn(crmena(True, iquad, "sector", w))
1393 setwnd(message_window)
1394 prout(_("Torpedo missed."))
1398 "Critical-hit resolution."
1399 if hit < (275.0-25.0*game.skill)*randreal(1.0, 1.5):
1401 ncrit = int(1.0 + hit/(500.0+randreal(100)))
1402 proutn(_("***CRITICAL HIT--"))
1403 # Select devices and cause damage
1408 # Cheat to prevent shuttle damage unless on ship
1409 if not (game.damage[j]<0.0 or (j == DSHUTTL and game.iscraft != "onship") or (j == DCLOAK and game.ship != 'E' or j == DDRAY)):
1412 extradm = (hit*game.damfac)/(ncrit*randreal(75, 100))
1413 game.damage[j] += extradm
1416 for (i, j) in enumerate(cdam):
1418 if skipcount % 3 == 2 and i < len(cdam)-1:
1423 prout(_(" damaged."))
1424 if damaged(DSHIELD) and game.shldup:
1425 prout(_("***Shields knocked down."))
1427 if damaged(DCLOAK) and game.iscloaked:
1428 prout(_("***Cloaking device rendered inoperative."))
1429 game.iscloaked = False
1431 def attack(torps_ok):
1432 # bad guy attacks us
1433 # torps_ok == False forces use of phasers in an attack
1436 # game could be over at this point, check
1446 prout("=== ATTACK!")
1447 # Tholian gets to move before attacking
1450 # if you have just entered the RNZ, you'll get a warning
1451 if game.neutz: # The one chance not to be attacked
1454 # commanders get a chance to tac-move towards you
1455 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:
1456 for (bugout, enemy, old, goto) in moveklings():
1458 # we know about this if either short or long range
1459 # sensors are working
1460 if damaged(DSRSENS) and damaged(DLRSENS) \
1461 and game.condition != "docked":
1462 prout(crmena(True, enemy.type, "sector", old) + \
1463 (_(" escapes to Quadrant %s (and regains strength).") % goto))
1464 else: # Enemy still in-sector
1465 if enemy.move(goto):
1466 if not damaged(DSRSENS) or game.condition == "docked":
1467 proutn(_("*** %s from Sector %s") % (cramen(enemy.type), enemy.location))
1468 if enemy.kdist < old:
1469 proutn(_(" advances to "))
1471 proutn(_(" retreats to "))
1472 prout("Sector %s." % goto)
1474 # if no enemies remain after movement, we're done
1475 if len(game.enemies) == 0 or (len(game.enemies) == 1 and thing.at(game.quadrant) and not thing.angered):
1477 # set up partial hits if attack happens during shield status change
1478 pfac = 1.0/game.inshld
1480 chgfac = 0.25 + randreal(0.5)
1482 # message verbosity control
1483 if game.skill <= SKILL_FAIR:
1485 for enemy in game.enemies:
1487 continue # too weak to attack
1488 # compute hit strength and diminish shield power
1490 # Increase chance of photon torpedos if docked or enemy energy is low
1491 if game.condition == "docked":
1493 if enemy.power < 500:
1495 if enemy.type == 'T' or (enemy.type == '?' and not thing.angered):
1497 # different enemies have different probabilities of throwing a torp
1498 usephasers = not torps_ok or \
1499 (enemy.type == 'K' and r > 0.0005) or \
1500 (enemy.type == 'C' and r > 0.015) or \
1501 (enemy.type == 'R' and r > 0.3) or \
1502 (enemy.type == 'S' and r > 0.07) or \
1503 (enemy.type == '?' and r > 0.05)
1504 if usephasers: # Enemy uses phasers
1505 if game.condition == "docked":
1506 continue # Don't waste the effort!
1507 attempt = True # Attempt to attack
1508 dustfac = randreal(0.8, 0.85)
1509 hit = enemy.power*math.pow(dustfac, enemy.kavgd)
1511 else: # Enemy uses photon torpedo
1512 # We should be able to make the bearing() method work here
1513 pcourse = 1.90985*math.atan2(game.sector.j-enemy.location.j, enemy.location.i-game.sector.i)
1515 proutn(_("***TORPEDO INCOMING"))
1516 if not damaged(DSRSENS):
1517 proutn(_(" From ") + crmena(False, enemy.type, where, enemy.location))
1520 dispersion = (randreal()+randreal())*0.5 - 0.5
1521 dispersion += 0.002*enemy.power*dispersion
1522 hit = torpedo(enemy.location, pcourse, dispersion, number=1, nburst=1)
1523 if game.unwon() == 0:
1524 finish(FWON) # Klingons did themselves in!
1525 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.alldone:
1526 return # Supernova or finished
1529 # incoming phaser or torpedo, shields may dissipate it
1530 if game.shldup or game.shldchg or game.condition == "docked":
1531 # shields will take hits
1532 propor = pfac * game.shield
1533 if game.condition == "docked":
1537 hitsh = propor*chgfac*hit+1.0
1539 if absorb > game.shield:
1540 absorb = game.shield
1541 game.shield -= absorb
1543 # taking a hit blasts us out of a starbase dock
1544 if game.condition == "docked":
1546 # but the shields may take care of it
1547 if propor > 0.1 and hit < 0.005*game.energy:
1549 # hit from this opponent got through shields, so take damage
1551 proutn(_("%d unit hit") % int(hit))
1552 if (damaged(DSRSENS) and usephasers) or game.skill<=SKILL_FAIR:
1553 proutn(_(" on the ") + crmshp())
1554 if not damaged(DSRSENS) and usephasers:
1555 prout(_(" from ") + crmena(False, enemy.type, where, enemy.location))
1557 # Decide if hit is critical
1563 if game.energy <= 0:
1564 # Returning home upon your shield, not with it...
1567 if not attempt and game.condition == "docked":
1568 prout(_("***Enemies decide against attacking your ship."))
1569 percent = 100.0*pfac*game.shield+0.5
1571 # Shields fully protect ship
1572 proutn(_("Enemy attack reduces shield strength to "))
1574 # Emit message if starship suffered hit(s)
1576 proutn(_("Energy left %2d shields ") % int(game.energy))
1579 elif not damaged(DSHIELD):
1582 proutn(_("damaged, "))
1583 prout(_("%d%%, torpedoes left %d") % (percent, game.torps))
1584 # Check if anyone was hurt
1585 if hitmax >= 200 or hittot >= 500:
1586 icas = randrange(int(hittot * 0.015))
1589 prout(_("Mc Coy- \"Sickbay to bridge. We suffered %d casualties") % icas)
1590 prout(_(" in that last attack.\""))
1592 game.state.crew -= icas
1593 # After attack, reset average distance to enemies
1594 for enemy in game.enemies:
1595 enemy.kavgd = enemy.kdist
1599 def deadkl(w, etype, mv):
1600 "Kill a Klingon, Tholian, Romulan, or Thingy."
1601 # Added mv to allow enemy to "move" before dying
1602 proutn(crmena(True, etype, "sector", mv))
1603 # Decide what kind of enemy it is and update appropriately
1605 # Chalk up a Romulan
1606 game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans -= 1
1608 game.state.nromrem -= 1
1617 # Killed some type of Klingon
1618 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
1621 game.state.kcmdr.remove(game.quadrant)
1623 if game.state.kcmdr:
1624 schedule(FTBEAM, expran(1.0*game.incom/len(game.state.kcmdr)))
1625 if is_scheduled(FCDBAS) and game.battle == game.quadrant:
1630 game.state.nscrem -= 1
1631 game.state.kscmdr.invalidate()
1636 # For each kind of enemy, finish message to player
1637 prout(_(" destroyed."))
1638 if game.unwon() == 0:
1641 # Remove enemy ship from arrays describing local conditions
1642 for e in game.enemies:
1649 "Return None if target is invalid, otherwise return a course angle."
1650 if not w.valid_sector():
1654 # C code this was translated from is wacky -- why the sign reversal?
1655 delta.j = (w.j - game.sector.j)
1656 delta.i = (game.sector.i - w.i)
1657 if delta == Coord(0, 0):
1659 prout(_("Spock- \"Bridge to sickbay. Dr. McCoy,"))
1660 prout(_(" I recommend an immediate review of"))
1661 prout(_(" the Captain's psychological profile.\""))
1664 return delta.bearing()
1667 "Launch photon torpedo salvo."
1670 if damaged(DPHOTON):
1671 prout(_("Photon tubes damaged."))
1675 prout(_("No torpedoes left."))
1678 # First, get torpedo count
1681 if scanner.token == "IHALPHA":
1684 elif scanner.token == "IHEOL" or not scanner.waiting():
1685 prout(_("%d torpedoes left.") % game.torps)
1687 proutn(_("Number of torpedoes to fire- "))
1688 continue # Go back around to get a number
1689 else: # key == "IHREAL"
1691 if n <= 0: # abort command
1696 prout(_("Maximum of %d torpedoes per burst.") % MAXBURST)
1699 scanner.chew() # User requested more torps than available
1700 continue # Go back around
1701 break # All is good, go to next stage
1705 key = scanner.nexttok()
1706 if i == 0 and key == "IHEOL":
1707 break # no coordinate waiting, we will try prompting
1708 if i == 1 and key == "IHEOL":
1709 # direct all torpedoes at one target
1711 target.append(target[0])
1712 tcourse.append(tcourse[0])
1715 scanner.push(scanner.token)
1716 target.append(scanner.getcoord())
1717 if target[-1] is None:
1719 tcourse.append(targetcheck(target[-1]))
1720 if tcourse[-1] is None:
1723 if len(target) == 0:
1724 # prompt for each one
1726 proutn(_("Target sector for torpedo number %d- ") % (i+1))
1728 target.append(scanner.getcoord())
1729 if target[-1] is None:
1731 tcourse.append(targetcheck(target[-1]))
1732 if tcourse[-1] is None:
1735 # Loop for moving <n> torpedoes
1737 if game.condition != "docked":
1739 dispersion = (randreal()+randreal())*0.5 -0.5
1740 if math.fabs(dispersion) >= 0.47:
1742 dispersion *= randreal(1.2, 2.2)
1744 prouts(_("***TORPEDO NUMBER %d MISFIRES") % (i+1))
1746 prouts(_("***TORPEDO MISFIRES."))
1749 prout(_(" Remainder of burst aborted."))
1751 prout(_("***Photon tubes damaged by misfire."))
1752 game.damage[DPHOTON] = game.damfac * randreal(1.0, 3.0)
1756 elif game.shldup or game.condition == "docked":
1757 dispersion *= 1.0 + 0.0001*game.shield
1758 torpedo(game.sector, tcourse[i], dispersion, number=i, nburst=n)
1759 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
1765 "Check for phasers overheating."
1767 checkburn = (rpow-1500.0)*0.00038
1768 if withprob(checkburn):
1769 prout(_("Weapons officer Sulu- \"Phasers overheated, sir.\""))
1770 game.damage[DPHASER] = game.damfac* randreal(1.0, 2.0) * (1.0+checkburn)
1772 def checkshctrl(rpow):
1773 "Check shield control."
1776 prout(_("Shields lowered."))
1778 # Something bad has happened
1779 prouts(_("***RED ALERT! RED ALERT!"))
1781 hit = rpow*game.shield/game.inshld
1782 game.energy -= rpow+hit*0.8
1783 game.shield -= hit*0.2
1784 if game.energy <= 0.0:
1785 prouts(_("Sulu- \"Captain! Shield malf***********************\""))
1790 prouts(_("Sulu- \"Captain! Shield malfunction! Phaser fire contained!\""))
1792 prout(_("Lt. Uhura- \"Sir, all decks reporting damage.\""))
1793 icas = randrange(int(hit*0.012))
1798 prout(_("McCoy to bridge- \"Severe radiation burns, Jim."))
1799 prout(_(" %d casualties so far.\"") % icas)
1801 game.state.crew -= icas
1803 prout(_("Phaser energy dispersed by shields."))
1804 prout(_("Enemy unaffected."))
1809 "Register a phaser hit on Klingons and Romulans."
1816 dustfac = randreal(0.9, 1.0)
1817 hit = wham*math.pow(dustfac, game.enemies[kk].kdist)
1818 kpini = game.enemies[kk].power
1819 kp = math.fabs(kpini)
1820 if PHASEFAC*hit < kp:
1822 if game.enemies[kk].power < 0:
1823 game.enemies[kk].power -= -kp
1825 game.enemies[kk].power -= kp
1826 kpow = game.enemies[kk].power
1827 w = game.enemies[kk].location
1829 if not damaged(DSRSENS):
1831 proutn(_("%d unit hit on ") % int(hit))
1833 proutn(_("Very small hit on "))
1834 ienm = game.quad[w.i][w.j]
1837 proutn(crmena(False, ienm, "sector", w))
1846 else: # decide whether or not to emasculate klingon
1847 if kpow > 0 and withprob(0.9) and kpow <= randreal(0.4, 0.8)*kpini:
1848 prout(_("***Mr. Spock- \"Captain, the vessel at Sector %s")%w)
1849 prout(_(" has just lost its firepower.\""))
1850 game.enemies[kk].power = -kpow
1855 "Fire phasers at bad guys."
1859 irec = 0 # Cheating inhibitor
1868 # SR sensors and Computer are needed for automode
1869 if damaged(DSRSENS) or damaged(DCOMPTR):
1871 if game.condition == "docked":
1872 prout(_("Phasers can't be fired through base shields."))
1875 if damaged(DPHASER):
1876 prout(_("Phaser control damaged."))
1880 if damaged(DSHCTRL):
1881 prout(_("High speed shield control damaged."))
1884 if game.energy <= 200.0:
1885 prout(_("Insufficient energy to activate high-speed shield control."))
1888 prout(_("Weapons Officer Sulu- \"High-speed shield control enabled, sir.\""))
1890 # Original code so convoluted, I re-did it all
1891 # (That was Tom Almy talking about the C code, I think -- ESR)
1892 while automode == "NOTSET":
1893 key = scanner.nexttok()
1894 if key == "IHALPHA":
1895 if scanner.sees("manual"):
1896 if len(game.enemies)==0:
1897 prout(_("There is no enemy present to select."))
1900 automode = "AUTOMATIC"
1903 key = scanner.nexttok()
1904 elif scanner.sees("automatic"):
1905 if (not itarg) and len(game.enemies) != 0:
1906 automode = "FORCEMAN"
1908 if len(game.enemies)==0:
1909 prout(_("Energy will be expended into space."))
1910 automode = "AUTOMATIC"
1911 key = scanner.nexttok()
1912 elif scanner.sees("no"):
1917 elif key == "IHREAL":
1918 if len(game.enemies)==0:
1919 prout(_("Energy will be expended into space."))
1920 automode = "AUTOMATIC"
1922 automode = "FORCEMAN"
1924 automode = "AUTOMATIC"
1927 if len(game.enemies)==0:
1928 prout(_("Energy will be expended into space."))
1929 automode = "AUTOMATIC"
1931 automode = "FORCEMAN"
1933 proutn(_("Manual or automatic? "))
1938 if automode == "AUTOMATIC":
1939 if key == "IHALPHA" and scanner.sees("no"):
1941 key = scanner.nexttok()
1942 if key != "IHREAL" and len(game.enemies) != 0:
1943 prout(_("Phasers locked on target. Energy available: %.2f")%avail)
1948 for i in range(len(game.enemies)):
1949 irec += math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))*randreal(1.01, 1.06) + 1.0
1951 proutn(_("%d units required. ") % irec)
1953 proutn(_("Units to fire= "))
1954 key = scanner.nexttok()
1959 proutn(_("Energy available= %.2f") % avail)
1962 if not rpow > avail:
1968 key = scanner.nexttok()
1969 if key == "IHALPHA" and scanner.sees("no"):
1972 game.energy -= 200 # Go and do it!
1973 if checkshctrl(rpow):
1978 if len(game.enemies):
1981 for i in range(len(game.enemies)):
1985 hits[i] = math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))
1986 over = randreal(1.01, 1.06) * hits[i]
1988 powrem -= hits[i] + over
1989 if powrem <= 0 and temp < hits[i]:
1998 if extra > 0 and not game.alldone:
2000 proutn(_("*** Tholian web absorbs "))
2001 if len(game.enemies)>0:
2002 proutn(_("excess "))
2003 prout(_("phaser energy."))
2005 prout(_("%d expended on empty space.") % int(extra))
2006 elif automode == "FORCEMAN":
2009 if damaged(DCOMPTR):
2010 prout(_("Battle computer damaged, manual fire only."))
2013 prouts(_("---WORKING---"))
2015 prout(_("Short-range-sensors-damaged"))
2016 prout(_("Insufficient-data-for-automatic-phaser-fire"))
2017 prout(_("Manual-fire-must-be-used"))
2019 elif automode == "MANUAL":
2021 for k in range(len(game.enemies)):
2022 aim = game.enemies[k].location
2023 ienm = game.quad[aim.i][aim.j]
2025 proutn(_("Energy available= %.2f") % (avail-0.006))
2029 if damaged(DSRSENS) and \
2030 not game.sector.distance(aim)<2**0.5 and ienm in ('C', 'S'):
2031 prout(cramen(ienm) + _(" can't be located without short range scan."))
2034 hits[k] = 0 # prevent overflow -- thanks to Alexei Voitenko
2039 if itarg and k > kz:
2040 irec = (abs(game.enemies[k].power)/(PHASEFAC*math.pow(0.9, game.enemies[k].kdist))) * randreal(1.01, 1.06) + 1.0
2043 if not damaged(DCOMPTR):
2048 proutn(_("units to fire at %s- ") % crmena(False, ienm, "sector", aim))
2049 key = scanner.nexttok()
2050 if key == "IHALPHA" and scanner.sees("no"):
2052 key = scanner.nexttok()
2054 if key == "IHALPHA":
2058 if k == 1: # Let me say I'm baffled by this
2061 if scanner.real < 0:
2065 hits[k] = scanner.real
2066 rpow += scanner.real
2067 # If total requested is too much, inform and start over
2069 prout(_("Available energy exceeded -- try again."))
2072 key = scanner.nexttok() # scan for next value
2075 # zero energy -- abort
2078 if key == "IHALPHA" and scanner.sees("no"):
2083 game.energy -= 200.0
2084 if checkshctrl(rpow):
2088 # Say shield raised or malfunction, if necessary
2095 prout(_("Sulu- \"Sir, the high-speed shield control has malfunctioned . . ."))
2096 prouts(_(" CLICK CLICK POP . . ."))
2097 prout(_(" No response, sir!"))
2100 prout(_("Shields raised."))
2107 game.ididit = False # Nothing if we fail
2110 # Make sure there is room in the brig */
2111 if game.brigfree == 0:
2112 prout(_("Security reports the brig is already full."))
2116 prout(_("Uhura- \"We have no subspace radio communication, sir.\""))
2119 if damaged(DTRANSP):
2120 prout(_("Scotty- \"Transporter damaged, sir.\""))
2123 # find out if there are any at all
2125 prout(_("Uhura- \"Getting no response, sir.\""))
2128 # if there is more than one Klingon, find out which one */
2129 # Cruddy, just takes one at random. Should ask the captain.
2130 # Nah, just select the weakest one since it is most likely to
2131 # surrender (Tom Almy mod)
2132 klingons = [e for e in game.enemies if e.type == 'K']
2133 weakest = sorted(klingons, key=lambda e: e.power)[0]
2134 game.optime = 0.05 # This action will take some time
2135 game.ididit = True # So any others can strike back
2137 # check out that Klingon
2138 # The algorithm isn't that great and could use some more
2139 # intelligent design
2140 # x = 300 + 25*skill;
2141 x = game.energy / (weakest.power * len(klingons))
2142 #prout(_("Stats: energy = %s, kpower = %s, klingons = %s")
2143 # % (game.energy, weakest.power, len(klingons)))
2144 x *= 2.5 # would originally have been equivalent of 1.4,
2145 # but we want command to work more often, more humanely */
2146 #prout(_("Prob = %.4f" % x))
2147 # x = 100; // For testing, of course!
2148 if x < randreal(100):
2149 # guess what, he surrendered!!! */
2150 prout(_("Klingon captain at %s surrenders.") % weakest.location)
2153 prout(_("%d Klingons commit suicide rather than be taken captive.") % (200 - i))
2154 if i > game.brigfree:
2155 prout(_("%d Klingons die because there is no room for them in the brig.") % (i-brigfree))
2158 prout(_("%d captives taken") % i)
2159 deadkl(weakest.location, weakest.type, game.sector)
2164 # big surprise, he refuses to surrender */
2165 prout(_("Fat chance, captain!"))
2167 # Code from events.c begins here.
2169 # This isn't a real event queue a la BSD Trek yet -- you can only have one
2170 # event of each type active at any given time. Mostly these means we can
2171 # only have one FDISTR/FENSLV/FREPRO sequence going at any given time
2172 # BSD Trek, from which we swiped the idea, can have up to 5.
2174 def unschedule(evtype):
2175 "Remove an event from the schedule."
2176 game.future[evtype].date = FOREVER
2177 return game.future[evtype]
2179 def is_scheduled(evtype):
2180 "Is an event of specified type scheduled."
2181 return game.future[evtype].date != FOREVER
2183 def scheduled(evtype):
2184 "When will this event happen?"
2185 return game.future[evtype].date
2187 def schedule(evtype, offset):
2188 "Schedule an event of specified type."
2189 game.future[evtype].date = game.state.date + offset
2190 return game.future[evtype]
2192 def postpone(evtype, offset):
2193 "Postpone a scheduled event."
2194 game.future[evtype].date += offset
2197 "Rest period is interrupted by event."
2200 proutn(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
2202 game.resting = False
2208 "Run through the event queue looking for things to do."
2210 fintim = game.state.date + game.optime
2219 def tractorbeam(yank):
2220 "Tractor-beaming cases merge here."
2222 game.optime = (10.0/(7.5*7.5))*yank # 7.5 is yank rate (warp 7.5)
2224 prout("***" + crmshp() + _(" caught in long range tractor beam--"))
2225 # If Kirk & Co. screwing around on planet, handle
2226 atover(True) # atover(true) is Grab
2229 if game.icraft: # Caught in Galileo?
2232 # Check to see if shuttle is aboard
2233 if game.iscraft == "offship":
2236 prout(_("Galileo, left on the planet surface, is captured"))
2237 prout(_("by aliens and made into a flying McDonald's."))
2238 game.damage[DSHUTTL] = -10
2239 game.iscraft = "removed"
2241 prout(_("Galileo, left on the planet surface, is well hidden."))
2243 game.quadrant = game.state.kscmdr
2245 game.quadrant = game.state.kcmdr[i]
2246 game.sector = randplace(QUADSIZE)
2247 prout(crmshp() + _(" is pulled to Quadrant %s, Sector %s") \
2248 % (game.quadrant, game.sector))
2250 prout(_("(Remainder of rest/repair period cancelled.)"))
2251 game.resting = False
2253 if not damaged(DSHIELD) and game.shield > 0:
2254 doshield(shraise=True) # raise shields
2255 game.shldchg = False
2257 prout(_("(Shields not currently useable.)"))
2259 # Adjust finish time to time of tractor beaming?
2260 # fintim = game.state.date+game.optime
2261 attack(torps_ok=False)
2262 if not game.state.kcmdr:
2265 schedule(FTBEAM, game.optime+expran(1.5*game.intime/len(game.state.kcmdr)))
2268 "Code merges here for any commander destroying a starbase."
2269 # Not perfect, but will have to do
2270 # Handle case where base is in same quadrant as starship
2271 if game.battle == game.quadrant:
2272 game.state.chart[game.battle.i][game.battle.j].starbase = False
2273 game.quad[game.base.i][game.base.j] = '.'
2274 game.base.invalidate()
2277 prout(_("Spock- \"Captain, I believe the starbase has been destroyed.\""))
2278 elif game.state.baseq and communicating():
2279 # Get word via subspace radio
2282 prout(_("Lt. Uhura- \"Captain, Starfleet Command reports that"))
2283 proutn(_(" the starbase in Quadrant %s has been destroyed by") % game.battle)
2285 prout(_("the Klingon Super-Commander"))
2287 prout(_("a Klingon Commander"))
2288 game.state.chart[game.battle.i][game.battle.j].starbase = False
2289 # Remove Starbase from galaxy
2290 game.state.galaxy[game.battle.i][game.battle.j].starbase = False
2291 game.state.baseq = [x for x in game.state.baseq if x != game.battle]
2293 # reinstate a commander's base attack
2297 game.battle.invalidate()
2299 prout("=== EVENTS from %.2f to %.2f:" % (game.state.date, fintim))
2300 for i in range(1, NEVENTS):
2301 if i == FSNOVA: proutn("=== Supernova ")
2302 elif i == FTBEAM: proutn("=== T Beam ")
2303 elif i == FSNAP: proutn("=== Snapshot ")
2304 elif i == FBATTAK: proutn("=== Base Attack ")
2305 elif i == FCDBAS: proutn("=== Base Destroy ")
2306 elif i == FSCMOVE: proutn("=== SC Move ")
2307 elif i == FSCDBAS: proutn("=== SC Base Destroy ")
2308 elif i == FDSPROB: proutn("=== Probe Move ")
2309 elif i == FDISTR: proutn("=== Distress Call ")
2310 elif i == FENSLV: proutn("=== Enslavement ")
2311 elif i == FREPRO: proutn("=== Klingon Build ")
2313 prout("%.2f" % (scheduled(i)))
2316 radio_was_broken = damaged(DRADIO)
2319 # Select earliest extraneous event, evcode==0 if no events
2324 for l in range(1, NEVENTS):
2325 if game.future[l].date < datemin:
2328 prout("== Event %d fires" % evcode)
2329 datemin = game.future[l].date
2330 xtime = datemin-game.state.date
2332 game.energy -= xtime*500.0
2333 if game.energy <= 0:
2336 game.state.date = datemin
2337 # Decrement Federation resources and recompute remaining time
2338 game.state.remres -= (game.remkl()+4*len(game.state.kcmdr))*xtime
2340 if game.state.remtime <= 0:
2343 # Any crew left alive?
2344 if game.state.crew <= 0:
2347 # Is life support adequate?
2348 if damaged(DLIFSUP) and game.condition != "docked":
2349 if game.lsupres < xtime and game.damage[DLIFSUP] > game.lsupres:
2352 game.lsupres -= xtime
2353 if game.damage[DLIFSUP] <= xtime:
2354 game.lsupres = game.inlsr
2357 if game.condition == "docked":
2359 # Don't fix Deathray here
2360 for l in range(NDEVICES):
2361 if game.damage[l] > 0.0 and l != DDRAY:
2362 if game.damage[l]-repair > 0.0:
2363 game.damage[l] -= repair
2365 game.damage[l] = 0.0
2366 # If radio repaired, update star chart and attack reports
2367 if radio_was_broken and not damaged(DRADIO):
2368 prout(_("Lt. Uhura- \"Captain, the sub-space radio is working and"))
2369 prout(_(" surveillance reports are coming in."))
2371 if not game.iseenit:
2375 prout(_(" The star chart is now up to date.\""))
2377 # Cause extraneous event EVCODE to occur
2378 game.optime -= xtime
2379 if evcode == FSNOVA: # Supernova
2382 schedule(FSNOVA, expran(0.5*game.intime))
2383 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2385 elif evcode == FSPY: # Check with spy to see if SC should tractor beam
2386 if game.state.nscrem == 0 or game.iscloaked or \
2387 ictbeam or istract or \
2388 game.condition == "docked" or game.isatb == 1 or game.iscate:
2390 if game.ientesc or \
2391 (game.energy<2000 and game.torps<4 and game.shield < 1250) or \
2392 (damaged(DPHASER) and (damaged(DPHOTON) or game.torps<4)) or \
2393 (damaged(DSHIELD) and \
2394 (game.energy < 2500 or damaged(DPHASER)) and \
2395 (game.torps < 5 or damaged(DPHOTON))):
2397 istract = ictbeam = True
2398 tractorbeam((game.state.kscmdr-game.quadrant).distance())
2401 elif evcode == FTBEAM: # Tractor beam
2402 if not game.state.kcmdr:
2405 i = randrange(len(game.state.kcmdr))
2406 yank = (game.state.kcmdr[i]-game.quadrant).distance()
2407 if istract or game.condition == "docked" or game.iscloaked or yank == 0:
2408 # Drats! Have to reschedule
2410 game.optime + expran(1.5*game.intime/len(game.state.kcmdr)))
2414 elif evcode == FSNAP: # Snapshot of the universe (for time warp)
2415 game.snapsht = copy.deepcopy(game.state)
2416 game.state.snap = True
2417 schedule(FSNAP, expran(0.5 * game.intime))
2418 elif evcode == FBATTAK: # Commander attacks starbase
2419 if not game.state.kcmdr or not game.state.baseq:
2424 ibq = None # Force battle location to persist past loop
2426 for ibq in game.state.baseq:
2427 for cmdr in game.state.kcmdr:
2428 if ibq == cmdr and ibq != game.quadrant and ibq != game.state.kscmdr:
2430 # no match found -- try later
2431 schedule(FBATTAK, expran(0.3*game.intime))
2436 # commander + starbase combination found -- launch attack
2438 schedule(FCDBAS, randreal(1.0, 4.0))
2439 if game.isatb: # extra time if SC already attacking
2440 postpone(FCDBAS, scheduled(FSCDBAS)-game.state.date)
2441 game.future[FBATTAK].date = game.future[FCDBAS].date + expran(0.3*game.intime)
2442 game.iseenit = False
2443 if not communicating():
2444 continue # No warning :-(
2448 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") % game.battle)
2449 prout(_(" reports that it is under attack and that it can"))
2450 prout(_(" hold out only until stardate %d.\"") % (int(scheduled(FCDBAS))))
2453 elif evcode == FSCDBAS: # Supercommander destroys base
2456 if not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].starbase:
2457 continue # WAS RETURN!
2459 game.battle = game.state.kscmdr
2461 elif evcode == FCDBAS: # Commander succeeds in destroying base
2462 if evcode == FCDBAS:
2464 if not game.state.baseq() \
2465 or not game.state.galaxy[game.battle.i][game.battle.j].starbase:
2466 game.battle.invalidate()
2468 # find the lucky pair
2469 for cmdr in game.state.kcmdr:
2470 if cmdr == game.battle:
2473 # No action to take after all
2476 elif evcode == FSCMOVE: # Supercommander moves
2477 schedule(FSCMOVE, 0.2777)
2478 if not game.ientesc and not istract and game.isatb != 1 and \
2479 (not game.iscate or not game.justin):
2481 elif evcode == FDSPROB: # Move deep space probe
2482 schedule(FDSPROB, 0.01)
2483 if not game.probe.nexttok():
2484 if not game.probe.quadrant().valid_quadrant() or \
2485 game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j].supernova:
2486 # Left galaxy or ran into supernova
2490 proutn(_("Lt. Uhura- \"The deep space probe "))
2491 if not game.probe.quadrant().valid_quadrant():
2492 prout(_("has left the galaxy.\""))
2494 prout(_("is no longer transmitting.\""))
2500 prout(_("Lt. Uhura- \"The deep space probe is now in Quadrant %s.\"") % game.probe.quadrant())
2501 pquad = game.probe.quadrant()
2502 pdest = game.state.galaxy[pquad.i][pquad.j]
2504 game.state.chart[pquad.i][pquad.j].klingons = pdest.klingons
2505 game.state.chart[pquad.i][pquad.j].starbase = pdest.starbase
2506 game.state.chart[pquad.i][pquad.j].stars = pdest.stars
2507 pdest.charted = True
2508 game.probe.moves -= 1 # One less to travel
2509 if game.probe.arrived() and game.isarmed and pdest.stars:
2510 supernova(game.probe) # fire in the hole!
2512 if game.state.galaxy[pquad.i][pquad.j].supernova:
2514 elif evcode == FDISTR: # inhabited system issues distress call
2516 # try a whole bunch of times to find something suitable
2517 for i in range(100):
2518 # need a quadrant which is not the current one,
2519 # which has some stars which are inhabited and
2520 # not already under attack, which is not
2521 # supernova'ed, and which has some Klingons in it
2522 w = randplace(GALSIZE)
2523 q = game.state.galaxy[w.i][w.j]
2524 if not (game.quadrant == w or q.planet is None or \
2525 not q.planet.inhabited or \
2526 q.supernova or q.status!="secure" or q.klingons<=0):
2529 # can't seem to find one; ignore this call
2531 prout("=== Couldn't find location for distress event.")
2533 # got one!! Schedule its enslavement
2534 ev = schedule(FENSLV, expran(game.intime))
2536 q.status = "distressed"
2537 # tell the captain about it if we can
2539 prout(_("Uhura- Captain, %s in Quadrant %s reports it is under attack") \
2540 % (q.planet, repr(w)))
2541 prout(_("by a Klingon invasion fleet."))
2544 elif evcode == FENSLV: # starsystem is enslaved
2545 ev = unschedule(FENSLV)
2546 # see if current distress call still active
2547 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2551 q.status = "enslaved"
2553 # play stork and schedule the first baby
2554 ev2 = schedule(FREPRO, expran(2.0 * game.intime))
2555 ev2.quadrant = ev.quadrant
2557 # report the disaster if we can
2559 prout(_("Uhura- We've lost contact with starsystem %s") % \
2561 prout(_("in Quadrant %s.\n") % ev.quadrant)
2562 elif evcode == FREPRO: # Klingon reproduces
2563 # If we ever switch to a real event queue, we'll need to
2564 # explicitly retrieve and restore the x and y.
2565 ev = schedule(FREPRO, expran(1.0 * game.intime))
2566 # see if current distress call still active
2567 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2571 if game.remkl() >= MAXKLGAME:
2572 continue # full right now
2573 # reproduce one Klingon
2576 if game.klhere >= MAXKLQUAD:
2578 # this quadrant not ok, pick an adjacent one
2579 for m.i in range(w.i - 1, w.i + 2):
2580 for m.j in range(w.j - 1, w.j + 2):
2581 if not m.valid_quadrant():
2583 q = game.state.galaxy[m.i][m.j]
2584 # check for this quad ok (not full & no snova)
2585 if q.klingons >= MAXKLQUAD or q.supernova:
2588 # search for eligible quadrant failed
2594 if game.quadrant == w:
2596 game.enemies.append(newkling())
2597 # recompute time left
2600 if game.quadrant == w:
2601 prout(_("Spock- sensors indicate the Klingons have"))
2602 prout(_("launched a warship from %s.") % q.planet)
2604 prout(_("Uhura- Starfleet reports increased Klingon activity"))
2605 if q.planet != None:
2606 proutn(_("near %s ") % q.planet)
2607 prout(_("in Quadrant %s.") % w)
2613 key = scanner.nexttok()
2616 proutn(_("How long? "))
2621 origTime = delay = scanner.real
2624 if delay >= game.state.remtime or len(game.enemies) != 0:
2625 proutn(_("Are you sure? "))
2628 # Alternate resting periods (events) with attacks
2632 game.resting = False
2633 if not game.resting:
2634 prout(_("%d stardates left.") % int(game.state.remtime))
2636 temp = game.optime = delay
2637 if len(game.enemies):
2638 rtime = randreal(1.0, 2.0)
2642 if game.optime < delay:
2643 attack(torps_ok=False)
2651 # Repair Deathray if long rest at starbase
2652 if origTime-delay >= 9.99 and game.condition == "docked":
2653 game.damage[DDRAY] = 0.0
2654 # leave if quadrant supernovas
2655 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2657 game.resting = False
2662 ncourse = (0.0, 10.5, 12.0, 1.5, 9.0, 0.0, 3.0, 7.5, 6.0, 4.5)
2663 newc = Coord(); neighbor = Coord(); bump = Coord(0, 0)
2665 # Wow! We've supernova'ed
2666 supernova(game.quadrant)
2668 # handle initial nova
2669 game.quad[nov.i][nov.j] = '.'
2670 prout(crmena(False, '*', "sector", nov) + _(" novas."))
2671 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2672 game.state.starkl += 1
2673 # Set up queue to recursively trigger adjacent stars
2679 for offset.i in range(-1, 1+1):
2680 for offset.j in range(-1, 1+1):
2681 if offset.j == 0 and offset.i == 0:
2683 neighbor = start + offset
2684 if not neighbor.valid_sector():
2686 iquad = game.quad[neighbor.i][neighbor.j]
2687 # Empty space ends reaction
2688 if iquad in ('.', '?', ' ', 'T', '#'):
2690 elif iquad == '*': # Affect another star
2692 # This star supernovas
2693 supernova(game.quadrant)
2696 hits.append(neighbor)
2697 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2698 game.state.starkl += 1
2699 proutn(crmena(True, '*', "sector", neighbor))
2701 game.quad[neighbor.i][neighbor.j] = '.'
2703 elif iquad in ('P', '@'): # Destroy planet
2704 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
2706 game.state.nplankl += 1
2708 game.state.nworldkl += 1
2709 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2710 game.iplnet.pclass = "destroyed"
2712 game.plnet.invalidate()
2716 game.quad[neighbor.i][neighbor.j] = '.'
2717 elif iquad == 'B': # Destroy base
2718 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
2719 game.state.baseq = [x for x in game.state.baseq if x!= game.quadrant]
2720 game.base.invalidate()
2721 game.state.basekl += 1
2723 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2724 game.quad[neighbor.i][neighbor.j] = '.'
2725 elif iquad in ('E', 'F'): # Buffet ship
2726 prout(_("***Starship buffeted by nova."))
2728 if game.shield >= 2000.0:
2729 game.shield -= 2000.0
2731 diff = 2000.0 - game.shield
2735 prout(_("***Shields knocked out."))
2736 game.damage[DSHIELD] += 0.005*game.damfac*randreal()*diff
2738 game.energy -= 2000.0
2739 if game.energy <= 0:
2742 # add in course nova contributes to kicking starship
2743 bump += (game.sector-hits[-1]).sgn()
2744 elif iquad == 'K': # kill klingon
2745 deadkl(neighbor, iquad, neighbor)
2746 elif iquad in ('C','S','R'): # Damage/destroy big enemies
2748 for ll in range(len(game.enemies)):
2749 if game.enemies[ll].location == neighbor:
2750 target = game.enemies[ll]
2752 if target is not None:
2753 target.power -= 800.0 # If firepower is lost, die
2754 if target.power <= 0.0:
2755 deadkl(neighbor, iquad, neighbor)
2756 continue # neighbor loop
2757 # Else enemy gets flung by the blast wave
2758 newc = neighbor + neighbor - start
2759 proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged"))
2760 if not newc.valid_sector():
2761 # can't leave quadrant
2764 iquad1 = game.quad[newc.i][newc.j]
2766 proutn(_(", blasted into ") + crmena(False, ' ', "sector", newc))
2768 deadkl(neighbor, iquad, newc)
2771 # can't move into something else
2774 proutn(_(", buffeted to Sector %s") % newc)
2775 game.quad[neighbor.i][neighbor.j] = '.'
2776 game.quad[newc.i][newc.j] = iquad
2778 # Starship affected by nova -- kick it away.
2780 direc = ncourse[3*(bump.i+1)+bump.j+2]
2785 scourse = course(bearing=direc, distance=dist)
2786 game.optime = scourse.time(w=4)
2788 prout(_("Force of nova displaces starship."))
2789 imove(scourse, noattack=True)
2790 game.optime = scourse.time(w=4)
2794 "Star goes supernova."
2799 # Scheduled supernova -- select star at random.
2802 for nq.i in range(GALSIZE):
2803 for nq.j in range(GALSIZE):
2804 nstars += game.state.galaxy[nq.i][nq.j].stars
2806 return # nothing to supernova exists
2807 num = randrange(nstars) + 1
2808 for nq.i in range(GALSIZE):
2809 for nq.j in range(GALSIZE):
2810 num -= game.state.galaxy[nq.i][nq.j].stars
2816 proutn("=== Super nova here?")
2819 if not nq == game.quadrant or game.justin:
2820 # it isn't here, or we just entered (treat as enroute)
2823 prout(_("Message from Starfleet Command Stardate %.2f") % game.state.date)
2824 prout(_(" Supernova in Quadrant %s; caution advised.") % nq)
2827 # we are in the quadrant!
2828 num = randrange(game.state.galaxy[nq.i][nq.j].stars) + 1
2829 for ns.i in range(QUADSIZE):
2830 for ns.j in range(QUADSIZE):
2831 if game.quad[ns.i][ns.j]=='*':
2838 prouts(_("***RED ALERT! RED ALERT!"))
2840 prout(_("***Incipient supernova detected at Sector %s") % ns)
2841 if (ns.i-game.sector.i)**2 + (ns.j-game.sector.j)**2 <= 2.1:
2842 proutn(_("Emergency override attempts t"))
2843 prouts("***************")
2847 # destroy any Klingons in supernovaed quadrant
2848 game.state.galaxy[nq.i][nq.j].klingons = 0
2849 if nq == game.state.kscmdr:
2850 # did in the Supercommander!
2851 game.state.nscrem = game.state.kscmdr.i = game.state.kscmdr.j = game.isatb = 0
2855 survivors = filter(lambda w: w != nq, game.state.kcmdr)
2856 comkills = len(game.state.kcmdr) - len(survivors)
2857 game.state.kcmdr = survivors
2858 if not game.state.kcmdr:
2860 # destroy Romulans and planets in supernovaed quadrant
2861 nrmdead = game.state.galaxy[nq.i][nq.j].romulans
2862 game.state.galaxy[nq.i][nq.j].romulans = 0
2863 game.state.nromrem -= nrmdead
2865 for loop in range(game.inplan):
2866 if game.state.planets[loop].quadrant == nq:
2867 game.state.planets[loop].pclass = "destroyed"
2869 # Destroy any base in supernovaed quadrant
2870 game.state.baseq = [x for x in game.state.baseq if x != nq]
2871 # If starship caused supernova, tally up destruction
2873 game.state.starkl += game.state.galaxy[nq.i][nq.j].stars
2874 game.state.basekl += game.state.galaxy[nq.i][nq.j].starbase
2875 game.state.nplankl += npdead
2876 # mark supernova in galaxy and in star chart
2877 if game.quadrant == nq or communicating():
2878 game.state.galaxy[nq.i][nq.j].supernova = True
2879 # If supernova destroys last Klingons give special message
2880 if game.unwon()==0 and not nq == game.quadrant:
2883 prout(_("Lucky you!"))
2884 proutn(_("A supernova in %s has just destroyed the last Klingons.") % nq)
2887 # if some Klingons remain, continue or die in supernova
2892 # Code from finish.c ends here.
2895 "Self-destruct maneuver. Finish with a BANG!"
2897 if damaged(DCOMPTR):
2898 prout(_("Computer damaged; cannot execute destruct sequence."))
2900 prouts(_("---WORKING---")); skip(1)
2901 prouts(_("SELF-DESTRUCT-SEQUENCE-ACTIVATED")); skip(1)
2902 prouts(" 10"); skip(1)
2903 prouts(" 9"); skip(1)
2904 prouts(" 8"); skip(1)
2905 prouts(" 7"); skip(1)
2906 prouts(" 6"); skip(1)
2908 prout(_("ENTER-CORRECT-PASSWORD-TO-CONTINUE-"))
2910 prout(_("SELF-DESTRUCT-SEQUENCE-OTHERWISE-"))
2912 prout(_("SELF-DESTRUCT-SEQUENCE-WILL-BE-ABORTED"))
2915 if game.passwd != scanner.token:
2916 prouts(_("PASSWORD-REJECTED;"))
2918 prouts(_("CONTINUITY-EFFECTED"))
2921 prouts(_("PASSWORD-ACCEPTED")); skip(1)
2922 prouts(" 5"); skip(1)
2923 prouts(" 4"); skip(1)
2924 prouts(" 3"); skip(1)
2925 prouts(" 2"); skip(1)
2926 prouts(" 1"); skip(1)
2928 prouts(_("GOODBYE-CRUEL-WORLD"))
2936 prouts(_("********* Entropy of %s maximized *********") % crmshp())
2940 if len(game.enemies) != 0:
2941 whammo = 25.0 * game.energy
2942 for l in range(len(game.enemies)):
2943 if game.enemies[l].power*game.enemies[l].kdist <= whammo:
2944 deadkl(game.enemies[l].location, game.quad[game.enemies[l].location.i][game.enemies[l].location.j], game.enemies[l].location)
2948 "Compute our rate of kils over time."
2949 elapsed = game.state.date - game.indate
2950 if elapsed == 0: # Avoid divide-by-zero error if calculated on turn 0
2953 starting = (game.inkling + game.incom + game.inscom)
2954 remaining = game.unwon()
2955 return (starting - remaining)/elapsed
2959 badpt = 5.0*game.state.starkl + \
2961 10.0*game.state.nplankl + \
2962 300*game.state.nworldkl + \
2964 100.0*game.state.basekl +\
2965 3.0*game.abandoned +\
2967 if game.ship == 'F':
2969 elif game.ship is None:
2974 # end the game, with appropriate notifications
2978 prout(_("It is stardate %.1f.") % game.state.date)
2980 if ifin == FWON: # Game has been won
2981 if game.state.nromrem != 0:
2982 prout(_("The remaining %d Romulans surrender to Starfleet Command.") %
2985 prout(_("You have smashed the Klingon invasion fleet and saved"))
2986 prout(_("the Federation."))
2987 if game.alive and game.brigcapacity-game.brigfree > 0:
2988 game.kcaptured += game.brigcapacity-game.brigfree
2989 prout(_("The %d captured Klingons are transferred to Star Fleet Command.") % (game.brigcapacity-game.brigfree))
2994 badpt = 0.0 # Close enough!
2995 # killsPerDate >= RateMax
2996 if game.state.date-game.indate < 5.0 or \
2997 killrate() >= 0.1*game.skill*(game.skill+1.0) + 0.1 + 0.008*badpt:
2999 prout(_("In fact, you have done so well that Starfleet Command"))
3000 if game.skill == SKILL_NOVICE:
3001 prout(_("promotes you one step in rank from \"Novice\" to \"Fair\"."))
3002 elif game.skill == SKILL_FAIR:
3003 prout(_("promotes you one step in rank from \"Fair\" to \"Good\"."))
3004 elif game.skill == SKILL_GOOD:
3005 prout(_("promotes you one step in rank from \"Good\" to \"Expert\"."))
3006 elif game.skill == SKILL_EXPERT:
3007 prout(_("promotes you to Commodore Emeritus."))
3009 prout(_("Now that you think you're really good, try playing"))
3010 prout(_("the \"Emeritus\" game. It will splatter your ego."))
3011 elif game.skill == SKILL_EMERITUS:
3013 proutn(_("Computer- "))
3014 prouts(_("ERROR-ERROR-ERROR-ERROR"))
3016 prouts(_(" YOUR-SKILL-HAS-EXCEEDED-THE-CAPACITY-OF-THIS-PROGRAM"))
3018 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
3020 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
3022 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
3024 prouts(_(" THIS-PROGRAM-MUST?- MUST ? - SUR? ? -? VI"))
3026 prout(_("Now you can retire and write your own Star Trek game!"))
3028 elif game.skill >= SKILL_EXPERT:
3029 if game.thawed and not game.idebug:
3030 prout(_("You cannot get a citation, so..."))
3032 proutn(_("Do you want your Commodore Emeritus Citation printed? "))
3036 # Only grant long life if alive (original didn't!)
3038 prout(_("LIVE LONG AND PROSPER."))
3043 elif ifin == FDEPLETE: # Federation Resources Depleted
3044 prout(_("Your time has run out and the Federation has been"))
3045 prout(_("conquered. Your starship is now Klingon property,"))
3046 prout(_("and you are put on trial as a war criminal. On the"))
3047 proutn(_("basis of your record, you are "))
3048 if game.unwon()*3.0 > (game.inkling + game.incom + game.inscom):
3049 prout(_("acquitted."))
3051 prout(_("LIVE LONG AND PROSPER."))
3053 prout(_("found guilty and"))
3054 prout(_("sentenced to death by slow torture."))
3058 elif ifin == FLIFESUP:
3059 prout(_("Your life support reserves have run out, and"))
3060 prout(_("you die of thirst, starvation, and asphyxiation."))
3061 prout(_("Your starship is a derelict in space."))
3063 prout(_("Your energy supply is exhausted."))
3065 prout(_("Your starship is a derelict in space."))
3066 elif ifin == FBATTLE:
3067 prout(_("The %s has been destroyed in battle.") % crmshp())
3069 prout(_("Dulce et decorum est pro patria mori."))
3071 prout(_("You have made three attempts to cross the negative energy"))
3072 prout(_("barrier which surrounds the galaxy."))
3074 prout(_("Your navigation is abominable."))
3077 prout(_("Your starship has been destroyed by a nova."))
3078 prout(_("That was a great shot."))
3080 elif ifin == FSNOVAED:
3081 prout(_("The %s has been fried by a supernova.") % crmshp())
3082 prout(_("...Not even cinders remain..."))
3083 elif ifin == FABANDN:
3084 prout(_("You have been captured by the Klingons. If you still"))
3085 prout(_("had a starbase to be returned to, you would have been"))
3086 prout(_("repatriated and given another chance. Since you have"))
3087 prout(_("no starbases, you will be mercilessly tortured to death."))
3088 elif ifin == FDILITHIUM:
3089 prout(_("Your starship is now an expanding cloud of subatomic particles"))
3090 elif ifin == FMATERIALIZE:
3091 prout(_("Starbase was unable to re-materialize your starship."))
3092 prout(_("Sic transit gloria mundi"))
3093 elif ifin == FPHASER:
3094 prout(_("The %s has been cremated by its own phasers.") % crmshp())
3096 prout(_("You and your landing party have been"))
3097 prout(_("converted to energy, dissipating through space."))
3098 elif ifin == FMINING:
3099 prout(_("You are left with your landing party on"))
3100 prout(_("a wild jungle planet inhabited by primitive cannibals."))
3102 prout(_("They are very fond of \"Captain Kirk\" soup."))
3104 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
3105 elif ifin == FDPLANET:
3106 prout(_("You and your mining party perish."))
3108 prout(_("That was a great shot."))
3111 prout(_("The Galileo is instantly annihilated by the supernova."))
3112 prout(_("You and your mining party are atomized."))
3114 prout(_("Mr. Spock takes command of the %s and") % crmshp())
3115 prout(_("joins the Romulans, wreaking terror on the Federation."))
3116 elif ifin == FPNOVA:
3117 prout(_("You and your mining party are atomized."))
3119 prout(_("Mr. Spock takes command of the %s and") % crmshp())
3120 prout(_("joins the Romulans, wreaking terror on the Federation."))
3121 elif ifin == FSTRACTOR:
3122 prout(_("The shuttle craft Galileo is also caught,"))
3123 prout(_("and breaks up under the strain."))
3125 prout(_("Your debris is scattered for millions of miles."))
3126 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
3128 prout(_("The mutants attack and kill Spock."))
3129 prout(_("Your ship is captured by Klingons, and"))
3130 prout(_("your crew is put on display in a Klingon zoo."))
3131 elif ifin == FTRIBBLE:
3132 prout(_("Tribbles consume all remaining water,"))
3133 prout(_("food, and oxygen on your ship."))
3135 prout(_("You die of thirst, starvation, and asphyxiation."))
3136 prout(_("Your starship is a derelict in space."))
3138 prout(_("Your ship is drawn to the center of the black hole."))
3139 prout(_("You are crushed into extremely dense matter."))
3140 elif ifin == FCLOAK:
3142 prout(_("You have violated the Treaty of Algeron."))
3143 prout(_("The Romulan Empire can never trust you again."))
3145 prout(_("Your last crew member has died."))
3146 if ifin != FWON and ifin != FCLOAK and game.iscloaked:
3147 prout(_("Your ship was cloaked so your subspace radio did not receive anything."))
3148 prout(_("You may have missed some warning messages."))
3150 if game.ship == 'F':
3152 elif game.ship == 'E':
3155 if game.unwon() != 0:
3156 goodies = game.state.remres/game.inresor
3157 baddies = (game.remkl() + 2.0*len(game.state.kcmdr))/(game.inkling+2.0*game.incom)
3158 if goodies/baddies >= randreal(1.0, 1.5):
3159 prout(_("As a result of your actions, a treaty with the Klingon"))
3160 prout(_("Empire has been signed. The terms of the treaty are"))
3161 if goodies/baddies >= randreal(3.0):
3162 prout(_("favorable to the Federation."))
3164 prout(_("Congratulations!"))
3166 prout(_("highly unfavorable to the Federation."))
3168 prout(_("The Federation will be destroyed."))
3170 prout(_("Since you took the last Klingon with you, you are a"))
3171 prout(_("martyr and a hero. Someday maybe they'll erect a"))
3172 prout(_("statue in your memory. Rest in peace, and try not"))
3173 prout(_("to think about pigeons."))
3176 scanner.chew() # Clean up leftovers
3179 "Compute player's score."
3180 timused = game.state.date - game.indate
3181 if (timused == 0 or game.unwon() != 0) and timused < 5.0:
3183 game.perdate = killrate()
3184 ithperd = 500*game.perdate + 0.5
3187 iwon = 100*game.skill
3188 if game.ship == 'E':
3190 elif game.ship == 'F':
3194 game.score = 10*(game.inkling - game.remkl()) \
3195 + 50*(game.incom - len(game.state.kcmdr)) \
3197 + 20*(game.inrom - game.state.nromrem) \
3198 + 200*(game.inscom - game.state.nscrem) \
3199 - game.state.nromrem \
3200 + 3 * game.kcaptured \
3205 prout(_("Your score --"))
3206 if game.inrom - game.state.nromrem:
3207 prout(_("%6d Romulans destroyed %5d") %
3208 (game.inrom - game.state.nromrem, 20*(game.inrom - game.state.nromrem)))
3209 if game.state.nromrem and game.gamewon:
3210 prout(_("%6d Romulans captured %5d") %
3211 (game.state.nromrem, game.state.nromrem))
3212 if game.inkling - game.remkl():
3213 prout(_("%6d ordinary Klingons destroyed %5d") %
3214 (game.inkling - game.remkl(), 10*(game.inkling - game.remkl())))
3215 if game.incom - len(game.state.kcmdr):
3216 prout(_("%6d Klingon commanders destroyed %5d") %
3217 (game.incom - len(game.state.kcmdr), 50*(game.incom - len(game.state.kcmdr))))
3219 prout(_("%d Klingons captured %5d") %
3220 (game.kcaptured, 3 * game.kcaptured))
3221 if game.inscom - game.state.nscrem:
3222 prout(_("%6d Super-Commander destroyed %5d") %
3223 (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem)))
3225 prout(_("%6.2f Klingons per stardate %5d") %
3226 (game.perdate, ithperd))
3227 if game.state.starkl:
3228 prout(_("%6d stars destroyed by your action %5d") %
3229 (game.state.starkl, -5*game.state.starkl))
3230 if game.state.nplankl:
3231 prout(_("%6d planets destroyed by your action %5d") %
3232 (game.state.nplankl, -10*game.state.nplankl))
3233 if (game.options & OPTION_WORLDS) and game.state.nworldkl:
3234 prout(_("%6d inhabited planets destroyed by your action %5d") %
3235 (game.state.nworldkl, -300*game.state.nworldkl))
3236 if game.state.basekl:
3237 prout(_("%6d bases destroyed by your action %5d") %
3238 (game.state.basekl, -100*game.state.basekl))
3240 prout(_("%6d calls for help from starbase %5d") %
3241 (game.nhelp, -45*game.nhelp))
3243 prout(_("%6d casualties incurred %5d") %
3244 (game.casual, -game.casual))
3246 prout(_("%6d crew abandoned in space %5d") %
3247 (game.abandoned, -3*game.abandoned))
3249 prout(_("%6d ship(s) lost or destroyed %5d") %
3250 (klship, -100*klship))
3253 prout(_("1 Treaty of Algeron violation -100"))
3255 prout(_("%6d Treaty of Algeron violations %5d\n") %
3256 (ncviol, -100*ncviol))
3258 prout(_("Penalty for getting yourself killed -200"))
3260 proutn(_("Bonus for winning "))
3261 if game.skill == SKILL_NOVICE: proutn(_("Novice game "))
3262 elif game.skill == SKILL_FAIR: proutn(_("Fair game "))
3263 elif game.skill == SKILL_GOOD: proutn(_("Good game "))
3264 elif game.skill == SKILL_EXPERT: proutn(_("Expert game "))
3265 elif game.skill == SKILL_EMERITUS: proutn(_("Emeritus game"))
3266 prout(" %5d" % iwon)
3268 prout(_("TOTAL SCORE %5d") % game.score)
3271 "Emit winner's commemmorative plaque."
3274 proutn(_("File or device name for your plaque: "))
3277 fp = open(winner, "w")
3280 prout(_("Invalid name."))
3282 proutn(_("Enter name to go on plaque (up to 30 characters): "))
3284 # The 38 below must be 64 for 132-column paper
3285 nskip = 38 - len(winner)/2
3286 # This is where the ASCII art picture was emitted.
3287 # It got garbled somewhere in the chain of transmission to the Almy version.
3288 # We should restore it if we can find old enough FORTRAN sources.
3290 fp.write(_(" U. S. S. ENTERPRISE\n"))
3291 fp.write("\n\n\n\n")
3292 fp.write(_(" For demonstrating outstanding ability as a starship captain\n"))
3294 fp.write(_(" Starfleet Command bestows to you\n"))
3296 fp.write("%*s%s\n\n" % (nskip, "", winner))
3297 fp.write(_(" the rank of\n\n"))
3298 fp.write(_(" \"Commodore Emeritus\"\n\n"))
3300 if game.skill == SKILL_EXPERT:
3301 fp.write(_(" Expert level\n\n"))
3302 elif game.skill == SKILL_EMERITUS:
3303 fp.write(_("Emeritus level\n\n"))
3305 fp.write(_(" Cheat level\n\n"))
3306 timestring = time.ctime()
3307 fp.write(_(" This day of %.6s %.4s, %.8s\n\n") %
3308 (timestring+4, timestring+20, timestring+11))
3309 fp.write(_(" Your score: %d\n\n") % game.score)
3310 fp.write(_(" Klingons per stardate: %.2f\n") % game.perdate)
3313 # Code from io.c begins here
3315 rows = linecount = 0 # for paging
3318 fullscreen_window = None
3319 srscan_window = None # Short range scan
3320 report_window = None # Report legends for status window
3321 status_window = None # The status window itself
3322 lrscan_window = None # Long range scan
3323 message_window = None # Main window for scrolling text
3324 prompt_window = None # Prompt window at bottom of display
3329 # for some recent versions of python2, the following enables UTF8
3330 # for the older ones we probably need to set C locale, and python3
3331 # has no problems at all
3332 if sys.version_info[0] < 3:
3333 locale.setlocale(locale.LC_ALL, "")
3334 gettext.bindtextdomain("sst", "/usr/local/share/locale")
3335 gettext.textdomain("sst")
3336 if not (game.options & OPTION_CURSES):
3337 ln_env = os.getenv("LINES")
3343 stdscr = curses.initscr()
3347 if game.options & OPTION_COLOR:
3348 curses.start_color()
3349 curses.use_default_colors()
3350 curses.init_pair(curses.COLOR_BLACK, curses.COLOR_BLACK, -1)
3351 curses.init_pair(curses.COLOR_GREEN, curses.COLOR_GREEN, -1)
3352 curses.init_pair(curses.COLOR_RED, curses.COLOR_RED, -1)
3353 curses.init_pair(curses.COLOR_CYAN, curses.COLOR_CYAN, -1)
3354 curses.init_pair(curses.COLOR_WHITE, curses.COLOR_WHITE, -1)
3355 curses.init_pair(curses.COLOR_MAGENTA, curses.COLOR_MAGENTA, -1)
3356 curses.init_pair(curses.COLOR_BLUE, curses.COLOR_BLUE, -1)
3357 curses.init_pair(curses.COLOR_YELLOW, curses.COLOR_YELLOW, -1)
3358 global fullscreen_window, srscan_window, report_window, status_window
3359 global lrscan_window, message_window, prompt_window
3360 (rows, _columns) = stdscr.getmaxyx()
3361 fullscreen_window = stdscr
3362 srscan_window = curses.newwin(12, 25, 0, 0)
3363 report_window = curses.newwin(11, 0, 1, 25)
3364 status_window = curses.newwin(10, 0, 1, 39)
3365 lrscan_window = curses.newwin(5, 0, 0, 64)
3366 message_window = curses.newwin(0, 0, 12, 0)
3367 prompt_window = curses.newwin(1, 0, rows-2, 0)
3368 message_window.scrollok(True)
3369 setwnd(fullscreen_window)
3373 if game.options & OPTION_CURSES:
3374 stdscr.keypad(False)
3380 "Wait for user action -- OK to do nothing if on a TTY"
3381 if game.options & OPTION_CURSES:
3386 prouts(_("[ANNOUNCEMENT ARRIVING...]"))
3390 if game.skill > SKILL_FAIR:
3391 prompt = _("[CONTINUE?]")
3393 prompt = _("[PRESS ENTER TO CONTINUE]")
3395 if game.options & OPTION_CURSES:
3397 setwnd(prompt_window)
3398 prompt_window.clear()
3399 prompt_window.addstr(prompt)
3400 prompt_window.getstr()
3401 prompt_window.clear()
3402 prompt_window.refresh()
3403 setwnd(message_window)
3406 sys.stdout.write('\n')
3410 sys.stdout.write('\n' * rows)
3414 "Skip i lines. Pause game if this would cause a scrolling event."
3415 for _dummy in range(i):
3416 if game.options & OPTION_CURSES:
3417 (y, _x) = curwnd.getyx()
3420 except curses.error:
3425 if rows and linecount >= rows:
3428 sys.stdout.write('\n')
3430 def proutn(proutntline):
3431 "Utter a line with no following line feed."
3432 if game.options & OPTION_CURSES:
3433 (y, x) = curwnd.getyx()
3434 (my, _mx) = curwnd.getmaxyx()
3435 if curwnd == message_window and y >= my - 2:
3438 # Uncomment this to debug curses problems
3440 # logfp.write("#curses: at %s proutn(%s)\n" % ((y, x), repr(proutntline)))
3441 curwnd.addstr(proutntline)
3444 sys.stdout.write(proutntline)
3447 def prout(proutline):
3451 def prouts(proutsline):
3453 for c in proutsline:
3454 if not replayfp or replayfp.closed: # Don't slow down replays
3457 if game.options & OPTION_CURSES:
3461 if not replayfp or replayfp.closed:
3465 "Get a line of input."
3466 if game.options & OPTION_CURSES:
3467 linein = curwnd.getstr() + "\n"
3470 if replayfp and not replayfp.closed:
3472 linein = replayfp.readline()
3475 prout("*** Replay finished")
3478 elif linein[0] != "#":
3482 linein = my_input() + "\n"
3491 "Change windows -- OK for this to be a no-op in tty mode."
3493 if game.options & OPTION_CURSES:
3494 # Uncomment this to debug curses problems
3496 if wnd == fullscreen_window:
3497 legend = "fullscreen"
3498 elif wnd == srscan_window:
3500 elif wnd == report_window:
3502 elif wnd == status_window:
3504 elif wnd == lrscan_window:
3506 elif wnd == message_window:
3508 elif wnd == prompt_window:
3512 #logfp.write("#curses: setwnd(%s)\n" % legend)
3514 # Some curses implementations get confused when you try this.
3516 curses.curs_set(wnd in (fullscreen_window, message_window, prompt_window))
3517 except curses.error:
3521 "Clear to end of line -- can be a no-op in tty mode"
3522 if game.options & OPTION_CURSES:
3527 "Clear screen -- can be a no-op in tty mode."
3529 if game.options & OPTION_CURSES:
3535 def textcolor(color=DEFAULT):
3536 if (game.options & OPTION_COLOR) and (game.options & OPTION_CURSES):
3537 if color == DEFAULT:
3539 elif color == BLACK:
3540 curwnd.attron(curses.color_pair(curses.COLOR_BLACK))
3542 curwnd.attron(curses.color_pair(curses.COLOR_BLUE))
3543 elif color == GREEN:
3544 curwnd.attron(curses.color_pair(curses.COLOR_GREEN))
3546 curwnd.attron(curses.color_pair(curses.COLOR_CYAN))
3548 curwnd.attron(curses.color_pair(curses.COLOR_RED))
3549 elif color == MAGENTA:
3550 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA))
3551 elif color == BROWN:
3552 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW))
3553 elif color == LIGHTGRAY:
3554 curwnd.attron(curses.color_pair(curses.COLOR_WHITE))
3555 elif color == DARKGRAY:
3556 curwnd.attron(curses.color_pair(curses.COLOR_BLACK) | curses.A_BOLD)
3557 elif color == LIGHTBLUE:
3558 curwnd.attron(curses.color_pair(curses.COLOR_BLUE) | curses.A_BOLD)
3559 elif color == LIGHTGREEN:
3560 curwnd.attron(curses.color_pair(curses.COLOR_GREEN) | curses.A_BOLD)
3561 elif color == LIGHTCYAN:
3562 curwnd.attron(curses.color_pair(curses.COLOR_CYAN) | curses.A_BOLD)
3563 elif color == LIGHTRED:
3564 curwnd.attron(curses.color_pair(curses.COLOR_RED) | curses.A_BOLD)
3565 elif color == LIGHTMAGENTA:
3566 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA) | curses.A_BOLD)
3567 elif color == YELLOW:
3568 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW) | curses.A_BOLD)
3569 elif color == WHITE:
3570 curwnd.attron(curses.color_pair(curses.COLOR_WHITE) | curses.A_BOLD)
3573 if (game.options & OPTION_COLOR) and (game.options & OPTION_CURSES):
3574 curwnd.attron(curses.A_REVERSE)
3577 # Things past this point have policy implications.
3581 "Hook to be called after moving to redraw maps."
3582 if game.options & OPTION_CURSES:
3585 setwnd(srscan_window)
3589 setwnd(status_window)
3590 status_window.clear()
3591 status_window.move(0, 0)
3592 setwnd(report_window)
3593 report_window.clear()
3594 report_window.move(0, 0)
3596 setwnd(lrscan_window)
3597 lrscan_window.clear()
3598 lrscan_window.move(0, 0)
3599 lrscan(silent=False)
3601 def put_srscan_sym(w, sym):
3602 "Emit symbol for short-range scan."
3603 srscan_window.move(w.i+1, w.j*2+2)
3604 srscan_window.addch(sym)
3605 srscan_window.refresh()
3608 "Enemy fall down, go boom."
3609 if game.options & OPTION_CURSES:
3611 setwnd(srscan_window)
3612 srscan_window.attron(curses.A_REVERSE)
3613 put_srscan_sym(w, game.quad[w.i][w.j])
3617 srscan_window.attroff(curses.A_REVERSE)
3618 put_srscan_sym(w, game.quad[w.i][w.j])
3619 curses.delay_output(500)
3620 setwnd(message_window)
3623 "Sound and visual effects for teleportation."
3624 if game.options & OPTION_CURSES:
3626 setwnd(message_window)
3628 prouts(" . . . . . ")
3629 if game.options & OPTION_CURSES:
3630 #curses.delay_output(1000)
3634 def tracktorpedo(w, step, i, n, iquad):
3635 "Torpedo-track animation."
3636 if not game.options & OPTION_CURSES:
3640 proutn(_("Track for torpedo number %d- ") % (i+1))
3643 proutn(_("Torpedo track- "))
3644 elif step==4 or step==9:
3648 if not damaged(DSRSENS) or game.condition=="docked":
3649 if i != 0 and step == 1:
3652 if (iquad=='.') or (iquad==' '):
3653 put_srscan_sym(w, '+')
3657 put_srscan_sym(w, iquad)
3659 curwnd.attron(curses.A_REVERSE)
3660 put_srscan_sym(w, iquad)
3664 curwnd.attroff(curses.A_REVERSE)
3665 put_srscan_sym(w, iquad)
3670 "Display the current galaxy chart."
3671 if game.options & OPTION_CURSES:
3672 setwnd(message_window)
3673 message_window.clear()
3675 if game.options & OPTION_TTY:
3680 def prstat(txt, data):
3682 if game.options & OPTION_CURSES:
3684 setwnd(status_window)
3686 proutn(" " * (NSYM - len(txt)))
3689 if game.options & OPTION_CURSES:
3690 setwnd(report_window)
3692 # Code from moving.c begins here
3694 def imove(icourse=None, noattack=False):
3695 "Movement execution for warp, impulse, supernova, and tractor-beam events."
3698 def newquadrant(noattack):
3699 # Leaving quadrant -- allow final enemy attack
3700 # Don't set up attack if being pushed by nova or cloaked
3701 if len(game.enemies) != 0 and not noattack and not game.iscloaked:
3703 for enemy in game.enemies:
3704 finald = (w - enemy.location).distance()
3705 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3706 # Stas Sergeev added the condition
3707 # that attacks only happen if Klingons
3708 # are present and your skill is good.
3709 if game.skill > SKILL_GOOD and game.klhere > 0 and not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3710 attack(torps_ok=False)
3713 # check for edge of galaxy
3717 if icourse.final.i < 0:
3718 icourse.final.i = -icourse.final.i
3720 if icourse.final.j < 0:
3721 icourse.final.j = -icourse.final.j
3723 if icourse.final.i >= GALSIZE*QUADSIZE:
3724 icourse.final.i = (GALSIZE*QUADSIZE*2) - icourse.final.i
3726 if icourse.final.j >= GALSIZE*QUADSIZE:
3727 icourse.final.j = (GALSIZE*QUADSIZE*2) - icourse.final.j
3735 if game.nkinks == 3:
3736 # Three strikes -- you're out!
3740 prout(_("YOU HAVE ATTEMPTED TO CROSS THE NEGATIVE ENERGY BARRIER"))
3741 prout(_("AT THE EDGE OF THE GALAXY. THE THIRD TIME YOU TRY THIS,"))
3742 prout(_("YOU WILL BE DESTROYED."))
3743 # Compute final position in new quadrant
3744 if trbeam: # Don't bother if we are to be beamed
3746 game.quadrant = icourse.final.quadrant()
3747 game.sector = icourse.final.sector()
3749 prout(_("Entering Quadrant %s.") % game.quadrant)
3750 game.quad[game.sector.i][game.sector.j] = game.ship
3752 if game.skill>SKILL_NOVICE:
3753 attack(torps_ok=False)
3755 def check_collision(h):
3756 iquad = game.quad[h.i][h.j]
3758 # object encountered in flight path
3759 stopegy = 50.0*icourse.distance/game.optime
3760 if iquad in ('T', 'K', 'C', 'S', 'R', '?'):
3761 for enemy in game.enemies:
3762 if enemy.location == game.sector:
3763 collision(rammed=False, enemy=enemy)
3765 # This should not happen
3766 prout(_("Which way did he go?"))
3770 prouts(_("***RED ALERT! RED ALERT!"))
3772 proutn("***" + crmshp())
3773 proutn(_(" pulled into black hole at Sector %s") % h)
3774 # Getting pulled into a black hole was certain
3775 # death in Almy's original. Stas Sergeev added a
3776 # possibility that you'll get timewarped instead.
3778 for m in range(NDEVICES):
3779 if game.damage[m]>0:
3781 probf=math.pow(1.4,(game.energy+game.shield)/5000.0-1.0)*math.pow(1.3,1.0/(n+1)-1.0)
3782 if (game.options & OPTION_BLKHOLE) and withprob(1-probf):
3792 prout(_(" encounters Tholian web at %s;") % h)
3794 prout(_(" blocked by object at %s;") % h)
3795 proutn(_("Emergency stop required "))
3796 prout(_("%2d units of energy.") % int(stopegy))
3797 game.energy -= stopegy
3798 if game.energy <= 0:
3805 prout(_("Helmsman Sulu- \"Leaving standard orbit.\""))
3806 game.inorbit = False
3807 # If tractor beam is to occur, don't move full distance
3808 if game.state.date+game.optime >= scheduled(FTBEAM):
3810 # We can't be tractor beamed if cloaked,
3811 # so move the event into the future
3812 postpone(FTBEAM, game.optime + expran(1.5*game.intime/len(game.kcmdr)))
3816 game.condition = "red"
3817 icourse.distance = icourse.distance*(scheduled(FTBEAM)-game.state.date)/game.optime + 0.1
3818 game.optime = scheduled(FTBEAM) - game.state.date + 1e-5
3820 game.quad[game.sector.i][game.sector.j] = '.'
3821 for _m in range(icourse.moves):
3823 w = icourse.sector()
3824 if icourse.origin.quadrant() != icourse.location.quadrant():
3825 newquadrant(noattack)
3827 elif check_collision(w):
3828 print("Collision detected")
3832 # We're in destination quadrant -- compute new average enemy distances
3833 game.quad[game.sector.i][game.sector.j] = game.ship
3835 for enemy in game.enemies:
3836 finald = (w-enemy.location).distance()
3837 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3838 enemy.kdist = finald
3840 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3841 attack(torps_ok=False)
3842 for enemy in game.enemies:
3843 enemy.kavgd = enemy.kdist
3846 setwnd(message_window)
3850 "Dock our ship at a starbase."
3852 if game.condition == "docked" and verbose:
3853 prout(_("Already docked."))
3856 prout(_("You must first leave standard orbit."))
3858 if not game.base.is_valid() or abs(game.sector.i-game.base.i) > 1 or abs(game.sector.j-game.base.j) > 1:
3859 prout(crmshp() + _(" not adjacent to base."))
3862 prout(_("You cannot dock while cloaked."))
3864 game.condition = "docked"
3868 if game.energy < game.inenrg:
3869 game.energy = game.inenrg
3870 game.shield = game.inshld
3871 game.torps = game.intorps
3872 game.lsupres = game.inlsr
3873 game.state.crew = FULLCREW
3874 if game.brigcapacity-game.brigfree > 0:
3875 prout(_("%d captured Klingons transferred to base") % (game.brigcapacity-game.brigfree))
3876 game.kcaptured += game.brigcapacity-game.brigfree
3877 game.brigfree = game.brigcapacity
3878 if communicating() and \
3879 ((is_scheduled(FCDBAS) or game.isatb == 1) and not game.iseenit):
3880 # get attack report from base
3881 prout(_("Lt. Uhura- \"Captain, an important message from the starbase:\""))
3885 def cartesian(loc1=None, loc2=None):
3887 return game.quadrant * QUADSIZE + game.sector
3889 return game.quadrant * QUADSIZE + loc1
3891 return loc1 * QUADSIZE + loc2
3893 def getcourse(isprobe):
3894 "Get a course and distance from the user."
3896 dquad = copy.copy(game.quadrant)
3897 navmode = "unspecified"
3901 if game.landed and not isprobe:
3902 prout(_("Dummy! You can't leave standard orbit until you"))
3903 proutn(_("are back aboard the ship."))
3906 while navmode == "unspecified":
3907 if damaged(DNAVSYS):
3909 prout(_("Computer damaged; manual navigation only"))
3911 prout(_("Computer damaged; manual movement only"))
3916 key = scanner.nexttok()
3918 proutn(_("Manual or automatic- "))
3921 elif key == "IHALPHA":
3922 if scanner.sees("manual"):
3924 key = scanner.nexttok()
3926 elif scanner.sees("automatic"):
3927 navmode = "automatic"
3928 key = scanner.nexttok()
3936 prout(_("(Manual navigation assumed.)"))
3938 prout(_("(Manual movement assumed.)"))
3942 if navmode == "automatic":
3943 while key == "IHEOL":
3945 proutn(_("Target quadrant or quadrant§or- "))
3947 proutn(_("Destination sector or quadrant§or- "))
3950 key = scanner.nexttok()
3954 xi = int(round(scanner.real))-1
3955 key = scanner.nexttok()
3959 xj = int(round(scanner.real))-1
3960 key = scanner.nexttok()
3962 # both quadrant and sector specified
3963 xk = int(round(scanner.real))-1
3964 key = scanner.nexttok()
3968 xl = int(round(scanner.real))-1
3974 # only one pair of numbers was specified
3976 # only quadrant specified -- go to center of dest quad
3979 dsect.j = dsect.i = 4 # preserves 1-origin behavior
3981 # only sector specified
3985 if not dquad.valid_quadrant() or not dsect.valid_sector():
3992 prout(_("Helmsman Sulu- \"Course locked in for Sector %s.\"") % dsect)
3994 prout(_("Ensign Chekov- \"Course laid in, Captain.\""))
3995 # the actual deltas get computed here
3996 delta.j = dquad.j-game.quadrant.j + (dsect.j-game.sector.j)/(QUADSIZE*1.0)
3997 delta.i = game.quadrant.i-dquad.i + (game.sector.i-dsect.i)/(QUADSIZE*1.0)
3999 while key == "IHEOL":
4000 proutn(_("X and Y displacements- "))
4003 key = scanner.nexttok()
4006 delta.j = scanner.real
4010 key = scanner.nexttok()
4012 delta.i = scanner.real
4013 elif key == "IHEOL":
4019 # Check for zero movement
4020 if delta.i == 0 and delta.j == 0:
4023 if itemp == "verbose" and not isprobe:
4025 prout(_("Helmsman Sulu- \"Aye, Sir.\""))
4027 return course(bearing=delta.bearing(), distance=delta.distance())
4030 def __init__(self, bearing, distance, origin=None):
4031 self.distance = distance
4032 self.bearing = bearing
4034 self.origin = cartesian(game.quadrant, game.sector)
4036 self.origin = origin
4037 # The bearing() code we inherited from FORTRAN is actually computing
4038 # clockface directions!
4039 if self.bearing < 0.0:
4040 self.bearing += 12.0
4041 self.angle = ((15.0 - self.bearing) * 0.5235988)
4042 self.increment = Coord(-math.sin(self.angle), math.cos(self.angle))
4043 bigger = max(abs(self.increment.i), abs(self.increment.j))
4044 self.increment /= bigger
4045 self.moves = int(round(10*self.distance*bigger))
4047 self.final = (self.location + self.moves*self.increment).roundtogrid()
4048 self.location = self.origin
4049 self.nextlocation = None
4051 self.location = self.origin
4054 return self.location.roundtogrid() == self.final
4056 "Next step on course."
4058 self.nextlocation = self.location + self.increment
4059 samequad = (self.location.quadrant() == self.nextlocation.quadrant())
4060 self.location = self.nextlocation
4063 return self.location.quadrant()
4065 return self.location.sector()
4067 return self.distance*(w**3)*(game.shldup+1)
4069 return 10.0*self.distance/w**2
4072 "Move under impulse power."
4074 if damaged(DIMPULS):
4077 prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
4079 if game.energy > 30.0:
4081 icourse = getcourse(isprobe=False)
4084 power = 20.0 + 100.0*icourse.distance
4087 if power >= game.energy:
4088 # Insufficient power for trip
4090 prout(_("First Officer Spock- \"Captain, the impulse engines"))
4091 prout(_("require 20.0 units to engage, plus 100.0 units per"))
4092 if game.energy > 30:
4093 proutn(_("quadrant. We can go, therefore, a maximum of %d") %
4094 int(0.01 * (game.energy-20.0)-0.05))
4095 prout(_(" quadrants.\""))
4097 prout(_("quadrant. They are, therefore, useless.\""))
4100 # Make sure enough time is left for the trip
4101 game.optime = icourse.distance/0.095
4102 if game.optime >= game.state.remtime:
4103 prout(_("First Officer Spock- \"Captain, our speed under impulse"))
4104 prout(_("power is only 0.95 sectors per stardate. Are you sure"))
4105 proutn(_("we dare spend the time?\" "))
4108 # Activate impulse engines and pay the cost
4109 imove(icourse, noattack=False)
4113 power = 20.0 + 100.0*icourse.distance
4114 game.energy -= power
4115 game.optime = icourse.distance/0.095
4116 if game.energy <= 0:
4120 def warp(wcourse, involuntary):
4121 "ove under warp drive."
4122 blooey = False; twarp = False
4123 if not involuntary: # Not WARPX entry
4128 prout(_("Engineer Scott- \"The warp engines can not be used while cloaked, Sir.\""))
4130 if game.damage[DWARPEN] > 10.0:
4133 prout(_("Engineer Scott- \"The warp engines are damaged, Sir.\""))
4135 if damaged(DWARPEN) and game.warpfac > 4.0:
4138 prout(_("Engineer Scott- \"Sorry, Captain. Until this damage"))
4139 prout(_(" is repaired, I can only give you warp 4.\""))
4141 # Read in course and distance
4144 wcourse = getcourse(isprobe=False)
4147 # Make sure starship has enough energy for the trip
4148 # Note: this formula is slightly different from the C version,
4149 # and lets you skate a bit closer to the edge.
4150 if wcourse.power(game.warpfac) >= game.energy:
4151 # Insufficient power for trip
4154 prout(_("Engineering to bridge--"))
4155 if not game.shldup or 0.5*wcourse.power(game.warpfac) > game.energy:
4156 iwarp = (game.energy/(wcourse.distance+0.05)) ** 0.333333333
4158 prout(_("We can't do it, Captain. We don't have enough energy."))
4160 proutn(_("We don't have enough energy, but we could do it at warp %d") % iwarp)
4163 prout(_("if you'll lower the shields."))
4167 prout(_("We haven't the energy to go that far with the shields up."))
4169 # Make sure enough time is left for the trip
4170 game.optime = wcourse.time(game.warpfac)
4171 if game.optime >= 0.8*game.state.remtime:
4173 prout(_("First Officer Spock- \"Captain, I compute that such"))
4174 proutn(_(" a trip would require approximately %2.0f") %
4175 (100.0*game.optime/game.state.remtime))
4176 prout(_(" percent of our"))
4177 proutn(_(" remaining time. Are you sure this is wise?\" "))
4183 if game.warpfac > 6.0:
4184 # Decide if engine damage will occur
4185 # ESR: Seems wrong. Probability of damage goes *down* with distance?
4186 prob = wcourse.distance*(6.0-game.warpfac)**2/66.666666666
4187 if prob > randreal():
4189 wcourse.distance = randreal(wcourse.distance)
4190 # Decide if time warp will occur
4191 if 0.5*wcourse.distance*math.pow(7.0,game.warpfac-10.0) > randreal():
4193 if game.idebug and game.warpfac==10 and not twarp:
4195 proutn("=== Force time warp? ")
4199 # If time warp or engine damage, check path
4200 # If it is obstructed, don't do warp or damage
4201 look = wcourse.moves
4205 w = wcourse.sector()
4206 if not w.valid_sector():
4208 if game.quad[w.i][w.j] != '.':
4212 # Activate Warp Engines and pay the cost
4213 imove(wcourse, noattack=False)
4216 game.energy -= wcourse.power(game.warpfac)
4217 if game.energy <= 0:
4219 game.optime = wcourse.time(game.warpfac)
4223 game.damage[DWARPEN] = game.damfac * randreal(1.0, 4.0)
4225 prout(_("Engineering to bridge--"))
4226 prout(_(" Scott here. The warp engines are damaged."))
4227 prout(_(" We'll have to reduce speed to warp 4."))
4232 "Change the warp factor."
4234 key=scanner.nexttok()
4238 proutn(_("Warp factor- "))
4242 if game.damage[DWARPEN] > 10.0:
4243 prout(_("Warp engines inoperative."))
4245 if damaged(DWARPEN) and scanner.real > 4.0:
4246 prout(_("Engineer Scott- \"I'm doing my best, Captain,"))
4247 prout(_(" but right now we can only go warp 4.\""))
4249 if scanner.real > 10.0:
4250 prout(_("Helmsman Sulu- \"Our top speed is warp 10, Captain.\""))
4252 if scanner.real < 1.0:
4253 prout(_("Helmsman Sulu- \"We can't go below warp 1, Captain.\""))
4255 oldfac = game.warpfac
4256 game.warpfac = scanner.real
4257 if game.warpfac <= oldfac or game.warpfac <= 6.0:
4258 prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\"") %
4261 if game.warpfac < 8.00:
4262 prout(_("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\""))
4264 if game.warpfac == 10.0:
4265 prout(_("Engineer Scott- \"Aye, Captain, we'll try it.\""))
4267 prout(_("Engineer Scott- \"Aye, Captain, but our engines may not take it.\""))
4271 "Cope with being tossed out of quadrant by supernova or yanked by beam."
4273 # is captain on planet?
4275 if damaged(DTRANSP):
4278 prout(_("Scotty rushes to the transporter controls."))
4280 prout(_("But with the shields up it's hopeless."))
4282 prouts(_("His desperate attempt to rescue you . . ."))
4287 prout(_("SUCCEEDS!"))
4290 proutn(_("The crystals mined were "))
4298 # Check to see if captain in shuttle craft
4303 # Inform captain of attempt to reach safety
4307 prouts(_("***RED ALERT! RED ALERT!"))
4309 proutn(_("The %s has stopped in a quadrant containing") % crmshp())
4310 prouts(_(" a supernova."))
4312 prout(_("***Emergency automatic override attempts to hurl ")+crmshp())
4313 prout(_("safely out of quadrant."))
4314 if not damaged(DRADIO):
4315 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
4316 # Try to use warp engines
4317 if damaged(DWARPEN):
4319 prout(_("Warp engines damaged."))
4322 game.warpfac = randreal(6.0, 8.0)
4323 prout(_("Warp factor set to %d") % int(game.warpfac))
4324 power = 0.75*game.energy
4325 dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1))
4326 dist = max(dist, randreal(math.sqrt(2)))
4327 bugout = course(bearing=randreal(12), distance=dist) # How dumb!
4328 game.optime = bugout.time(game.warpfac)
4330 game.inorbit = False
4331 warp(bugout, involuntary=True)
4333 # This is bad news, we didn't leave quadrant.
4337 prout(_("Insufficient energy to leave quadrant."))
4340 # Repeat if another snova
4341 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
4344 finish(FWON) # Snova killed remaining enemy.
4347 "Let's do the time warp again."
4348 prout(_("***TIME WARP ENTERED."))
4349 if game.state.snap and withprob(0.5):
4351 prout(_("You are traveling backwards in time %d stardates.") %
4352 int(game.state.date-game.snapsht.date))
4353 game.state = game.snapsht
4354 game.state.snap = False
4355 if len(game.state.kcmdr):
4356 schedule(FTBEAM, expran(game.intime/len(game.state.kcmdr)))
4357 schedule(FBATTAK, expran(0.3*game.intime))
4358 schedule(FSNOVA, expran(0.5*game.intime))
4359 # next snapshot will be sooner
4360 schedule(FSNAP, expran(0.25*game.state.remtime))
4362 if game.state.nscrem:
4363 schedule(FSCMOVE, 0.2777)
4367 game.battle.invalidate()
4368 # Make sure Galileo is consistant -- Snapshot may have been taken
4369 # when on planet, which would give us two Galileos!
4371 for l in range(game.inplan):
4372 if game.state.planets[l].known == "shuttle_down":
4374 if game.iscraft == "onship" and game.ship=='E':
4375 prout(_("Chekov- \"Security reports the Galileo has disappeared, Sir!"))
4376 game.iscraft = "offship"
4377 # Likewise, if in the original time the Galileo was abandoned, but
4378 # was on ship earlier, it would have vanished -- let's restore it.
4379 if game.iscraft == "offship" and not gotit and game.damage[DSHUTTL] >= 0.0:
4380 prout(_("Chekov- \"Security reports the Galileo has reappeared in the dock!\""))
4381 game.iscraft = "onship"
4382 # There used to be code to do the actual reconstrction here,
4383 # but the starchart is now part of the snapshotted galaxy state.
4384 prout(_("Spock has reconstructed a correct star chart from memory"))
4386 # Go forward in time
4387 game.optime = expran(0.5*game.intime)
4388 prout(_("You are traveling forward in time %d stardates.") % int(game.optime))
4389 # cheat to make sure no tractor beams occur during time warp
4390 postpone(FTBEAM, game.optime)
4391 game.damage[DRADIO] += game.optime
4393 events() # Stas Sergeev added this -- do pending events
4396 "Launch deep-space probe."
4397 # New code to launch a deep space probe
4398 if game.nprobes == 0:
4401 if game.ship == 'E':
4402 prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\""))
4404 prout(_("Ye Faerie Queene has no deep space probes."))
4409 prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\""))
4411 if is_scheduled(FDSPROB):
4414 if damaged(DRADIO) and game.condition != "docked":
4415 prout(_("Spock- \"Records show the previous probe has not yet"))
4416 prout(_(" reached its destination.\""))
4418 prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""))
4420 key = scanner.nexttok()
4422 if game.nprobes == 1:
4423 prout(_("1 probe left."))
4425 prout(_("%d probes left") % game.nprobes)
4426 proutn(_("Are you sure you want to fire a probe? "))
4429 game.isarmed = False
4430 if key == "IHALPHA" and scanner.token == "armed":
4432 key = scanner.nexttok()
4433 elif key == "IHEOL":
4434 proutn(_("Arm NOVAMAX warhead? "))
4436 elif key == "IHREAL": # first element of course
4437 scanner.push(scanner.token)
4439 game.probe = getcourse(isprobe=True)
4443 schedule(FDSPROB, 0.01) # Time to move one sector
4444 prout(_("Ensign Chekov- \"The deep space probe is launched, Captain.\""))
4449 "Yell for help from nearest starbase."
4450 # There's more than one way to move in this game!
4452 # Test for conditions which prevent calling for help
4453 if game.condition == "docked":
4454 prout(_("Lt. Uhura- \"But Captain, we're already docked.\""))
4457 prout(_("Subspace radio damaged."))
4459 if not game.state.baseq:
4460 prout(_("Lt. Uhura- \"Captain, I'm not getting any response from Starbase.\""))
4463 prout(_("You must be aboard the %s.") % crmshp())
4465 # OK -- call for help from nearest starbase
4468 # There's one in this quadrant
4469 ddist = (game.base - game.sector).distance()
4471 ibq = None # Force base-quadrant game to persist past loop
4473 for ibq in game.state.baseq:
4474 xdist = QUADSIZE * (ibq - game.quadrant).distance()
4478 prout(_("No starbases remain. You are alone in a hostile galaxy."))
4480 # Since starbase not in quadrant, set up new quadrant
4483 # dematerialize starship
4484 game.quad[game.sector.i][game.sector.j]='.'
4485 proutn(_("Starbase in Quadrant %s responds--%s dematerializes") \
4486 % (game.quadrant, crmshp()))
4487 game.sector.invalidate()
4488 for m in range(1, 5+1):
4489 w = game.base.scatter()
4490 if w.valid_sector() and game.quad[w.i][w.j]=='.':
4491 # found one -- finish up
4494 if not game.sector.is_valid():
4495 prout(_("You have been lost in space..."))
4496 finish(FMATERIALIZE)
4498 # Give starbase three chances to rematerialize starship
4499 probf = math.pow((1.0 - math.pow(0.98,ddist)), 0.33333333)
4500 for m in range(1, 3+1):
4501 if m == 1: proutn(_("1st"))
4502 elif m == 2: proutn(_("2nd"))
4503 elif m == 3: proutn(_("3rd"))
4504 proutn(_(" attempt to re-materialize ") + crmshp())
4505 game.quad[game.sector.i][game.sector.j]=('-','o','O')[m-1]
4508 if randreal() > probf:
4512 curses.delay_output(500)
4514 game.quad[game.sector.i][game.sector.j]='?'
4517 setwnd(message_window)
4518 finish(FMATERIALIZE)
4520 game.quad[game.sector.i][game.sector.j]=game.ship
4522 prout(_("succeeds."))
4526 prout(_("Lt. Uhura- \"Captain, we made it!\""))
4531 if game.condition=="docked":
4533 prout(_("You cannot abandon Ye Faerie Queene."))
4536 # Must take shuttle craft to exit
4537 if game.damage[DSHUTTL]==-1:
4538 prout(_("Ye Faerie Queene has no shuttle craft."))
4540 if game.damage[DSHUTTL]<0:
4541 prout(_("Shuttle craft now serving Big Macs."))
4543 if game.damage[DSHUTTL]>0:
4544 prout(_("Shuttle craft damaged."))
4547 prout(_("You must be aboard the ship."))
4549 if game.iscraft != "onship":
4550 prout(_("Shuttle craft not currently available."))
4552 # Emit abandon ship messages
4554 prouts(_("***ABANDON SHIP! ABANDON SHIP!"))
4556 prouts(_("***ALL HANDS ABANDON SHIP!"))
4558 prout(_("Captain and crew escape in shuttle craft."))
4559 if not game.state.baseq:
4560 # Oops! no place to go...
4563 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
4565 if not (game.options & OPTION_WORLDS) and not damaged(DTRANSP):
4566 prout(_("Remainder of ship's complement beam down"))
4567 prout(_("to nearest habitable planet."))
4568 elif q.planet != None and not damaged(DTRANSP):
4569 prout(_("Remainder of ship's complement beam down to %s.") %
4572 prout(_("Entire crew of %d left to die in outer space.") %
4574 game.casual += game.state.crew
4575 game.abandoned += game.state.crew
4576 # If at least one base left, give 'em the Faerie Queene
4578 game.icrystl = False # crystals are lost
4579 game.nprobes = 0 # No probes
4580 prout(_("You are captured by Klingons and released to"))
4581 prout(_("the Federation in a prisoner-of-war exchange."))
4582 nb = randrange(len(game.state.baseq))
4583 # Set up quadrant and position FQ adjacient to base
4584 if not game.quadrant == game.state.baseq[nb]:
4585 game.quadrant = game.state.baseq[nb]
4586 game.sector.i = game.sector.j = 5
4589 # position next to base by trial and error
4590 game.quad[game.sector.i][game.sector.j] = '.'
4592 for l in range(QUADSIZE):
4593 game.sector = game.base.scatter()
4594 if game.sector.valid_sector() and \
4595 game.quad[game.sector.i][game.sector.j] == '.':
4598 break # found a spot
4599 game.sector.i=QUADSIZE/2
4600 game.sector.j=QUADSIZE/2
4602 # Get new commission
4603 game.quad[game.sector.i][game.sector.j] = game.ship = 'F'
4604 game.state.crew = FULLCREW
4605 prout(_("Starfleet puts you in command of another ship,"))
4606 prout(_("the Faerie Queene, which is antiquated but,"))
4607 prout(_("still useable."))
4609 prout(_("The dilithium crystals have been moved."))
4611 game.iscraft = "offship" # Galileo disappears
4613 game.condition="docked"
4614 for l in range(NDEVICES):
4615 game.damage[l] = 0.0
4616 game.damage[DSHUTTL] = -1
4617 game.energy = game.inenrg = 3000.0
4618 game.shield = game.inshld = 1250.0
4619 game.torps = game.intorps = 6
4620 game.lsupres=game.inlsr=3.0
4623 game.brigfree = game.brigcapacity = 300
4626 # Code from planets.c begins here.
4629 "Abort a lengthy operation if an event interrupts it."
4632 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.justin:
4637 "Report on (uninhabited) planets in the galaxy."
4641 prout(_("Spock- \"Planet report follows, Captain.\""))
4643 for i in range(game.inplan):
4644 if game.state.planets[i].pclass == "destroyed":
4646 if (game.state.planets[i].known != "unknown" \
4647 and not game.state.planets[i].inhabited) \
4650 if game.idebug and game.state.planets[i].known=="unknown":
4651 proutn("(Unknown) ")
4652 proutn(_("Quadrant %s") % game.state.planets[i].quadrant)
4653 proutn(_(" class "))
4654 proutn(game.state.planets[i].pclass)
4656 if game.state.planets[i].crystals != "present":
4658 prout(_("dilithium crystals present."))
4659 if game.state.planets[i].known=="shuttle_down":
4660 prout(_(" Shuttle Craft Galileo on surface."))
4662 prout(_("No information available."))
4665 "Enter standard orbit."
4669 prout(_("Already in standard orbit."))
4671 if damaged(DWARPEN) and damaged(DIMPULS):
4672 prout(_("Both warp and impulse engines damaged."))
4674 if not game.plnet.is_valid():
4675 prout("There is no planet in this sector.")
4677 if abs(game.sector.i-game.plnet.i)>1 or abs(game.sector.j-game.plnet.j)>1:
4678 prout(crmshp() + _(" not adjacent to planet."))
4681 game.optime = randreal(0.02, 0.05)
4682 prout(_("Helmsman Sulu- \"Entering standard orbit, Sir.\""))
4686 game.height = randreal(1400, 8600)
4687 prout(_("Sulu- \"Entered orbit at altitude %.2f kilometers.\"") % game.height)
4692 "Examine planets in this quadrant."
4693 if damaged(DSRSENS):
4694 if game.options & OPTION_TTY:
4695 prout(_("Short range sensors damaged."))
4697 if game.iplnet is None:
4698 if game.options & OPTION_TTY:
4699 prout(_("Spock- \"No planet in this quadrant, Captain.\""))
4701 if game.iplnet.known == "unknown":
4702 prout(_("Spock- \"Sensor scan for Quadrant %s-") % game.quadrant)
4704 prout(_(" Planet at Sector %s is of class %s.") %
4705 (game.plnet, game.iplnet.pclass))
4706 if game.iplnet.known=="shuttle_down":
4707 prout(_(" Sensors show Galileo still on surface."))
4708 proutn(_(" Readings indicate"))
4709 if game.iplnet.crystals != "present":
4711 prout(_(" dilithium crystals present.\""))
4712 if game.iplnet.known == "unknown":
4713 game.iplnet.known = "known"
4714 elif game.iplnet.inhabited:
4715 prout(_("Spock- \"The inhabited planet %s ") % game.iplnet.name)
4716 prout(_(" is located at Sector %s, Captain.\"") % game.plnet)
4719 "Use the transporter."
4723 if damaged(DTRANSP):
4724 prout(_("Transporter damaged."))
4725 if not damaged(DSHUTTL) and (game.iplnet.known=="shuttle_down" or game.iscraft == "onship"):
4727 proutn(_("Spock- \"May I suggest the shuttle craft, Sir?\" "))
4731 if not game.inorbit:
4732 prout(crmshp() + _(" not in standard orbit."))
4735 prout(_("Impossible to transport through shields."))
4737 if game.iplnet.known=="unknown":
4738 prout(_("Spock- \"Captain, we have no information on this planet"))
4739 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4740 prout(_(" you may not go down.\""))
4742 if not game.landed and game.iplnet.crystals=="absent":
4743 prout(_("Spock- \"Captain, I fail to see the logic in"))
4744 prout(_(" exploring a planet with no dilithium crystals."))
4745 proutn(_(" Are you sure this is wise?\" "))
4749 if not (game.options & OPTION_PLAIN):
4750 nrgneed = 50 * game.skill + game.height / 100.0
4751 if nrgneed > game.energy:
4752 prout(_("Engineering to bridge--"))
4753 prout(_(" Captain, we don't have enough energy for transportation."))
4755 if not game.landed and nrgneed * 2 > game.energy:
4756 prout(_("Engineering to bridge--"))
4757 prout(_(" Captain, we have enough energy only to transport you down to"))
4758 prout(_(" the planet, but there wouldn't be an energy for the trip back."))
4759 if game.iplnet.known == "shuttle_down":
4760 prout(_(" Although the Galileo shuttle craft may still be on a surface."))
4761 proutn(_(" Are you sure this is wise?\" "))
4766 # Coming from planet
4767 if game.iplnet.known=="shuttle_down":
4768 proutn(_("Spock- \"Wouldn't you rather take the Galileo?\" "))
4772 prout(_("Your crew hides the Galileo to prevent capture by aliens."))
4773 prout(_("Landing party assembled, ready to beam up."))
4775 prout(_("Kirk whips out communicator..."))
4776 prouts(_("BEEP BEEP BEEP"))
4778 prout(_("\"Kirk to enterprise- Lock on coordinates...energize.\""))
4781 prout(_("Scotty- \"Transporter room ready, Sir.\""))
4783 prout(_("Kirk and landing party prepare to beam down to planet surface."))
4785 prout(_("Kirk- \"Energize.\""))
4788 prouts("WWHOOOIIIIIRRRRREEEE.E.E. . . . . . .")
4790 if not withprob(0.98):
4791 prouts("BOOOIIIOOOIIOOOOIIIOIING . . .")
4793 prout(_("Scotty- \"Oh my God! I've lost them.\""))
4796 prouts(". . . . . . .E.E.EEEERRRRRIIIIIOOOHWW")
4797 game.landed = not game.landed
4798 game.energy -= nrgneed
4800 prout(_("Transport complete."))
4801 if game.landed and game.iplnet.known=="shuttle_down":
4802 prout(_("The shuttle craft Galileo is here!"))
4803 if not game.landed and game.imine:
4810 "Strip-mine a world for dilithium."
4814 prout(_("Mining party not on planet."))
4816 if game.iplnet.crystals == "mined":
4817 prout(_("This planet has already been strip-mined for dilithium."))
4819 elif game.iplnet.crystals == "absent":
4820 prout(_("No dilithium crystals on this planet."))
4823 prout(_("You've already mined enough crystals for this trip."))
4825 if game.icrystl and game.cryprob == 0.05:
4826 prout(_("With all those fresh crystals aboard the ") + crmshp())
4827 prout(_("there's no reason to mine more at this time."))
4829 game.optime = randreal(0.1, 0.3)*(ord(game.iplnet.pclass)-ord("L"))
4832 prout(_("Mining operation complete."))
4833 game.iplnet.crystals = "mined"
4834 game.imine = game.ididit = True
4837 "Use dilithium crystals."
4841 if not game.icrystl:
4842 prout(_("No dilithium crystals available."))
4844 if game.energy >= 1000:
4845 prout(_("Spock- \"Captain, Starfleet Regulations prohibit such an operation"))
4846 prout(_(" except when Condition Yellow exists."))
4848 prout(_("Spock- \"Captain, I must warn you that loading"))
4849 prout(_(" raw dilithium crystals into the ship's power"))
4850 prout(_(" system may risk a severe explosion."))
4851 proutn(_(" Are you sure this is wise?\" "))
4856 prout(_("Engineering Officer Scott- \"(GULP) Aye Sir."))
4857 prout(_(" Mr. Spock and I will try it.\""))
4859 prout(_("Spock- \"Crystals in place, Sir."))
4860 prout(_(" Ready to activate circuit.\""))
4862 prouts(_("Scotty- \"Keep your fingers crossed, Sir!\""))
4864 if withprob(game.cryprob):
4865 prouts(_(" \"Activating now! - - No good! It's***"))
4867 prouts(_("***RED ALERT! RED A*L********************************"))
4870 prouts(_("****************** KA-BOOM!!!! *******************"))
4874 game.energy += randreal(5000.0, 5500.0)
4875 prouts(_(" \"Activating now! - - "))
4876 prout(_("The instruments"))
4877 prout(_(" are going crazy, but I think it's"))
4878 prout(_(" going to work!! Congratulations, Sir!\""))
4883 "Use shuttlecraft for planetary jaunt."
4886 if damaged(DSHUTTL):
4887 if game.damage[DSHUTTL] == -1.0:
4888 if game.inorbit and game.iplnet.known == "shuttle_down":
4889 prout(_("Ye Faerie Queene has no shuttle craft bay to dock it at."))
4891 prout(_("Ye Faerie Queene had no shuttle craft."))
4892 elif game.damage[DSHUTTL] > 0:
4893 prout(_("The Galileo is damaged."))
4894 else: # game.damage[DSHUTTL] < 0
4895 prout(_("Shuttle craft is now serving Big Macs."))
4897 if not game.inorbit:
4898 prout(crmshp() + _(" not in standard orbit."))
4900 if (game.iplnet.known != "shuttle_down") and game.iscraft != "onship":
4901 prout(_("Shuttle craft not currently available."))
4903 if not game.landed and game.iplnet.known=="shuttle_down":
4904 prout(_("You will have to beam down to retrieve the shuttle craft."))
4906 if game.shldup or game.condition == "docked":
4907 prout(_("Shuttle craft cannot pass through shields."))
4909 if game.iplnet.known=="unknown":
4910 prout(_("Spock- \"Captain, we have no information on this planet"))
4911 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4912 prout(_(" you may not fly down.\""))
4914 game.optime = 3.0e-5*game.height
4915 if game.optime >= 0.8*game.state.remtime:
4916 prout(_("First Officer Spock- \"Captain, I compute that such"))
4917 proutn(_(" a maneuver would require approximately %2d%% of our") % \
4918 int(100*game.optime/game.state.remtime))
4919 prout(_("remaining time."))
4920 proutn(_("Are you sure this is wise?\" "))
4926 if game.iscraft == "onship":
4928 if not damaged(DTRANSP):
4929 proutn(_("Spock- \"Would you rather use the transporter?\" "))
4933 proutn(_("Shuttle crew"))
4935 proutn(_("Rescue party"))
4936 prout(_(" boards Galileo and swoops toward planet surface."))
4937 game.iscraft = "offship"
4941 game.iplnet.known="shuttle_down"
4942 prout(_("Trip complete."))
4945 # Ready to go back to ship
4946 prout(_("You and your mining party board the"))
4947 prout(_("shuttle craft for the trip back to the Enterprise."))
4949 prouts(_("The short hop begins . . ."))
4951 game.iplnet.known="known"
4957 game.iscraft = "onship"
4963 prout(_("Trip complete."))
4966 # Kirk on ship and so is Galileo
4967 prout(_("Mining party assembles in the hangar deck,"))
4968 prout(_("ready to board the shuttle craft \"Galileo\"."))
4970 prouts(_("The hangar doors open; the trip begins."))
4973 game.iscraft = "offship"
4976 game.iplnet.known = "shuttle_down"
4979 prout(_("Trip complete."))
4983 "Use the big zapper."
4987 if game.ship != 'E':
4988 prout(_("Ye Faerie Queene has no death ray."))
4990 if len(game.enemies)==0:
4991 prout(_("Sulu- \"But Sir, there are no enemies in this quadrant.\""))
4994 prout(_("Death Ray is damaged."))
4996 prout(_("Spock- \"Captain, the 'Experimental Death Ray'"))
4997 prout(_(" is highly unpredictible. Considering the alternatives,"))
4998 proutn(_(" are you sure this is wise?\" "))
5001 prout(_("Spock- \"Acknowledged.\""))
5004 prouts(_("WHOOEE ... WHOOEE ... WHOOEE ... WHOOEE"))
5006 prout(_("Crew scrambles in emergency preparation."))
5007 prout(_("Spock and Scotty ready the death ray and"))
5008 prout(_("prepare to channel all ship's power to the device."))
5010 prout(_("Spock- \"Preparations complete, sir.\""))
5011 prout(_("Kirk- \"Engage!\""))
5013 prouts(_("WHIRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"))
5016 if game.options & OPTION_PLAIN:
5020 prouts(_("Sulu- \"Captain! It's working!\""))
5022 while len(game.enemies) > 0:
5023 deadkl(game.enemies[1].location, game.quad[game.enemies[1].location.i][game.enemies[1].location.j],game.enemies[1].location)
5024 prout(_("Ensign Chekov- \"Congratulations, Captain!\""))
5025 if game.unwon() == 0:
5027 if (game.options & OPTION_PLAIN) == 0:
5028 prout(_("Spock- \"Captain, I believe the `Experimental Death Ray'"))
5030 prout(_(" is still operational.\""))
5032 prout(_(" has been rendered nonfunctional.\""))
5033 game.damage[DDRAY] = 39.95
5035 r = randreal() # Pick failure method
5037 prouts(_("Sulu- \"Captain! It's working!\""))
5039 prouts(_("***RED ALERT! RED ALERT!"))
5041 prout(_("***MATTER-ANTIMATTER IMPLOSION IMMINENT!"))
5043 prouts(_("***RED ALERT! RED A*L********************************"))
5046 prouts(_("****************** KA-BOOM!!!! *******************"))
5051 prouts(_("Sulu- \"Captain! Yagabandaghangrapl, brachriigringlanbla!\""))
5053 prout(_("Lt. Uhura- \"Graaeek! Graaeek!\""))
5055 prout(_("Spock- \"Fascinating! . . . All humans aboard"))
5056 prout(_(" have apparently been transformed into strange mutations."))
5057 prout(_(" Vulcans do not seem to be affected."))
5059 prout(_("Kirk- \"Raauch! Raauch!\""))
5063 prouts(_("Sulu- \"Captain! It's --WHAT?!?!\""))
5065 proutn(_("Spock- \"I believe the word is"))
5066 prouts(_(" *ASTONISHING*"))
5067 prout(_(" Mr. Sulu."))
5068 for i in range(QUADSIZE):
5069 for j in range(QUADSIZE):
5070 if game.quad[i][j] == '.':
5071 game.quad[i][j] = '?'
5072 prout(_(" Captain, our quadrant is now infested with"))
5073 prouts(_(" - - - - - - *THINGS*."))
5075 prout(_(" I have no logical explanation.\""))
5077 prouts(_("Sulu- \"Captain! The Death Ray is creating tribbles!\""))
5079 prout(_("Scotty- \"There are so many tribbles down here"))
5080 prout(_(" in Engineering, we can't move for 'em, Captain.\""))
5084 # Code from reports.c begins here
5086 def attackreport(curt):
5087 "eport status of bases under attack."
5089 if is_scheduled(FCDBAS):
5090 prout(_("Starbase in Quadrant %s is currently under Commander attack.") % game.battle)
5091 prout(_("It can hold out until Stardate %d.") % int(scheduled(FCDBAS)))
5092 elif game.isatb == 1:
5093 prout(_("Starbase in Quadrant %s is under Super-commander attack.") % game.state.kscmdr)
5094 prout(_("It can hold out until Stardate %d.") % int(scheduled(FSCDBAS)))
5096 prout(_("No Starbase is currently under attack."))
5098 if is_scheduled(FCDBAS):
5099 proutn(_("Base in %s attacked by C. Alive until %.1f") % (game.battle, scheduled(FCDBAS)))
5101 proutn(_("Base in %s attacked by S. Alive until %.1f") % (game.state.kscmdr, scheduled(FSCDBAS)))
5105 # report on general game status
5107 s1 = (game.thawed and _("thawed ")) or ""
5108 s2 = {1:"short", 2:"medium", 4:"long"}[game.length]
5109 s3 = (None, _("novice"), _("fair"),
5110 _("good"), _("expert"), _("emeritus"))[game.skill]
5111 prout(_("You %s a %s%s %s game.") % ((_("were playing"), _("are playing"))[game.alldone], s1, s2, s3))
5112 if game.skill>SKILL_GOOD and game.thawed and not game.alldone:
5113 prout(_("No plaque is allowed."))
5115 prout(_("This is tournament game %d.") % game.tourn)
5116 prout(_("Your secret password is \"%s\"") % game.passwd)
5117 proutn(_("%d of %d Klingons have been killed") % (((game.inkling + game.incom + game.inscom) - game.unwon()),
5118 (game.inkling + game.incom + game.inscom)))
5119 if game.incom - len(game.state.kcmdr):
5120 prout(_(", including %d Commander%s.") % (game.incom - len(game.state.kcmdr), (_("s"), "")[(game.incom - len(game.state.kcmdr))==1]))
5121 elif game.inkling - game.remkl() + (game.inscom - game.state.nscrem) > 0:
5122 prout(_(", but no Commanders."))
5125 if game.skill > SKILL_FAIR:
5126 prout(_("The Super Commander has %sbeen destroyed.") % ("", _("not "))[game.state.nscrem])
5127 if len(game.state.baseq) != game.inbase:
5129 if game.inbase-len(game.state.baseq)==1:
5130 proutn(_("has been 1 base"))
5132 proutn(_("have been %d bases") % (game.inbase-len(game.state.baseq)))
5133 prout(_(" destroyed, %d remaining.") % len(game.state.baseq))
5135 prout(_("There are %d bases.") % game.inbase)
5136 if communicating() or game.iseenit:
5137 # Don't report this if not seen and
5138 # either the radio is dead or not at base!
5142 prout(_("%d casualt%s suffered so far.") % (game.casual, ("y", "ies")[game.casual!=1]))
5143 if game.brigcapacity != game.brigfree:
5144 embriggened = brigcapacity-brigfree
5145 if embriggened == 1:
5146 prout(_("1 Klingon in brig"))
5148 prout(_("%d Klingons in brig.") % embriggened)
5149 if game.kcaptured == 0:
5151 elif game.kcaptured == 1:
5152 prout(_("1 captured Klingon turned in to Starfleet."))
5154 prout(_("%d captured Klingons turned in to Star Fleet.") % game.kcaptured)
5156 prout(_("There were %d call%s for help.") % (game.nhelp, ("" , _("s"))[game.nhelp!=1]))
5157 if game.ship == 'E':
5158 proutn(_("You have "))
5160 proutn("%d" % (game.nprobes))
5163 proutn(_(" deep space probe"))
5167 if communicating() and is_scheduled(FDSPROB):
5169 proutn(_("An armed deep space probe is in "))
5171 proutn(_("A deep space probe is in "))
5172 prout("Quadrant %s." % game.probe.quadrant())
5174 if game.cryprob <= .05:
5175 prout(_("Dilithium crystals aboard ship... not yet used."))
5179 while game.cryprob > ai:
5182 prout(_("Dilithium crystals have been used %d time%s.") % \
5183 (i, (_("s"), "")[i==1]))
5187 "Long-range sensor scan."
5188 if damaged(DLRSENS):
5189 # Now allow base's sensors if docked
5190 if game.condition != "docked":
5192 prout(_("LONG-RANGE SENSORS DAMAGED."))
5195 prout(_("Starbase's long-range scan"))
5197 prout(_("Long-range scan"))
5198 for x in range(game.quadrant.i-1, game.quadrant.i+2):
5201 for y in range(game.quadrant.j-1, game.quadrant.j+2):
5202 if not Coord(x, y).valid_quadrant():
5206 if not damaged(DRADIO):
5207 game.state.galaxy[x][y].charted = True
5208 game.state.chart[x][y].klingons = game.state.galaxy[x][y].klingons
5209 game.state.chart[x][y].starbase = game.state.galaxy[x][y].starbase
5210 game.state.chart[x][y].stars = game.state.galaxy[x][y].stars
5211 if not silent and game.state.galaxy[x][y].supernova:
5214 cn = " %3d" % (game.state.chart[x][y].klingons*100 + game.state.chart[x][y].starbase * 10 + game.state.chart[x][y].stars)
5215 proutn(((3 - len(cn)) * '.') + cn)
5223 for i in range(NDEVICES):
5226 prout(_("\tDEVICE\t\t\t-REPAIR TIMES-"))
5227 prout(_("\t\t\tIN FLIGHT\t\tDOCKED"))
5229 prout(" %-26s\t%8.2f\t\t%8.2f" % (device[i],
5230 game.damage[i]+0.05,
5231 DOCKFAC*game.damage[i]+0.005))
5233 prout(_("All devices functional."))
5236 "Update the chart in the Enterprise's computer from galaxy data."
5237 game.lastchart = game.state.date
5238 for i in range(GALSIZE):
5239 for j in range(GALSIZE):
5240 if game.state.galaxy[i][j].charted:
5241 game.state.chart[i][j].klingons = game.state.galaxy[i][j].klingons
5242 game.state.chart[i][j].starbase = game.state.galaxy[i][j].starbase
5243 game.state.chart[i][j].stars = game.state.galaxy[i][j].stars
5246 "Display the star chart."
5248 if (game.options & OPTION_AUTOSCAN):
5252 if game.lastchart < game.state.date and game.condition == "docked":
5253 prout(_("Spock- \"I revised the Star Chart from the starbase's records.\""))
5255 prout(_(" STAR CHART FOR THE KNOWN GALAXY"))
5256 if game.state.date > game.lastchart:
5257 prout(_("(Last surveillance update %d stardates ago).") % ((int)(game.state.date-game.lastchart)))
5258 prout(" 1 2 3 4 5 6 7 8")
5259 for i in range(GALSIZE):
5260 proutn("%d |" % (i+1))
5261 for j in range(GALSIZE):
5262 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5266 if game.state.galaxy[i][j].supernova:
5268 elif not game.state.galaxy[i][j].charted and game.state.galaxy[i][j].starbase:
5270 elif game.state.galaxy[i][j].charted:
5271 show = "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars)
5275 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5283 def sectscan(goodScan, i, j):
5284 "Light up an individual dot in a sector."
5285 if goodScan or (abs(i-game.sector.i)<= 1 and abs(j-game.sector.j) <= 1):
5286 if game.quad[i][j] in ('E', 'F'):
5289 textcolor({"green":GREEN,
5293 "dead":BROWN}[game.condition])
5295 textcolor({'?':LIGHTMAGENTA,
5301 }.get(game.quad[i][j], DEFAULT))
5302 proutn("%c " % game.quad[i][j])
5308 "Emit status report lines"
5309 if not req or req == 1:
5310 prstat(_("Stardate"), _("%.1f, Time Left %.2f") \
5311 % (game.state.date, game.state.remtime))
5312 if not req or req == 2:
5313 if game.condition != "docked":
5315 prstat(_("Condition"), _("%s, %i DAMAGES") % \
5316 (game.condition.upper(), sum([x > 0 for x in game.damage])))
5318 prout(_(", CLOAKED"))
5319 if not req or req == 3:
5320 prstat(_("Position"), "%s , %s" % (game.quadrant, game.sector))
5321 if not req or req == 4:
5322 if damaged(DLIFSUP):
5323 if game.condition == "docked":
5324 s = _("DAMAGED, Base provides")
5326 s = _("DAMAGED, reserves=%4.2f") % game.lsupres
5329 prstat(_("Life Support"), s)
5330 if not req or req == 5:
5331 prstat(_("Warp Factor"), "%.1f" % game.warpfac)
5332 if not req or req == 6:
5334 if game.icrystl and (game.options & OPTION_SHOWME):
5335 extra = _(" (have crystals)")
5336 prstat(_("Energy"), "%.2f%s" % (game.energy, extra))
5337 if not req or req == 7:
5338 prstat(_("Torpedoes"), "%d" % (game.torps))
5339 if not req or req == 8:
5340 if damaged(DSHIELD):
5346 data = _(" %d%% %.1f units") \
5347 % (int((100.0*game.shield)/game.inshld + 0.5), game.shield)
5348 prstat(_("Shields"), s+data)
5349 if not req or req == 9:
5350 prstat(_("Klingons Left"), "%d" % game.unwon())
5351 if not req or req == 10:
5352 if game.options & OPTION_WORLDS:
5353 plnet = game.state.galaxy[game.quadrant.i][game.quadrant.j].planet
5354 if plnet and plnet.inhabited:
5355 prstat(_("Major system"), plnet.name)
5357 prout(_("Sector is uninhabited"))
5358 elif not req or req == 11:
5359 attackreport(not req)
5362 "Request specified status data, a historical relic from slow TTYs."
5363 requests = ("da","co","po","ls","wa","en","to","sh","kl","sy", "ti")
5364 while scanner.nexttok() == "IHEOL":
5365 proutn(_("Information desired? "))
5367 if scanner.token in requests:
5368 status(requests.index(scanner.token))
5370 prout(_("UNRECOGNIZED REQUEST. Legal requests are:"))
5371 prout((" date, condition, position, lsupport, warpfactor,"))
5372 prout((" energy, torpedoes, shields, klingons, system, time."))
5377 if damaged(DSRSENS):
5378 # Allow base's sensors if docked
5379 if game.condition != "docked":
5380 prout(_(" S.R. SENSORS DAMAGED!"))
5383 prout(_(" [Using Base's sensors]"))
5385 prout(_(" Short-range scan"))
5386 if goodScan and communicating():
5387 game.state.chart[game.quadrant.i][game.quadrant.j].klingons = game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons
5388 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase
5389 game.state.chart[game.quadrant.i][game.quadrant.j].stars = game.state.galaxy[game.quadrant.i][game.quadrant.j].stars
5390 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
5391 prout(" 1 2 3 4 5 6 7 8 9 10")
5392 if game.condition != "docked":
5394 for i in range(QUADSIZE):
5395 proutn("%2d " % (i+1))
5396 for j in range(QUADSIZE):
5397 sectscan(goodScan, i, j)
5401 "Use computer to get estimated time of arrival for a warp jump."
5402 w1 = Coord(); w2 = Coord()
5404 if damaged(DCOMPTR):
5405 prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR."))
5408 if scanner.nexttok() != "IHREAL":
5411 proutn(_("Destination quadrant and/or sector? "))
5412 if scanner.nexttok()!="IHREAL":
5415 w1.j = int(scanner.real-0.5)
5416 if scanner.nexttok() != "IHREAL":
5419 w1.i = int(scanner.real-0.5)
5420 if scanner.nexttok() == "IHREAL":
5421 w2.j = int(scanner.real-0.5)
5422 if scanner.nexttok() != "IHREAL":
5425 w2.i = int(scanner.real-0.5)
5427 if game.quadrant.j>w1.i:
5431 if game.quadrant.i>w1.j:
5435 if not w1.valid_quadrant() or not w2.valid_sector():
5438 dist = math.sqrt((w1.j-game.quadrant.j+(w2.j-game.sector.j)/(QUADSIZE*1.0))**2+
5439 (w1.i-game.quadrant.i+(w2.i-game.sector.i)/(QUADSIZE*1.0))**2)
5442 prout(_("Answer \"no\" if you don't know the value:"))
5445 proutn(_("Time or arrival date? "))
5446 if scanner.nexttok()=="IHREAL":
5447 ttime = scanner.real
5448 if ttime > game.state.date:
5449 ttime -= game.state.date # Actually a star date
5450 twarp=(math.floor(math.sqrt((10.0*dist)/ttime)*10.0)+1.0)/10.0
5451 if ttime <= 1e-10 or twarp > 10:
5452 prout(_("We'll never make it, sir."))
5459 proutn(_("Warp factor? "))
5460 if scanner.nexttok()== "IHREAL":
5462 twarp = scanner.real
5463 if twarp<1.0 or twarp > 10.0:
5467 prout(_("Captain, certainly you can give me one of these."))
5470 ttime = (10.0*dist)/twarp**2
5471 tpower = dist*twarp*twarp*twarp*(game.shldup+1)
5472 if tpower >= game.energy:
5473 prout(_("Insufficient energy, sir."))
5474 if not game.shldup or tpower > game.energy*2.0:
5477 proutn(_("New warp factor to try? "))
5478 if scanner.nexttok() == "IHREAL":
5480 twarp = scanner.real
5481 if twarp<1.0 or twarp > 10.0:
5489 prout(_("But if you lower your shields,"))
5490 proutn(_("remaining"))
5493 proutn(_("Remaining"))
5494 prout(_(" energy will be %.2f.") % (game.energy-tpower))
5496 prout(_("And we will arrive at stardate %.2f.") % (game.state.date+ttime))
5498 prout(_("Any warp speed is adequate."))
5500 prout(_("Minimum warp needed is %.2f,") % (twarp))
5501 prout(_("and we will arrive at stardate %.2f.") % (game.state.date+ttime))
5502 if game.state.remtime < ttime:
5503 prout(_("Unfortunately, the Federation will be destroyed by then."))
5505 prout(_("You'll be taking risks at that speed, Captain"))
5506 if (game.isatb==1 and game.state.kscmdr == w1 and \
5507 scheduled(FSCDBAS)< ttime+game.state.date) or \
5508 (scheduled(FCDBAS)<ttime+game.state.date and game.battle == w1):
5509 prout(_("The starbase there will be destroyed by then."))
5510 proutn(_("New warp factor to try? "))
5511 if scanner.nexttok() == "IHREAL":
5513 twarp = scanner.real
5514 if twarp<1.0 or twarp > 10.0:
5522 # Code from setup.c begins here
5525 "Issue a historically correct banner."
5527 prout(_("-SUPER- STAR TREK"))
5529 # From the FORTRAN original
5530 # prout(_("Latest update-21 Sept 78"))
5536 scanner.push("emsave.trk")
5537 key = scanner.nexttok()
5539 proutn(_("File name: "))
5540 key = scanner.nexttok()
5541 if key != "IHALPHA":
5544 if '.' not in scanner.token:
5545 scanner.token += ".trk"
5547 fp = open(scanner.token, "wb")
5549 prout(_("Can't freeze game as file %s") % scanner.token)
5551 pickle.dump(game, fp)
5556 "Retrieve saved game."
5559 key = scanner.nexttok()
5561 proutn(_("File name: "))
5562 key = scanner.nexttok()
5563 if key != "IHALPHA":
5566 if '.' not in scanner.token:
5567 scanner.token += ".trk"
5569 fp = open(scanner.token, "rb")
5571 prout(_("Can't thaw game in %s") % scanner.token)
5573 game = pickle.load(fp)
5578 # I used <http://www.memory-alpha.org> to find planets
5579 # with references in ST:TOS. Earth and the Alpha Centauri
5580 # Colony have been omitted.
5582 # Some planets marked Class G and P here will be displayed as class M
5583 # because of the way planets are generated. This is a known bug.
5586 _("Andoria (Fesoan)"), # several episodes
5587 _("Tellar Prime (Miracht)"), # TOS: "Journey to Babel"
5588 _("Vulcan (T'Khasi)"), # many episodes
5589 _("Medusa"), # TOS: "Is There in Truth No Beauty?"
5590 _("Argelius II (Nelphia)"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5591 _("Ardana"), # TOS: "The Cloud Minders"
5592 _("Catulla (Cendo-Prae)"), # TOS: "The Way to Eden"
5593 _("Gideon"), # TOS: "The Mark of Gideon"
5594 _("Aldebaran III"), # TOS: "The Deadly Years"
5595 _("Alpha Majoris I"), # TOS: "Wolf in the Fold"
5596 _("Altair IV"), # TOS: "Amok Time
5597 _("Ariannus"), # TOS: "Let That Be Your Last Battlefield"
5598 _("Benecia"), # TOS: "The Conscience of the King"
5599 _("Beta Niobe I (Sarpeidon)"), # TOS: "All Our Yesterdays"
5600 _("Alpha Carinae II"), # TOS: "The Ultimate Computer"
5601 _("Capella IV (Kohath)"), # TOS: "Friday's Child" (Class G)
5602 _("Daran V"), # TOS: "For the World is Hollow and I Have Touched the Sky"
5603 _("Deneb II"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5604 _("Eminiar VII"), # TOS: "A Taste of Armageddon"
5605 _("Gamma Canaris IV"), # TOS: "Metamorphosis"
5606 _("Gamma Tranguli VI (Vaalel)"), # TOS: "The Apple"
5607 _("Ingraham B"), # TOS: "Operation: Annihilate"
5608 _("Janus IV"), # TOS: "The Devil in the Dark"
5609 _("Makus III"), # TOS: "The Galileo Seven"
5610 _("Marcos XII"), # TOS: "And the Children Shall Lead",
5611 _("Omega IV"), # TOS: "The Omega Glory"
5612 _("Regulus V"), # TOS: "Amok Time
5613 _("Deneva"), # TOS: "Operation -- Annihilate!"
5614 # Worlds from BSD Trek
5615 _("Rigel II"), # TOS: "Shore Leave" ("III" in BSD)
5616 _("Beta III"), # TOS: "The Return of the Archons"
5617 _("Triacus"), # TOS: "And the Children Shall Lead",
5618 _("Exo III"), # TOS: "What Are Little Girls Made Of?" (Class P)
5620 # _("Hansen's Planet"), # TOS: "The Galileo Seven"
5621 # _("Taurus IV"), # TOS: "The Galileo Seven" (class G)
5622 # _("Antos IV (Doraphane)"), # TOS: "Whom Gods Destroy", "Who Mourns for Adonais?"
5623 # _("Izar"), # TOS: "Whom Gods Destroy"
5624 # _("Tiburon"), # TOS: "The Way to Eden"
5625 # _("Merak II"), # TOS: "The Cloud Minders"
5626 # _("Coridan (Desotriana)"), # TOS: "Journey to Babel"
5627 # _("Iotia"), # TOS: "A Piece of the Action"
5631 _("S. R. Sensors"), \
5632 _("L. R. Sensors"), \
5634 _("Photon Tubes"), \
5635 _("Life Support"), \
5636 _("Warp Engines"), \
5637 _("Impulse Engines"), \
5639 _("Subspace Radio"), \
5640 _("Shuttle Craft"), \
5642 _("Navigation System"), \
5644 _("Shield Control"), \
5647 _("Cloaking Device"), \
5651 "Prepare to play, set up cosmos."
5653 # Decide how many of everything
5655 return # frozen game
5656 # Prepare the Enterprise
5657 game.alldone = game.gamewon = game.shldchg = game.shldup = False
5659 game.state.crew = FULLCREW
5660 game.energy = game.inenrg = 5000.0
5661 game.shield = game.inshld = 2500.0
5664 game.quadrant = randplace(GALSIZE)
5665 game.sector = randplace(QUADSIZE)
5666 game.torps = game.intorps = 10
5667 game.nprobes = randrange(2, 5)
5669 for i in range(NDEVICES):
5670 game.damage[i] = 0.0
5671 # Set up assorted game parameters
5672 game.battle = Coord()
5673 game.state.date = game.indate = 100.0 * randreal(20, 51)
5674 game.nkinks = game.nhelp = game.casual = game.abandoned = 0
5675 game.iscate = game.resting = game.imine = game.icrystl = game.icraft = False
5676 game.isatb = game.state.nplankl = 0
5677 game.state.starkl = game.state.basekl = game.state.nworldkl = 0
5678 game.iscraft = "onship"
5683 game.state.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
5685 game.state.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
5687 game.state.planets = [] # Planet information
5688 game.state.baseq = [] # Base quadrant coordinates
5689 game.state.kcmdr = [] # Commander quadrant coordinates
5690 game.statekscmdr = Coord() # Supercommander quadrant coordinates
5692 # Starchart is functional but we've never seen it
5693 game.lastchart = FOREVER
5694 # Put stars in the galaxy
5696 for i in range(GALSIZE):
5697 for j in range(GALSIZE):
5698 # Can't have more stars per quadrant than fit in one decimal digit,
5699 # if we do the chart representation will break.
5700 k = randrange(1, min(10, QUADSIZE**2/10))
5702 game.state.galaxy[i][j].stars = k
5703 # Locate star bases in galaxy
5705 prout("=== Allocating %d bases" % game.inbase)
5706 for i in range(game.inbase):
5709 w = randplace(GALSIZE)
5710 if not game.state.galaxy[w.i][w.j].starbase:
5713 # C version: for (j = i-1; j > 0; j--)
5714 # so it did them in the opposite order.
5715 for j in range(1, i):
5716 # Improved placement algorithm to spread out bases
5717 distq = (w - game.state.baseq[j]).distance()
5718 if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75):
5721 prout("=== Abandoning base #%d at %s" % (i, w))
5723 elif distq < 6.0 * (BASEMAX+1-game.inbase):
5725 prout("=== Saving base #%d, close to #%d" % (i, j))
5729 prout("=== Placing base #%d in quadrant %s" % (i, w))
5730 game.state.baseq.append(w)
5731 game.state.galaxy[w.i][w.j].starbase = game.state.chart[w.i][w.j].starbase = True
5732 # Position ordinary Klingon Battle Cruisers
5734 klumper = 0.25*game.skill*(9.0-game.length)+1.0
5735 if klumper > MAXKLQUAD:
5739 klump = int((1.0 - r*r)*klumper)
5744 w = randplace(GALSIZE)
5745 if not game.state.galaxy[w.i][w.j].supernova and \
5746 game.state.galaxy[w.i][w.j].klingons + klump <= MAXKLQUAD:
5748 game.state.galaxy[w.i][w.j].klingons += klump
5751 # Position Klingon Commander Ships
5752 for i in range(game.incom):
5754 w = randplace(GALSIZE)
5755 if not welcoming(w) or w in game.state.kcmdr:
5757 if (game.state.galaxy[w.i][w.j].klingons or withprob(0.25)):
5759 game.state.galaxy[w.i][w.j].klingons += 1
5760 game.state.kcmdr.append(w)
5761 # Locate planets in galaxy
5762 for i in range(game.inplan):
5764 w = randplace(GALSIZE)
5765 if game.state.galaxy[w.i][w.j].planet is None:
5769 new.crystals = "absent"
5770 if (game.options & OPTION_WORLDS) and i < NINHAB:
5771 new.pclass = "M" # All inhabited planets are class M
5772 new.crystals = "absent"
5774 new.name = systnames[i]
5775 new.inhabited = True
5777 new.pclass = ("M", "N", "O")[randrange(0, 3)]
5779 new.crystals = "present"
5780 new.known = "unknown"
5781 new.inhabited = False
5782 game.state.galaxy[w.i][w.j].planet = new
5783 game.state.planets.append(new)
5785 for i in range(game.state.nromrem):
5786 w = randplace(GALSIZE)
5787 game.state.galaxy[w.i][w.j].romulans += 1
5788 # Place the Super-Commander if needed
5789 if game.state.nscrem > 0:
5791 w = randplace(GALSIZE)
5794 game.state.kscmdr = w
5795 game.state.galaxy[w.i][w.j].klingons += 1
5796 # Initialize times for extraneous events
5797 schedule(FSNOVA, expran(0.5 * game.intime))
5798 schedule(FTBEAM, expran(1.5 * (game.intime / len(game.state.kcmdr))))
5799 schedule(FSNAP, randreal(1.0, 2.0)) # Force an early snapshot
5800 schedule(FBATTAK, expran(0.3*game.intime))
5802 if game.state.nscrem:
5803 schedule(FSCMOVE, 0.2777)
5808 if (game.options & OPTION_WORLDS) and game.skill >= SKILL_GOOD:
5809 schedule(FDISTR, expran(1.0 + game.intime))
5814 # Place thing (in tournament game, we don't want one!)
5815 # New in SST2K: never place the Thing near a starbase.
5816 # This makes sense and avoids a special case in the old code.
5818 if game.tourn is None:
5820 thing = randplace(GALSIZE)
5821 if thing not in game.state.baseq:
5824 game.state.snap = False
5825 if game.skill == SKILL_NOVICE:
5826 prout(_("It is stardate %d. The Federation is being attacked by") % int(game.state.date))
5827 prout(_("a deadly Klingon invasion force. As captain of the United"))
5828 prout(_("Starship U.S.S. Enterprise, it is your mission to seek out"))
5829 prout(_("and destroy this invasion force of %d battle cruisers.") % ((game.inkling + game.incom + game.inscom)))
5830 prout(_("You have an initial allotment of %d stardates to complete") % int(game.intime))
5831 prout(_("your mission. As you proceed you may be given more time."))
5833 prout(_("You will have %d supporting starbases.") % (game.inbase))
5834 proutn(_("Starbase locations- "))
5836 prout(_("Stardate %d.") % int(game.state.date))
5838 prout(_("%d Klingons.") % (game.inkling + game.incom + game.inscom))
5839 prout(_("An unknown number of Romulans."))
5840 if game.state.nscrem:
5841 prout(_("And one (GULP) Super-Commander."))
5842 prout(_("%d stardates.") % int(game.intime))
5843 proutn(_("%d starbases in ") % game.inbase)
5844 for i in range(game.inbase):
5845 proutn(repr(game.state.baseq[i]))
5848 proutn(_("The Enterprise is currently in Quadrant %s") % game.quadrant)
5849 proutn(_(" Sector %s") % game.sector)
5851 prout(_("Good Luck!"))
5852 if game.state.nscrem:
5853 prout(_(" YOU'LL NEED IT."))
5856 setwnd(message_window)
5858 if len(game.enemies) - (thing == game.quadrant) - (game.tholian != None):
5860 if game.neutz: # bad luck to start in a Romulan Neutral Zone
5861 attack(torps_ok=False)
5864 "Choose your game type."
5866 game.tourn = game.length = 0
5868 game.skill = SKILL_NONE
5869 # Do not chew here, we want to use command-line tokens
5870 if not scanner.inqueue: # Can start with command line options
5871 proutn(_("Would you like a regular, tournament, or saved game? "))
5873 if scanner.sees("tournament"):
5874 while scanner.nexttok() == "IHEOL":
5875 proutn(_("Type in tournament number-"))
5876 if scanner.real == 0:
5878 continue # We don't want a blank entry
5879 game.tourn = int(round(scanner.real))
5880 random.seed(scanner.real)
5882 logfp.write("# random.seed(%d)\n" % scanner.real)
5884 if scanner.sees("saved") or scanner.sees("frozen"):
5888 if game.passwd is None:
5890 if not game.alldone:
5891 game.thawed = True # No plaque if not finished
5895 if scanner.sees("regular"):
5897 proutn(_("What is \"%s\"? ") % scanner.token)
5899 while game.length==0 or game.skill==SKILL_NONE:
5900 if scanner.nexttok() == "IHALPHA":
5901 if scanner.sees("short"):
5903 elif scanner.sees("medium"):
5905 elif scanner.sees("long"):
5907 elif scanner.sees("novice"):
5908 game.skill = SKILL_NOVICE
5909 elif scanner.sees("fair"):
5910 game.skill = SKILL_FAIR
5911 elif scanner.sees("good"):
5912 game.skill = SKILL_GOOD
5913 elif scanner.sees("expert"):
5914 game.skill = SKILL_EXPERT
5915 elif scanner.sees("emeritus"):
5916 game.skill = SKILL_EMERITUS
5918 proutn(_("What is \""))
5919 proutn(scanner.token)
5924 proutn(_("Would you like a Short, Medium, or Long game? "))
5925 elif game.skill == SKILL_NONE:
5926 proutn(_("Are you a Novice, Fair, Good, Expert, or Emeritus player? "))
5927 # Choose game options -- added by ESR for SST2K
5928 if scanner.nexttok() != "IHALPHA":
5930 proutn(_("Choose your game style (plain, almy, fancy or just press enter): "))
5932 if scanner.sees("plain"):
5933 # Approximates the UT FORTRAN version.
5934 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)
5935 game.options |= OPTION_PLAIN
5936 elif scanner.sees("almy"):
5937 # Approximates Tom Almy's version.
5938 game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS | OPTION_COLOR)
5939 game.options |= OPTION_ALMY
5940 elif scanner.sees("fancy") or scanner.sees("\n"):
5942 elif len(scanner.token):
5943 proutn(_("What is \"%s\"?") % scanner.token)
5945 if game.passwd == "debug":
5947 prout("=== Debug mode enabled.")
5948 # Use parameters to generate initial values of things
5949 game.damfac = 0.5 * game.skill
5950 game.inbase = randrange(BASEMIN, BASEMAX+1)
5952 if game.options & OPTION_PLANETS:
5953 game.inplan += randrange(MAXUNINHAB/2, MAXUNINHAB+1)
5954 if game.options & OPTION_WORLDS:
5955 game.inplan += int(NINHAB)
5956 game.state.nromrem = game.inrom = randrange(2 * game.skill)
5957 game.state.nscrem = game.inscom = (game.skill > SKILL_FAIR)
5958 game.state.remtime = 7.0 * game.length
5959 game.intime = game.state.remtime
5960 game.inkling = int(2.0*game.intime*((game.skill+1 - 2*randreal())*game.skill*0.1+.15))
5961 game.incom = min(MINCMDR, int(game.skill + 0.0625*game.inkling*randreal()))
5962 game.state.remres = (game.inkling+4*game.incom)*game.intime
5963 game.inresor = game.state.remres
5964 if game.inkling > 50:
5968 def dropin(iquad=None):
5969 "Drop a feature on a random dot in the current quadrant."
5971 w = randplace(QUADSIZE)
5972 if game.quad[w.i][w.j] == '.':
5974 if iquad is not None:
5975 game.quad[w.i][w.j] = iquad
5979 "Update our alert status."
5980 game.condition = "green"
5981 if game.energy < 1000.0:
5982 game.condition = "yellow"
5983 if game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons or game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans:
5984 game.condition = "red"
5986 game.condition="dead"
5989 "Drop new Klingon into current quadrant."
5990 return Enemy('K', loc=dropin(), power=randreal(300,450)+25.0*game.skill)
5993 "Sort enemies by distance so 'nearest' is meaningful."
5994 game.enemies.sort(key=lambda x: x.kdist)
5997 "Set up a new state of quadrant, for when we enter or re-enter it."
6000 game.neutz = game.inorbit = game.landed = False
6001 game.ientesc = game.iseenit = game.isviolreported = False
6002 # Create a blank quadrant
6003 game.quad = fill2d(QUADSIZE, lambda i, j: '.')
6005 # Attempt to escape Super-commander, so tbeam back!
6008 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
6009 # cope with supernova
6012 game.klhere = q.klingons
6013 game.irhere = q.romulans
6015 game.quad[game.sector.i][game.sector.j] = game.ship
6018 # Position ordinary Klingons
6019 for _i in range(game.klhere):
6021 # If we need a commander, promote a Klingon
6022 for cmdr in game.state.kcmdr:
6023 if cmdr == game.quadrant:
6024 e = game.enemies[game.klhere-1]
6025 game.quad[e.location.i][e.location.j] = 'C'
6026 e.power = randreal(950,1350) + 50.0*game.skill
6028 # If we need a super-commander, promote a Klingon
6029 if game.quadrant == game.state.kscmdr:
6031 game.quad[e.location.i][e.location.j] = 'S'
6032 e.power = randreal(1175.0, 1575.0) + 125.0*game.skill
6033 game.iscate = (game.remkl() > 1)
6034 # Put in Romulans if needed
6035 for _i in range(q.romulans):
6036 Enemy('R', loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill)
6037 # If quadrant needs a starbase, put it in
6039 game.base = dropin('B')
6040 # If quadrant needs a planet, put it in
6042 game.iplnet = q.planet
6043 if not q.planet.inhabited:
6044 game.plnet = dropin('P')
6046 game.plnet = dropin('@')
6047 # Check for condition
6050 if game.irhere > 0 and game.klhere == 0:
6052 if not damaged(DRADIO):
6054 prout(_("LT. Uhura- \"Captain, an urgent message."))
6055 prout(_(" I'll put it on audio.\" CLICK"))
6057 prout(_("INTRUDER! YOU HAVE VIOLATED THE ROMULAN NEUTRAL ZONE."))
6058 prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!"))
6059 # Put in THING if needed
6060 if thing == game.quadrant:
6061 Enemy(etype='?', loc=dropin(),
6062 power=randreal(6000,6500.0)+250.0*game.skill)
6063 if not damaged(DSRSENS):
6065 prout(_("Mr. Spock- \"Captain, this is most unusual."))
6066 prout(_(" Please examine your short-range scan.\""))
6067 # Decide if quadrant needs a Tholian; lighten up if skill is low
6068 if game.options & OPTION_THOLIAN:
6069 if (game.skill < SKILL_GOOD and withprob(0.02)) or \
6070 (game.skill == SKILL_GOOD and withprob(0.05)) or \
6071 (game.skill > SKILL_GOOD and withprob(0.08)):
6074 w.i = withprob(0.5) * (QUADSIZE-1)
6075 w.j = withprob(0.5) * (QUADSIZE-1)
6076 if game.quad[w.i][w.j] == '.':
6078 game.tholian = Enemy(etype='T', loc=w,
6079 power=randrange(100, 500) + 25.0*game.skill)
6080 # Reserve unoccupied corners
6081 if game.quad[0][0]=='.':
6082 game.quad[0][0] = 'X'
6083 if game.quad[0][QUADSIZE-1]=='.':
6084 game.quad[0][QUADSIZE-1] = 'X'
6085 if game.quad[QUADSIZE-1][0]=='.':
6086 game.quad[QUADSIZE-1][0] = 'X'
6087 if game.quad[QUADSIZE-1][QUADSIZE-1]=='.':
6088 game.quad[QUADSIZE-1][QUADSIZE-1] = 'X'
6090 # And finally the stars
6091 for _i in range(q.stars):
6093 # Put in a few black holes
6094 for _i in range(1, 3+1):
6097 # Take out X's in corners if Tholian present
6099 if game.quad[0][0]=='X':
6100 game.quad[0][0] = '.'
6101 if game.quad[0][QUADSIZE-1]=='X':
6102 game.quad[0][QUADSIZE-1] = '.'
6103 if game.quad[QUADSIZE-1][0]=='X':
6104 game.quad[QUADSIZE-1][0] = '.'
6105 if game.quad[QUADSIZE-1][QUADSIZE-1]=='X':
6106 game.quad[QUADSIZE-1][QUADSIZE-1] = '.'
6107 # This should guarantee that replay games don't lose info about the chart
6108 if (game.options & OPTION_AUTOSCAN) or replayfp:
6112 "Set the self-destruct password."
6113 if game.options & OPTION_PLAIN:
6116 proutn(_("Please type in a secret password- "))
6118 game.passwd = scanner.token
6119 if game.passwd != None:
6123 game.passwd += chr(ord('a')+randrange(26))
6124 game.passwd += chr(ord('a')+randrange(26))
6125 game.passwd += chr(ord('a')+randrange(26))
6127 # Code from sst.c begins here
6130 ("SRSCAN", OPTION_TTY),
6131 ("STATUS", OPTION_TTY),
6132 ("REQUEST", OPTION_TTY),
6133 ("LRSCAN", OPTION_TTY),
6145 ("SENSORS", OPTION_PLANETS),
6146 ("ORBIT", OPTION_PLANETS),
6147 ("TRANSPORT", OPTION_PLANETS),
6148 ("MINE", OPTION_PLANETS),
6149 ("CRYSTALS", OPTION_PLANETS),
6150 ("SHUTTLE", OPTION_PLANETS),
6151 ("PLANETS", OPTION_PLANETS),
6156 ("PROBE", OPTION_PROBE),
6158 ("FREEZE", 0), # Synonym for SAVE
6162 ("CAPTURE", OPTION_CAPTURE),
6163 ("CLOAK", OPTION_CLOAK),
6166 ("SOS", 0), # Synonym for MAYDAY
6167 ("CALL", 0), # Synonym for MAYDAY
6176 "Generate a list of legal commands."
6177 prout(_("LEGAL COMMANDS ARE:"))
6179 for (key, opt) in commands:
6180 if not opt or (opt & game.options):
6181 proutn("%-12s " % key)
6183 if emitted % 5 == 4:
6188 "Browse on-line help."
6189 key = scanner.nexttok()
6192 setwnd(prompt_window)
6193 proutn(_("Help on what command? "))
6194 key = scanner.nexttok()
6195 setwnd(message_window)
6198 cmds = [x[0] for x in commands]
6199 if scanner.token.upper() in cmds or scanner.token.upper() == "ABBREV":
6206 cmd = scanner.token.upper()
6207 for directory in docpath:
6209 fp = open(os.path.join(directory, "sst.doc"), "r")
6214 prout(_("Spock- \"Captain, that information is missing from the"))
6215 prout(_(" computer. You need to find sst.doc and put it somewhere"))
6216 proutn(_(" in these directories: %s") % ":".join(docpath))
6218 # This used to continue: "You need to find SST.DOC and put
6219 # it in the current directory."
6222 linebuf = fp.readline()
6224 prout(_("Spock- \"Captain, there is no information on that command.\""))
6227 if linebuf[0] == '%' and linebuf[1] == '%' and linebuf[2] == ' ':
6228 linebuf = linebuf[3:].strip()
6229 if cmd.upper() == linebuf:
6232 prout(_("Spock- \"Captain, I've found the following information:\""))
6235 linebuf = fp.readline()
6236 if "******" in linebuf:
6242 "Command-interpretation loop."
6244 if game.irhere and game.state.date >= ALGERON and not game.isviolreported and game.iscloaked:
6245 prout(_("The Romulan ship discovers you are breaking the Treaty of Algeron!"))
6247 game.isviolreported = True
6248 while True: # command loop
6250 while True: # get a command
6252 game.optime = game.justin = False
6254 setwnd(prompt_window)
6257 if scanner.nexttok() == "IHEOL":
6258 if game.options & OPTION_CURSES:
6261 elif scanner.token == "":
6265 setwnd(message_window)
6267 abandon_passed = False
6268 cmd = "" # Force cmd to persist after loop
6269 opt = 0 # Force opt to persist after loop
6270 for (cmd, opt) in commands:
6271 # commands after ABANDON cannot be abbreviated
6272 if cmd == "ABANDON":
6273 abandon_passed = True
6274 if cmd == scanner.token.upper() or (not abandon_passed \
6275 and cmd.startswith(scanner.token.upper())):
6280 elif opt and not (opt & game.options):
6284 if game.options & OPTION_CURSES:
6285 prout("COMMAND> %s" % cmd)
6286 if cmd == "SRSCAN": # srscan
6288 elif cmd == "STATUS": # status
6290 elif cmd == "REQUEST": # status request
6292 elif cmd == "LRSCAN": # long range scan
6293 lrscan(silent=False)
6294 elif cmd == "PHASERS": # phasers
6299 elif cmd in ("TORPEDO", "PHOTONS"): # photon torpedos
6304 elif cmd == "MOVE": # move under warp
6305 warp(wcourse=None, involuntary=False)
6306 elif cmd == "SHIELDS": # shields
6307 doshield(shraise=False)
6310 game.shldchg = False
6311 elif cmd == "DOCK": # dock at starbase
6314 attack(torps_ok=False)
6315 elif cmd == "DAMAGES": # damage reports
6317 elif cmd == "CHART": # chart
6319 elif cmd == "IMPULSE": # impulse
6321 elif cmd == "REST": # rest
6325 elif cmd == "WARP": # warp
6327 elif cmd == "SENSORS": # sensors
6329 elif cmd == "ORBIT": # orbit
6333 elif cmd == "TRANSPORT": # transport "beam"
6335 elif cmd == "MINE": # mine
6339 elif cmd == "CRYSTALS": # crystals
6343 elif cmd == "SHUTTLE": # shuttle
6347 elif cmd == "PLANETS": # Planet list
6349 elif cmd == "REPORT": # Game Report
6351 elif cmd == "COMPUTER": # use COMPUTER!
6353 elif cmd == "COMMANDS":
6355 elif cmd == "EMEXIT": # Emergency exit
6356 clrscr() # Hide screen
6357 freeze(True) # forced save
6358 raise SystemExit(1) # And quick exit
6359 elif cmd == "PROBE":
6360 probe() # Launch probe
6363 elif cmd == "ABANDON": # Abandon Ship
6365 elif cmd == "DESTRUCT": # Self Destruct
6367 elif cmd == "SAVE": # Save Game
6370 if game.skill > SKILL_GOOD:
6371 prout(_("WARNING--Saved games produce no plaques!"))
6372 elif cmd == "DEATHRAY": # Try a desparation measure
6376 elif cmd == "CAPTURE":
6378 elif cmd == "CLOAK":
6380 elif cmd == "DEBUGCMD": # What do we want for debug???
6382 elif cmd == "MAYDAY": # Call for help
6387 game.alldone = True # quit the game
6390 elif cmd == "SCORE":
6391 score() # see current score
6392 elif cmd == "CURSES":
6393 game.options |= (OPTION_CURSES | OPTION_COLOR)
6397 break # Game has ended
6398 if game.optime != 0.0:
6401 break # Events did us in
6402 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6405 if hitme and not game.justin:
6406 attack(torps_ok=True)
6409 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6420 "Emit the name of an enemy or feature."
6421 if ch == 'R': s = _("Romulan")
6422 elif ch == 'K': s = _("Klingon")
6423 elif ch == 'C': s = _("Commander")
6424 elif ch == 'S': s = _("Super-commander")
6425 elif ch == '*': s = _("Star")
6426 elif ch == 'P': s = _("Planet")
6427 elif ch == 'B': s = _("Starbase")
6428 elif ch == ' ': s = _("Black hole")
6429 elif ch == 'T': s = _("Tholian")
6430 elif ch == '#': s = _("Tholian web")
6431 elif ch == '?': s = _("Stranger")
6432 elif ch == '@': s = _("Inhabited World")
6433 else: s = "Unknown??"
6436 def crmena(loud, enemy, loctype, w):
6437 "Emit the name of an enemy and his location."
6441 buf += cramen(enemy) + _(" at ")
6442 if loctype == "quadrant":
6443 buf += _("Quadrant ")
6444 elif loctype == "sector":
6446 return buf + repr(w)
6449 "Emit our ship name."
6450 return{'E':_("Enterprise"),'F':_("Faerie Queene")}.get(game.ship,"Ship???")
6453 "Emit a line of stars"
6454 prouts("******************************************************")
6458 return -avrage*math.log(1e-7 + randreal())
6460 def randplace(size):
6461 "Choose a random location."
6463 w.i = randrange(size)
6464 w.j = randrange(size)
6474 # Get a token from the user
6477 # Fill the token quue if nothing here
6478 while not self.inqueue:
6480 if curwnd==prompt_window:
6482 setwnd(message_window)
6489 self.inqueue = sline.lstrip().split() + ["\n"]
6490 # From here on in it's all looking at the queue
6491 self.token = self.inqueue.pop(0)
6492 if self.token == "\n":
6496 self.real = float(self.token)
6497 self.type = "IHREAL"
6502 self.token = self.token.lower()
6503 self.type = "IHALPHA"
6506 def append(self, tok):
6507 self.inqueue.append(tok)
6508 def push(self, tok):
6509 self.inqueue.insert(0, tok)
6513 # Demand input for next scan
6515 self.real = self.token = None
6517 # compares s to item and returns true if it matches to the length of s
6518 return s.startswith(self.token)
6520 # Round token value to nearest integer
6521 return int(round(self.real))
6525 if self.type != "IHREAL":
6530 if self.type != "IHREAL":
6536 return "<sstcanner: token=%s, type=%s, queue=%s>" % (self.token, self.type, self.inqueue)
6539 "Yes-or-no confirmation."
6543 if scanner.token == 'y':
6545 if scanner.token == 'n':
6548 proutn(_("Please answer with \"y\" or \"n\": "))
6551 "Complain about unparseable input."
6554 prout(_("Beg your pardon, Captain?"))
6557 "Access to the internals for debugging."
6558 proutn("Reset levels? ")
6560 if game.energy < game.inenrg:
6561 game.energy = game.inenrg
6562 game.shield = game.inshld
6563 game.torps = game.intorps
6564 game.lsupres = game.inlsr
6565 proutn("Reset damage? ")
6567 for i in range(NDEVICES):
6568 if game.damage[i] > 0.0:
6569 game.damage[i] = 0.0
6570 proutn("Toggle debug flag? ")
6572 game.idebug = not game.idebug
6574 prout("Debug output ON")
6576 prout("Debug output OFF")
6577 proutn("Cause selective damage? ")
6579 for i in range(NDEVICES):
6580 proutn("Kill %s?" % device[i])
6582 key = scanner.nexttok()
6583 if key == "IHALPHA" and scanner.sees("y"):
6584 game.damage[i] = 10.0
6585 proutn("Examine/change events? ")
6590 FSNOVA: "Supernova ",
6593 FBATTAK: "Base Attack ",
6594 FCDBAS: "Base Destroy ",
6595 FSCMOVE: "SC Move ",
6596 FSCDBAS: "SC Base Destroy ",
6597 FDSPROB: "Probe Move ",
6598 FDISTR: "Distress Call ",
6599 FENSLV: "Enslavement ",
6600 FREPRO: "Klingon Build ",
6602 for i in range(1, NEVENTS):
6605 proutn("%.2f" % (scheduled(i)-game.state.date))
6606 if i == FENSLV or i == FREPRO:
6608 proutn(" in %s" % ev.quadrant)
6613 key = scanner.nexttok()
6617 elif key == "IHREAL":
6618 ev = schedule(i, scanner.real)
6619 if i == FENSLV or i == FREPRO:
6621 proutn("In quadrant- ")
6622 key = scanner.nexttok()
6623 # "IHEOL" says to leave coordinates as they are
6626 prout("Event %d canceled, no x coordinate." % (i))
6629 w.i = int(round(scanner.real))
6630 key = scanner.nexttok()
6632 prout("Event %d canceled, no y coordinate." % (i))
6635 w.j = int(round(scanner.real))
6638 proutn("Induce supernova here? ")
6640 game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova = True
6643 if __name__ == '__main__':
6645 #global line, thing, game
6649 game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY)
6650 if os.getenv("TERM"):
6651 game.options |= OPTION_CURSES
6653 game.options |= OPTION_TTY
6654 seed = int(time.time())
6655 (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:txV")
6657 for (switch, val) in options:
6660 replayfp = open(val, "r")
6662 sys.stderr.write("sst: can't open replay file %s\n" % val)
6665 line = replayfp.readline().strip()
6666 (leader, __, seed) = line.split()
6668 sys.stderr.write("sst2k: seed set to %s\n" % seed)
6669 line = replayfp.readline().strip()
6670 arguments += line.split()[2:]
6673 sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
6675 game.options |= OPTION_TTY
6676 game.options &=~ OPTION_CURSES
6677 elif switch == '-s':
6679 elif switch == '-t':
6680 game.options |= OPTION_TTY
6681 game.options &=~ OPTION_CURSES
6682 elif switch == '-x':
6684 elif switch == '-V':
6685 print("SST2K", version)
6688 sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n")
6690 # where to save the input in case of bugs
6691 if "TMPDIR" in os.environ:
6692 tmpdir = os.environ['TMPDIR']
6696 logfp = open(os.path.join(tmpdir, "sst-input.log"), "w")
6698 sys.stderr.write("sst: warning, can't open logfile\n")
6701 logfp.write("# seed %s\n" % seed)
6702 logfp.write("# options %s\n" % " ".join(arguments))
6703 logfp.write("# SST2K version %s\n" % version)
6704 logfp.write("# recorded by %s@%s on %s\n" % \
6705 (getpass.getuser(),socket.gethostname(),time.ctime()))
6707 scanner = sstscanner()
6708 for arg in arguments:
6712 while True: # Play a game
6713 setwnd(fullscreen_window)
6719 game.alldone = False
6727 if game.tourn and game.alldone:
6728 proutn(_("Do you want your score recorded?"))
6734 proutn(_("Do you want to play again? "))
6738 prout(_("May the Great Bird of the Galaxy roost upon your home planet."))
6742 except KeyboardInterrupt: