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
33 docpath = (".", "doc/", "/usr/share/doc/sst/")
36 return gettext.gettext(st)
38 GALSIZE = 8 # Galaxy size in quadrants
39 NINHAB = (GALSIZE * GALSIZE // 2) # Number of inhabited worlds
40 MAXUNINHAB = 10 # Maximum uninhabited worlds
41 QUADSIZE = 10 # Quadrant size in sectors
42 BASEMIN = 2 # Minimum starbases
43 BASEMAX = (GALSIZE * GALSIZE // 12) # Maximum starbases
44 MAXKLGAME = 127 # Maximum Klingons per game
45 MAXKLQUAD = 9 # Maximum Klingons per quadrant
46 FULLCREW = 428 # Crew size. BSD Trek was 387, that's wrong
47 FOREVER = 1e30 # Time for the indefinite future
48 MAXBURST = 3 # Max # of torps you can launch in one turn
49 MINCMDR = 10 # Minimum number of Klingon commanders
50 DOCKFAC = 0.25 # Repair faster when docked
51 PHASEFAC = 2.0 # Unclear what this is, it was in the C version
53 ALGERON = 2311 # Date of the Treaty of Algeron
74 class TrekError(Exception):
77 class JumpOut(Exception):
81 def __init__(self, x=None, y=None):
84 def valid_quadrant(self):
85 return self.i >= 0 and self.i < GALSIZE and self.j >= 0 and self.j < GALSIZE
86 def valid_sector(self):
87 return self.i >= 0 and self.i < QUADSIZE and self.j >= 0 and self.j < QUADSIZE
89 self.i = self.j = None
91 return self.i != None and self.j != None
92 def __eq__(self, other):
93 return other != None and self.i == other.i and self.j == other.j
94 def __ne__(self, other):
95 return other is None or self.i != other.i or self.j != other.j
96 def __add__(self, other):
97 return Coord(self.i+other.i, self.j+other.j)
98 def __sub__(self, other):
99 return Coord(self.i-other.i, self.j-other.j)
100 def __mul__(self, other):
101 return Coord(self.i*other, self.j*other)
102 def __rmul__(self, other):
103 return Coord(self.i*other, self.j*other)
104 def __div__(self, other):
105 return Coord(self.i/other, self.j/other)
106 def __mod__(self, other):
107 return Coord(self.i % other, self.j % other)
108 def __rdiv__(self, other):
109 return Coord(self.i/other, self.j/other)
110 def roundtogrid(self):
111 return Coord(int(round(self.i)), int(round(self.j)))
112 def distance(self, other=None):
115 return math.sqrt((self.i - other.i)**2 + (self.j - other.j)**2)
117 return 1.90985*math.atan2(self.j, self.i)
123 s.i = self.i / abs(self.i)
127 s.j = self.j / abs(self.j)
130 #print "Location %s -> %s" % (self, (self / QUADSIZE).roundtogrid())
131 return self.roundtogrid() / QUADSIZE
133 return self.roundtogrid() % QUADSIZE
136 s.i = self.i + randrange(-1, 2)
137 s.j = self.j + randrange(-1, 2)
140 if self.i is None or self.j is None:
142 return "%s - %s" % (self.i+1, self.j+1)
146 "Do not anger the Space Thingy!"
153 return (q.i, q.j) == (self.i, self.j)
157 self.name = None # string-valued if inhabited
158 self.quadrant = Coord() # quadrant located
159 self.pclass = None # could be ""M", "N", "O", or "destroyed"
160 self.crystals = "absent"# could be "mined", "present", "absent"
161 self.known = "unknown" # could be "unknown", "known", "shuttle_down"
162 self.inhabited = False # is it inhabited?
170 self.starbase = False
173 self.supernova = False
175 self.status = "secure" # Could be "secure", "distressed", "enslaved"
180 self.starbase = False
183 return "<%s,%s,%s>" % (self.klingons, self.starbase, self.stars)
185 def fill2d(size, fillfun):
186 "Fill an empty list in 2D."
188 for i in range(size):
190 for j in range(size):
191 lst[i].append(fillfun(i, j))
196 self.snap = False # snapshot taken
197 self.crew = 0 # crew complement
198 self.remkl = 0 # remaining klingons
199 self.nscrem = 0 # remaining super commanders
200 self.starkl = 0 # destroyed stars
201 self.basekl = 0 # destroyed bases
202 self.nromrem = 0 # Romulans remaining
203 self.nplankl = 0 # destroyed uninhabited planets
204 self.nworldkl = 0 # destroyed inhabited planets
205 self.planets = [] # Planet information
206 self.date = 0.0 # stardate
207 self.remres = 0 # remaining resources
208 self.remtime = 0 # remaining time
209 self.baseq = [] # Base quadrant coordinates
210 self.kcmdr = [] # Commander quadrant coordinates
211 self.kscmdr = Coord() # Supercommander quadrant coordinates
213 self.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
215 self.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
219 self.date = None # A real number
220 self.quadrant = None # A coord structure
223 OPTION_ALL = 0xffffffff
224 OPTION_TTY = 0x00000001 # old interface
225 OPTION_CURSES = 0x00000002 # new interface
226 OPTION_IOMODES = 0x00000003 # cover both interfaces
227 OPTION_PLANETS = 0x00000004 # planets and mining
228 OPTION_THOLIAN = 0x00000008 # Tholians and their webs (UT 1979 version)
229 OPTION_THINGY = 0x00000010 # Space Thingy can shoot back (Stas, 2005)
230 OPTION_PROBE = 0x00000020 # deep-space probes (DECUS version, 1980)
231 OPTION_SHOWME = 0x00000040 # bracket Enterprise in chart
232 OPTION_RAMMING = 0x00000080 # enemies may ram Enterprise (Almy)
233 OPTION_MVBADDY = 0x00000100 # more enemies can move (Almy)
234 OPTION_BLKHOLE = 0x00000200 # black hole may timewarp you (Stas, 2005)
235 OPTION_BASE = 0x00000400 # bases have good shields (Stas, 2005)
236 OPTION_WORLDS = 0x00000800 # logic for inhabited worlds (ESR, 2006)
237 OPTION_AUTOSCAN = 0x00001000 # automatic LRSCAN before CHART (ESR, 2006)
238 OPTION_CAPTURE = 0x00002000 # Enable BSD-Trek capture (Almy, 2013).
239 OPTION_CLOAK = 0x80004000 # Enable BSD-Trek capture (Almy, 2013).
240 OPTION_PLAIN = 0x01000000 # user chose plain game
241 OPTION_ALMY = 0x02000000 # user chose Almy variant
242 OPTION_COLOR = 0x04000000 # enable color display (ESR, 2010)
262 NDEVICES = 17 # Number of devices
272 return (game.damage[dev] != 0.0)
274 return not damaged(DRADIO) or game.condition=="docked"
276 # Define future events
277 FSPY = 0 # Spy event happens always (no future[] entry)
278 # can cause SC to tractor beam Enterprise
279 FSNOVA = 1 # Supernova
280 FTBEAM = 2 # Commander tractor beams Enterprise
281 FSNAP = 3 # Snapshot for time warp
282 FBATTAK = 4 # Commander attacks base
283 FCDBAS = 5 # Commander destroys base
284 FSCMOVE = 6 # Supercommander moves (might attack base)
285 FSCDBAS = 7 # Supercommander destroys base
286 FDSPROB = 8 # Move deep space probe
287 FDISTR = 9 # Emit distress call from an inhabited world
288 FENSLV = 10 # Inhabited word is enslaved */
289 FREPRO = 11 # Klingons build a ship in an enslaved system
292 # Abstract out the event handling -- underlying data structures will change
293 # when we implement stateful events
294 def findevent(evtype):
295 return game.future[evtype]
298 def __init__(self, etype=None, loc=None, power=None):
300 self.location = Coord()
305 self.power = power # enemy energy level
306 game.enemies.append(self)
308 motion = (loc != self.location)
309 if self.location.i is not None and self.location.j is not None:
312 game.quad[self.location.i][self.location.j] = '#'
314 game.quad[self.location.i][self.location.j] = '.'
316 self.location = copy.copy(loc)
317 game.quad[self.location.i][self.location.j] = self.type
318 self.kdist = self.kavgd = (game.sector - loc).distance()
320 self.location = Coord()
321 self.kdist = self.kavgd = None
322 game.enemies.remove(self)
325 return "<%s,%s.%f>" % (self.type, self.location, self.power) # For debugging
329 self.options = None # Game options
330 self.state = Snapshot() # A snapshot structure
331 self.snapsht = Snapshot() # Last snapshot taken for time-travel purposes
332 self.quad = None # contents of our quadrant
333 self.damage = [0.0] * NDEVICES # damage encountered
334 self.future = [] # future events
338 self.future.append(Event())
339 self.passwd = None # Self Destruct password
341 self.quadrant = None # where we are in the large
342 self.sector = None # where we are in the small
343 self.tholian = None # Tholian enemy object
344 self.base = None # position of base in current quadrant
345 self.battle = None # base coordinates being attacked
346 self.plnet = None # location of planet in quadrant
347 self.gamewon = False # Finished!
348 self.ididit = False # action taken -- allows enemy to attack
349 self.alive = False # we are alive (not killed)
350 self.justin = False # just entered quadrant
351 self.shldup = False # shields are up
352 self.shldchg = False # shield is changing (affects efficiency)
353 self.iscate = False # super commander is here
354 self.ientesc = False # attempted escape from supercommander
355 self.resting = False # rest time
356 self.icraft = False # Kirk in Galileo
357 self.landed = False # party on planet (true), on ship (false)
358 self.alldone = False # game is now finished
359 self.neutz = False # Romulan Neutral Zone
360 self.isarmed = False # probe is armed
361 self.inorbit = False # orbiting a planet
362 self.imine = False # mining
363 self.icrystl = False # dilithium crystals aboard
364 self.iseenit = False # seen base attack report
365 self.thawed = False # thawed game
366 self.condition = None # "green", "yellow", "red", "docked", "dead"
367 self.iscraft = None # "onship", "offship", "removed"
368 self.skill = None # Player skill level
369 self.inkling = 0 # initial number of klingons
370 self.inbase = 0 # initial number of bases
371 self.incom = 0 # initial number of commanders
372 self.inscom = 0 # initial number of commanders
373 self.inrom = 0 # initial number of commanders
374 self.instar = 0 # initial stars
375 self.intorps = 0 # initial/max torpedoes
376 self.torps = 0 # number of torpedoes
377 self.ship = 0 # ship type -- 'E' is Enterprise
378 self.abandoned = 0 # count of crew abandoned in space
379 self.length = 0 # length of game
380 self.klhere = 0 # klingons here
381 self.casual = 0 # causalties
382 self.nhelp = 0 # calls for help
383 self.nkinks = 0 # count of energy-barrier crossings
384 self.iplnet = None # planet # in quadrant
385 self.inplan = 0 # initial planets
386 self.irhere = 0 # Romulans in quadrant
387 self.isatb = 0 # =2 if super commander is attacking base
388 self.tourn = None # tournament number
389 self.nprobes = 0 # number of probes available
390 self.inresor = 0.0 # initial resources
391 self.intime = 0.0 # initial time
392 self.inenrg = 0.0 # initial/max energy
393 self.inshld = 0.0 # initial/max shield
394 self.inlsr = 0.0 # initial life support resources
395 self.indate = 0.0 # initial date
396 self.energy = 0.0 # energy level
397 self.shield = 0.0 # shield level
398 self.warpfac = 0.0 # warp speed
399 self.lsupres = 0.0 # life support reserves
400 self.optime = 0.0 # time taken by current operation
401 self.damfac = 0.0 # damage factor
402 self.lastchart = 0.0 # time star chart was last updated
403 self.cryprob = 0.0 # probability that crystal will work
404 self.probe = None # object holding probe course info
405 self.height = 0.0 # height of orbit around planet
406 self.score = 0.0 # overall score
407 self.perdate = 0.0 # rate of kills
408 self.idebug = False # Debugging instrumentation enabled?
409 self.statekscmdr = None # No SuperCommander coordinates yet.
410 self.brigcapacity = 400 # Enterprise brig capacity
411 self.brigfree = 400 # How many klingons can we put in the brig?
412 self.kcaptured = 0 # Total Klingons captured, for scoring.
413 self.iscloaked = False # Cloaking device on?
414 self.ncviol = 0 # Algreon treaty violations
415 self.isviolreported = False # We have been warned
417 # Stas thinks this should be (C expression):
418 # game.state.remkl + len(game.state.kcmdr) > 0 ?
419 # game.state.remres/(game.state.remkl + 4*len(game.state.kcmdr)) : 99
420 # He says the existing expression is prone to divide-by-zero errors
421 # after killing the last klingon when score is shown -- perhaps also
422 # if the only remaining klingon is SCOM.
423 self.state.remtime = self.state.remres/(self.state.remkl + 4*len(self.state.kcmdr))
425 "Are there Klingons remaining?"
426 return self.state.remkl + len(self.state.kcmdr) + self.state.nscrem
453 return random.random() < p
455 def randrange(*args):
456 return random.randrange(*args)
461 v *= args[0] # from [0, args[0])
463 v = args[0] + v*(args[1]-args[0]) # from [args[0], args[1])
466 # Code from ai.c begins here
469 "Would this quadrant welcome another Klingon?"
470 return iq.valid_quadrant() and \
471 not game.state.galaxy[iq.i][iq.j].supernova and \
472 game.state.galaxy[iq.i][iq.j].klingons < MAXKLQUAD
474 def tryexit(enemy, look, irun):
475 "A bad guy attempts to bug out."
477 iq.i = game.quadrant.i+(look.i+(QUADSIZE-1))/QUADSIZE - 1
478 iq.j = game.quadrant.j+(look.j+(QUADSIZE-1))/QUADSIZE - 1
479 if not welcoming(iq):
481 if enemy.type == 'R':
482 return False # Romulans cannot escape!
484 # avoid intruding on another commander's territory
485 if enemy.type == 'C':
486 if iq in game.state.kcmdr:
488 # refuse to leave if currently attacking starbase
489 if game.battle == game.quadrant:
491 # don't leave if over 1000 units of energy
492 if enemy.power > 1000.0:
494 oldloc = copy.copy(enemy.location)
495 # handle local matters related to escape
498 if game.condition != "docked":
500 # Handle global matters related to escape
501 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
502 game.state.galaxy[iq.i][iq.j].klingons += 1
503 if enemy.type == 'S':
507 schedule(FSCMOVE, 0.2777)
509 game.state.kscmdr = iq
511 for cmdr in game.state.kcmdr:
512 if cmdr == game.quadrant:
513 game.state.kcmdr.append(iq)
515 # report move out of quadrant.
516 return [(True, enemy, oldloc, iq)]
518 # The bad-guy movement algorithm:
520 # 1. Enterprise has "force" based on condition of phaser and photon torpedoes.
521 # If both are operating full strength, force is 1000. If both are damaged,
522 # force is -1000. Having shields down subtracts an additional 1000.
524 # 2. Enemy has forces equal to the energy of the attacker plus
525 # 100*(K+R) + 500*(C+S) - 400 for novice through good levels OR
526 # 346*K + 400*R + 500*(C+S) - 400 for expert and emeritus.
528 # Attacker Initial energy levels (nominal):
529 # Klingon Romulan Commander Super-Commander
530 # Novice 400 700 1200
532 # Good 450 800 1300 1750
533 # Expert 475 850 1350 1875
534 # Emeritus 500 900 1400 2000
535 # VARIANCE 75 200 200 200
537 # Enemy vessels only move prior to their attack. In Novice - Good games
538 # only commanders move. In Expert games, all enemy vessels move if there
539 # is a commander present. In Emeritus games all enemy vessels move.
541 # 3. If Enterprise is not docked, an aggressive action is taken if enemy
542 # forces are 1000 greater than Enterprise.
544 # Agressive action on average cuts the distance between the ship and
545 # the enemy to 1/4 the original.
547 # 4. At lower energy advantage, movement units are proportional to the
548 # advantage with a 650 advantage being to hold ground, 800 to move forward
549 # 1, 950 for two, 150 for back 4, etc. Variance of 100.
551 # If docked, is reduced by roughly 1.75*game.skill, generally forcing a
552 # retreat, especially at high skill levels.
554 # 5. Motion is limited to skill level, except for SC hi-tailing it out.
556 def movebaddy(enemy):
557 "Tactical movement for the bad guys."
561 # This should probably be just (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
562 if game.skill >= SKILL_EXPERT:
563 nbaddys = (((game.quadrant in game.state.kcmdr)*2 + (game.state.kscmdr==game.quadrant)*2+game.klhere*1.23+game.irhere*1.5)/2.0)
565 nbaddys = (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
566 old_dist = enemy.kdist
567 mdist = int(old_dist + 0.5) # Nearest integer distance
568 # If SC, check with spy to see if should hi-tail it
569 if enemy.type == 'S' and \
570 (enemy.power <= 500.0 or (game.condition=="docked" and not damaged(DPHOTON))):
574 # decide whether to advance, retreat, or hold position
575 forces = enemy.power+100.0*len(game.enemies)+400*(nbaddys-1)
577 forces += 1000 # Good for enemy if shield is down!
578 if not damaged(DPHASER) or not damaged(DPHOTON):
579 if damaged(DPHASER): # phasers damaged
582 forces -= 0.2*(game.energy - 2500.0)
583 if damaged(DPHOTON): # photon torpedoes damaged
586 forces -= 50.0*game.torps
588 # phasers and photon tubes both out!
591 if forces <= 1000.0 and game.condition != "docked": # Typical situation
592 motion = ((forces + randreal(200))/150.0) - 5.0
594 if forces > 1000.0: # Very strong -- move in for kill
595 motion = (1.0 - randreal())**2 * old_dist + 1.0
596 if game.condition == "docked" and (game.options & OPTION_BASE): # protected by base -- back off !
597 motion -= game.skill*(2.0-randreal()**2)
599 proutn("=== MOTION = %d, FORCES = %1.2f, " % (motion, forces))
600 # don't move if no motion
603 # Limit motion according to skill
604 if abs(motion) > game.skill:
609 # calculate preferred number of steps
610 nsteps = abs(int(motion))
611 if motion > 0 and nsteps > mdist:
612 nsteps = mdist # don't overshoot
613 if nsteps > QUADSIZE:
614 nsteps = QUADSIZE # This shouldn't be necessary
616 nsteps = 1 # This shouldn't be necessary
618 proutn("NSTEPS = %d:" % nsteps)
619 # Compute preferred values of delta X and Y
620 m = game.sector - enemy.location
621 if 2.0 * abs(m.i) < abs(m.j):
623 if 2.0 * abs(m.j) < abs(game.sector.i-enemy.location.i):
625 m = (motion * m).sgn()
626 goto = enemy.location
628 for ll in range(nsteps):
630 proutn(" %d" % (ll+1))
631 # Check if preferred position available
642 attempts = 0 # Settle mysterious hang problem
643 while attempts < 20 and not success:
645 if look.i < 0 or look.i >= QUADSIZE:
647 return tryexit(enemy, look, irun)
648 if krawli == m.i or m.j == 0:
650 look.i = goto.i + krawli
652 elif look.j < 0 or look.j >= QUADSIZE:
654 return tryexit(enemy, look, irun)
655 if krawlj == m.j or m.i == 0:
657 look.j = goto.j + krawlj
659 elif (game.options & OPTION_RAMMING) and game.quad[look.i][look.j] != '.':
660 # See if enemy should ram ship
661 if game.quad[look.i][look.j] == game.ship and \
662 (enemy.type == 'C' or enemy.type == 'S'):
663 collision(rammed=True, enemy=enemy)
665 if krawli != m.i and m.j != 0:
666 look.i = goto.i + krawli
668 elif krawlj != m.j and m.i != 0:
669 look.j = goto.j + krawlj
672 break # we have failed
683 # Enemy moved, but is still in sector
684 return [(False, enemy, old_dist, goto)]
687 "Sequence Klingon tactical movement."
690 # Figure out which Klingon is the commander (or Supercommander)
693 if game.quadrant in game.state.kcmdr:
694 for enemy in game.enemies:
695 if enemy.type == 'C':
696 tacmoves += movebaddy(enemy)
697 if game.state.kscmdr == game.quadrant:
698 for enemy in game.enemies:
699 if enemy.type == 'S':
700 tacmoves += movebaddy(enemy)
702 # If skill level is high, move other Klingons and Romulans too!
703 # Move these last so they can base their actions on what the
705 if game.skill >= SKILL_EXPERT and (game.options & OPTION_MVBADDY):
706 for enemy in game.enemies:
707 if enemy.type in ('K', 'R'):
708 tacmoves += movebaddy(enemy)
711 def movescom(iq, avoid):
712 "Commander movement helper."
713 # Avoid quadrants with bases if we want to avoid Enterprise
714 if not welcoming(iq) or (avoid and iq in game.state.baseq):
716 if game.justin and not game.iscate:
719 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons -= 1
720 game.state.kscmdr = iq
721 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons += 1
722 if game.state.kscmdr == game.quadrant:
723 # SC has scooted, remove him from current quadrant
728 for enemy in game.enemies:
729 if enemy.type == 'S':
732 if game.condition != "docked":
735 # check for a helpful planet
736 for i in range(game.inplan):
737 if game.state.planets[i].quadrant == game.state.kscmdr and \
738 game.state.planets[i].crystals == "present":
740 game.state.planets[i].pclass = "destroyed"
741 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].planet = None
744 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
745 proutn(_(" a planet in Quadrant %s has been destroyed") % game.state.kscmdr)
746 prout(_(" by the Super-commander.\""))
748 return True # looks good!
750 def supercommander():
751 "Move the Super Commander."
758 prout("== SUPERCOMMANDER")
759 # Decide on being active or passive
760 avoid = ((game.incom - len(game.state.kcmdr) + game.inkling - game.state.remkl)/(game.state.date+0.01-game.indate) < 0.1*game.skill*(game.skill+1.0) or \
761 (game.state.date-game.indate) < 3.0)
762 if not game.iscate and avoid:
763 # compute move away from Enterprise
764 idelta = game.state.kscmdr-game.quadrant
765 if idelta.distance() > 2.0:
767 idelta.i = game.state.kscmdr.j-game.quadrant.j
768 idelta.j = game.quadrant.i-game.state.kscmdr.i
770 # compute distances to starbases
771 if not game.state.baseq:
775 sc = game.state.kscmdr
776 for (i, base) in enumerate(game.state.baseq):
777 basetbl.append((i, (base - sc).distance()))
778 if game.state.baseq > 1:
779 basetbl.sort(key=lambda x: x[1])
780 # look for nearest base without a commander, no Enterprise, and
781 # without too many Klingons, and not already under attack.
782 ifindit = iwhichb = 0
783 for (i2, base) in enumerate(game.state.baseq):
784 i = basetbl[i2][0] # bug in original had it not finding nearest
785 if base == game.quadrant or base == game.battle or not welcoming(base):
787 # if there is a commander, and no other base is appropriate,
788 # we will take the one with the commander
789 for cmdr in game.state.kcmdr:
790 if base == cmdr and ifindit != 2:
794 else: # no commander -- use this one
799 return # Nothing suitable -- wait until next time
800 ibq = game.state.baseq[iwhichb]
801 # decide how to move toward base
802 idelta = ibq - game.state.kscmdr
803 # Maximum movement is 1 quadrant in either or both axes
804 idelta = idelta.sgn()
805 # try moving in both x and y directions
806 # there was what looked like a bug in the Almy C code here,
807 # but it might be this translation is just wrong.
808 iq = game.state.kscmdr + idelta
809 if not movescom(iq, avoid):
810 # failed -- try some other maneuvers
811 if idelta.i == 0 or idelta.j == 0:
814 iq.j = game.state.kscmdr.j + 1
815 if not movescom(iq, avoid):
816 iq.j = game.state.kscmdr.j - 1
819 iq.i = game.state.kscmdr.i + 1
820 if not movescom(iq, avoid):
821 iq.i = game.state.kscmdr.i - 1
824 # try moving just in x or y
825 iq.j = game.state.kscmdr.j
826 if not movescom(iq, avoid):
827 iq.j = game.state.kscmdr.j + idelta.j
828 iq.i = game.state.kscmdr.i
831 if len(game.state.baseq) == 0:
834 for ibq in game.state.baseq:
835 if ibq == game.state.kscmdr and game.state.kscmdr == game.battle:
838 return # no, don't attack base!
841 schedule(FSCDBAS, randreal(1.0, 3.0))
842 if is_scheduled(FCDBAS):
843 postpone(FSCDBAS, scheduled(FCDBAS)-game.state.date)
844 if not communicating():
848 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") \
850 prout(_(" reports that it is under attack from the Klingon Super-commander."))
851 proutn(_(" It can survive until stardate %d.\"") \
852 % int(scheduled(FSCDBAS)))
855 prout(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
859 game.optime = 0.0 # actually finished
861 # Check for intelligence report
862 if not game.idebug and \
864 (not communicating()) or \
865 not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].charted):
868 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
869 proutn(_(" the Super-commander is in Quadrant %s,") % game.state.kscmdr)
874 if not game.tholian or game.justin:
877 if game.tholian.location.i == 0 and game.tholian.location.j == 0:
880 elif game.tholian.location.i == 0 and game.tholian.location.j == QUADSIZE-1:
883 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == QUADSIZE-1:
886 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == 0:
890 # something is wrong!
891 game.tholian.move(None)
892 prout("***Internal error: Tholian in a bad spot.")
894 # do nothing if we are blocked
895 if game.quad[tid.i][tid.j] not in ('.', '#'):
897 here = copy.copy(game.tholian.location)
898 delta = (tid - game.tholian.location).sgn()
900 while here.i != tid.i:
902 if game.quad[here.i][here.j] == '.':
903 game.tholian.move(here)
905 while here.j != tid.j:
907 if game.quad[here.i][here.j] == '.':
908 game.tholian.move(here)
909 # check to see if all holes plugged
910 for i in range(QUADSIZE):
911 if game.quad[0][i] != '#' and game.quad[0][i] != 'T':
913 if game.quad[QUADSIZE-1][i] != '#' and game.quad[QUADSIZE-1][i] != 'T':
915 if game.quad[i][0] != '#' and game.quad[i][0] != 'T':
917 if game.quad[i][QUADSIZE-1] != '#' and game.quad[i][QUADSIZE-1] != 'T':
919 # All plugged up -- Tholian splits
920 game.quad[game.tholian.location.i][game.tholian.location.j] = '#'
922 prout(crmena(True, 'T', "sector", game.tholian) + _(" completes web."))
923 game.tholian.move(None)
926 # Code from battle.c begins here
929 "Change cloaking-device status."
931 prout(_("Ye Faerie Queene hath no cloaking device."));
934 key = scanner.nexttok()
941 if scanner.sees("on"):
943 prout(_("The cloaking device has already been switched on."))
946 elif scanner.sees("off"):
947 if not game.iscloaked:
948 prout(_("The cloaking device has already been switched off."))
955 if not game.iscloaked:
956 proutn(_("Switch cloaking device on? "))
961 proutn(_("Switch cloaking device off? "))
968 if action == "CLOFF":
969 if game.irhere and game.state.date >= ALGERON and not game.isviolreported:
970 prout(_("Spock- \"Captain, the Treaty of Algeron is in effect.\n Are you sure this is wise?\""))
973 prout("Engineer Scott- \"Aye, Sir.\"");
974 game.iscloaked = False;
975 if game.irhere and game.state.date >= ALGERON and not game.isviolreported:
976 prout(_("The Romulan ship discovers you are breaking the Treaty of Algeron!"))
978 game.isviolreported = True
980 #if (neutz and game.state.date >= ALGERON) finish(FCLOAK);
985 prout(_("Engineer Scott- \"The cloaking device is damaged, Sir.\""))
988 if game.condition == "docked":
989 prout(_("You cannot cloak while docked."))
991 if game.state.date >= ALGERON and not game.isviolreported:
992 prout(_("Spock- \"Captain, using the cloaking device is a violation"))
993 prout(_(" of the Treaty of Algeron. Considering the alternatives,"))
994 proutn(_(" are you sure this is wise? "))
997 prout(_("Engineer Scott- \"Cloaking device has engaging, Sir...\""))
999 prout(_("Engineer Scott- \"Cloaking device has engaged, Sir.\""))
1000 game.iscloaked = True
1002 if game.irhere and game.state.date >= ALGERON and not game.isviolreported:
1003 prout(_("The Romulan ship discovers you are breaking the Treaty of Algeron!"))
1005 game.isviolreported = True
1007 def doshield(shraise):
1008 "Change shield status."
1014 key = scanner.nexttok()
1015 if key == "IHALPHA":
1016 if scanner.sees("transfer"):
1019 if damaged(DSHIELD):
1020 prout(_("Shields damaged and down."))
1022 if scanner.sees("up"):
1024 elif scanner.sees("down"):
1026 if action == "NONE":
1027 proutn(_("Do you wish to change shield energy? "))
1030 elif damaged(DSHIELD):
1031 prout(_("Shields damaged and down."))
1034 proutn(_("Shields are up. Do you want them down? "))
1041 proutn(_("Shields are down. Do you want them up? "))
1047 if action == "SHUP": # raise shields
1049 prout(_("Shields already up."))
1053 if game.condition != "docked":
1055 prout(_("Shields raised."))
1056 if game.energy <= 0:
1058 prout(_("Shields raising uses up last of energy."))
1063 elif action == "SHDN":
1065 prout(_("Shields already down."))
1069 prout(_("Shields lowered."))
1072 elif action == "NRG":
1073 while scanner.nexttok() != "IHREAL":
1075 proutn(_("Energy to transfer to shields- "))
1080 if nrg > game.energy:
1081 prout(_("Insufficient ship energy."))
1084 if game.shield+nrg >= game.inshld:
1085 prout(_("Shield energy maximized."))
1086 if game.shield+nrg > game.inshld:
1087 prout(_("Excess energy requested returned to ship energy"))
1088 game.energy -= game.inshld-game.shield
1089 game.shield = game.inshld
1091 if nrg < 0.0 and game.energy-nrg > game.inenrg:
1092 # Prevent shield drain loophole
1094 prout(_("Engineering to bridge--"))
1095 prout(_(" Scott here. Power circuit problem, Captain."))
1096 prout(_(" I can't drain the shields."))
1099 if game.shield+nrg < 0:
1100 prout(_("All shield energy transferred to ship."))
1101 game.energy += game.shield
1104 proutn(_("Scotty- \""))
1106 prout(_("Transferring energy to shields.\""))
1108 prout(_("Draining energy from shields.\""))
1114 "Choose a device to damage, at random."
1116 105, # DSRSENS: short range scanners 10.5%
1117 105, # DLRSENS: long range scanners 10.5%
1118 120, # DPHASER: phasers 12.0%
1119 120, # DPHOTON: photon torpedoes 12.0%
1120 25, # DLIFSUP: life support 2.5%
1121 65, # DWARPEN: warp drive 6.5%
1122 70, # DIMPULS: impulse engines 6.5%
1123 145, # DSHIELD: deflector shields 14.5%
1124 30, # DRADIO: subspace radio 3.0%
1125 45, # DSHUTTL: shuttle 4.5%
1126 15, # DCOMPTR: computer 1.5%
1127 20, # NAVCOMP: navigation system 2.0%
1128 75, # DTRANSP: transporter 7.5%
1129 20, # DSHCTRL: high-speed shield controller 2.0%
1130 10, # DDRAY: death ray 1.0%
1131 30, # DDSP: deep-space probes 3.0%
1132 0, # DCLOAK: the cloaking device 0.0
1134 assert(sum(weights) == 1000)
1135 idx = randrange(1000)
1137 for (i, w) in enumerate(weights):
1141 return None # we should never get here
1143 def collision(rammed, enemy):
1144 "Collision handling for rammong events."
1145 prouts(_("***RED ALERT! RED ALERT!"))
1147 prout(_("***COLLISION IMMINENT."))
1151 hardness = {'R':1.5, 'C':2.0, 'S':2.5, 'T':0.5, '?':4.0}.get(enemy.type, 1.0)
1153 proutn(_(" rammed by "))
1156 proutn(crmena(False, enemy.type, "sector", enemy.location))
1158 proutn(_(" (original position)"))
1160 deadkl(enemy.location, enemy.type, game.sector)
1161 proutn("***" + crmshp() + " heavily damaged.")
1162 icas = randrange(10, 30)
1163 prout(_("***Sickbay reports %d casualties") % icas)
1165 game.state.crew -= icas
1166 # In the pre-SST2K version, all devices got equiprobably damaged,
1167 # which was silly. Instead, pick up to half the devices at
1168 # random according to our weighting table,
1169 ncrits = randrange(NDEVICES/2)
1173 if game.damage[dev] < 0:
1175 extradm = (10.0*hardness*randreal()+1.0)*game.damfac
1176 # Damage for at least time of travel!
1177 game.damage[dev] += game.optime + extradm
1179 prout(_("***Shields are down."))
1180 if game.state.remkl + len(game.state.kcmdr) + game.state.nscrem:
1187 def torpedo(origin, bearing, dispersion, number, nburst):
1188 "Let a photon torpedo fly"
1189 if not damaged(DSRSENS) or game.condition == "docked":
1190 setwnd(srscan_window)
1192 setwnd(message_window)
1193 ac = bearing + 0.25*dispersion # dispersion is a random variable
1194 bullseye = (15.0 - bearing)*0.5235988
1195 track = course(bearing=ac, distance=QUADSIZE, origin=cartesian(origin))
1196 bumpto = Coord(0, 0)
1197 # Loop to move a single torpedo
1198 setwnd(message_window)
1199 for step in range(1, QUADSIZE*2):
1200 if not track.nexttok():
1203 if not w.valid_sector():
1205 iquad = game.quad[w.i][w.j]
1206 tracktorpedo(w, step, number, nburst, iquad)
1210 setwnd(message_window)
1211 if not damaged(DSRSENS) or game.condition == "docked":
1212 skip(1) # start new line after text track
1213 if iquad in ('E', 'F'): # Hit our ship
1215 prout(_("Torpedo hits %s.") % crmshp())
1216 hit = 700.0 + randreal(100) - \
1217 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1218 newcnd() # we're blown out of dock
1219 if game.landed or game.condition == "docked":
1220 return hit # Cheat if on a planet
1221 # In the C/FORTRAN version, dispersion was 2.5 radians, which
1222 # is 143 degrees, which is almost exactly 4.8 clockface units
1223 displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
1224 displacement.nexttok()
1225 bumpto = displacement.sector()
1226 if not bumpto.valid_sector():
1228 if game.quad[bumpto.i][bumpto.j] == ' ':
1231 if game.quad[bumpto.i][bumpto.j] != '.':
1232 # can't move into object
1234 game.sector = bumpto
1236 game.quad[w.i][w.j] = '.'
1237 game.quad[bumpto.i][bumpto.j] = iquad
1238 prout(_(" displaced by blast to Sector %s ") % bumpto)
1239 for enemy in game.enemies:
1240 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1243 elif iquad in ('C', 'S', 'R', 'K'): # Hit a regular enemy
1245 if iquad in ('C', 'S') and withprob(0.05):
1246 prout(crmena(True, iquad, "sector", w) + _(" uses anti-photon device;"))
1247 prout(_(" torpedo neutralized."))
1249 for enemy in game.enemies:
1250 if w == enemy.location:
1251 kp = math.fabs(enemy.power)
1252 h1 = 700.0 + randrange(100) - \
1253 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1261 if enemy.power == 0:
1264 proutn(crmena(True, iquad, "sector", w))
1265 displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
1266 displacement.nexttok()
1267 bumpto = displacement.sector()
1268 if not bumpto.valid_sector():
1269 prout(_(" damaged but not destroyed."))
1271 if game.quad[bumpto.i][bumpto.j] == ' ':
1272 prout(_(" buffeted into black hole."))
1273 deadkl(w, iquad, bumpto)
1274 if game.quad[bumpto.i][bumpto.j] != '.':
1275 prout(_(" damaged but not destroyed."))
1277 prout(_(" damaged-- displaced by blast to Sector %s ")%bumpto)
1278 enemy.location = bumpto
1279 game.quad[w.i][w.j] = '.'
1280 game.quad[bumpto.i][bumpto.j] = iquad
1281 for enemy in game.enemies:
1282 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1286 prout("Internal error, no enemy where expected!")
1289 elif iquad == 'B': # Hit a base
1291 prout(_("***STARBASE DESTROYED.."))
1292 game.state.baseq = [x for x in game.state.baseq if x != game.quadrant]
1293 game.quad[w.i][w.j] = '.'
1294 game.base.invalidate()
1295 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
1296 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = False
1297 game.state.basekl += 1
1300 elif iquad == 'P': # Hit a planet
1301 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1302 game.state.nplankl += 1
1303 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1304 game.iplnet.pclass = "destroyed"
1306 game.plnet.invalidate()
1307 game.quad[w.i][w.j] = '.'
1309 # captain perishes on planet
1312 elif iquad == '@': # Hit an inhabited world -- very bad!
1313 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1314 game.state.nworldkl += 1
1315 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1316 game.iplnet.pclass = "destroyed"
1318 game.plnet.invalidate()
1319 game.quad[w.i][w.j] = '.'
1321 # captain perishes on planet
1323 prout(_("The torpedo destroyed an inhabited planet."))
1325 elif iquad == '*': # Hit a star
1329 prout(crmena(True, '*', "sector", w) + _(" unaffected by photon blast."))
1331 elif iquad == '?': # Hit a thingy
1332 if not (game.options & OPTION_THINGY) or withprob(0.3):
1334 prouts(_("AAAAIIIIEEEEEEEEAAAAAAAAUUUUUGGGGGHHHHHHHHHHHH!!!"))
1336 prouts(_(" HACK! HACK! HACK! *CHOKE!* "))
1338 proutn(_("Mr. Spock-"))
1339 prouts(_(" \"Fascinating!\""))
1343 # Stas Sergeev added the possibility that
1344 # you can shove the Thingy and piss it off.
1345 # It then becomes an enemy and may fire at you.
1348 elif iquad == ' ': # Black hole
1350 prout(crmena(True, ' ', "sector", w) + _(" swallows torpedo."))
1352 elif iquad == '#': # hit the web
1354 prout(_("***Torpedo absorbed by Tholian web."))
1356 elif iquad == 'T': # Hit a Tholian
1357 h1 = 700.0 + randrange(100) - \
1358 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1361 game.quad[w.i][w.j] = '.'
1366 proutn(crmena(True, 'T', "sector", w))
1368 prout(_(" survives photon blast."))
1370 prout(_(" disappears."))
1371 game.tholian.move(None)
1372 game.quad[w.i][w.j] = '#'
1377 proutn("Don't know how to handle torpedo collision with ")
1378 proutn(crmena(True, iquad, "sector", w))
1383 setwnd(message_window)
1384 prout(_("Torpedo missed."))
1388 "Critical-hit resolution."
1389 if hit < (275.0-25.0*game.skill)*randreal(1.0, 1.5):
1391 ncrit = int(1.0 + hit/(500.0+randreal(100)))
1392 proutn(_("***CRITICAL HIT--"))
1393 # Select devices and cause damage
1398 # Cheat to prevent shuttle damage unless on ship
1399 if not (game.damage[j]<0.0 or (j == DSHUTTL and game.iscraft != "onship") or (j == DCLOAK and game.ship != 'E' or j == DDRAY)):
1402 extradm = (hit*game.damfac)/(ncrit*randreal(75, 100))
1403 game.damage[j] += extradm
1406 for (i, j) in enumerate(cdam):
1408 if skipcount % 3 == 2 and i < len(cdam)-1:
1413 prout(_(" damaged."))
1414 if damaged(DSHIELD) and game.shldup:
1415 prout(_("***Shields knocked down."))
1417 if damaged(DCLOAK) and game.iscloaked:
1418 prout(_("***Cloaking device rendered inoperative."))
1419 game.iscloaked = False
1421 def attack(torps_ok):
1422 # bad guy attacks us
1423 # torps_ok == False forces use of phasers in an attack
1426 # game could be over at this point, check
1436 prout("=== ATTACK!")
1437 # Tholian gets to move before attacking
1440 # if you have just entered the RNZ, you'll get a warning
1441 if game.neutz: # The one chance not to be attacked
1444 # commanders get a chance to tac-move towards you
1445 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:
1446 for (bugout, enemy, old, goto) in moveklings():
1448 # we know about this if either short or long range
1449 # sensors are working
1450 if damaged(DSRSENS) and damaged(DLRSENS) \
1451 and game.condition != "docked":
1452 prout(crmena(True, enemy.type, "sector", old) + \
1453 (_(" escapes to Quadrant %s (and regains strength).") % goto))
1454 else: # Enemy still in-sector
1455 if enemy.move(goto):
1456 if not damaged(DSRSENS) or game.condition == "docked":
1457 proutn(_("*** %s from Sector %s") % (cramen(enemy.type), enemy.location))
1458 if enemy.kdist < old:
1459 proutn(_(" advances to "))
1461 proutn(_(" retreats to "))
1462 prout("Sector %s." % goto)
1464 # if no enemies remain after movement, we're done
1465 if len(game.enemies) == 0 or (len(game.enemies) == 1 and thing.at(game.quadrant) and not thing.angered):
1467 # set up partial hits if attack happens during shield status change
1468 pfac = 1.0/game.inshld
1470 chgfac = 0.25 + randreal(0.5)
1472 # message verbosity control
1473 if game.skill <= SKILL_FAIR:
1475 for enemy in game.enemies:
1477 continue # too weak to attack
1478 # compute hit strength and diminish shield power
1480 # Increase chance of photon torpedos if docked or enemy energy is low
1481 if game.condition == "docked":
1483 if enemy.power < 500:
1485 if enemy.type == 'T' or (enemy.type == '?' and not thing.angered):
1487 # different enemies have different probabilities of throwing a torp
1488 usephasers = not torps_ok or \
1489 (enemy.type == 'K' and r > 0.0005) or \
1490 (enemy.type == 'C' and r > 0.015) or \
1491 (enemy.type == 'R' and r > 0.3) or \
1492 (enemy.type == 'S' and r > 0.07) or \
1493 (enemy.type == '?' and r > 0.05)
1494 if usephasers: # Enemy uses phasers
1495 if game.condition == "docked":
1496 continue # Don't waste the effort!
1497 attempt = True # Attempt to attack
1498 dustfac = randreal(0.8, 0.85)
1499 hit = enemy.power*math.pow(dustfac, enemy.kavgd)
1501 else: # Enemy uses photon torpedo
1502 # We should be able to make the bearing() method work here
1503 pcourse = 1.90985*math.atan2(game.sector.j-enemy.location.j, enemy.location.i-game.sector.i)
1505 proutn(_("***TORPEDO INCOMING"))
1506 if not damaged(DSRSENS):
1507 proutn(_(" From ") + crmena(False, enemy.type, where, enemy.location))
1510 dispersion = (randreal()+randreal())*0.5 - 0.5
1511 dispersion += 0.002*enemy.power*dispersion
1512 hit = torpedo(enemy.location, pcourse, dispersion, number=1, nburst=1)
1513 if game.unwon() == 0:
1514 finish(FWON) # Klingons did themselves in!
1515 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.alldone:
1516 return # Supernova or finished
1519 # incoming phaser or torpedo, shields may dissipate it
1520 if game.shldup or game.shldchg or game.condition == "docked":
1521 # shields will take hits
1522 propor = pfac * game.shield
1523 if game.condition == "docked":
1527 hitsh = propor*chgfac*hit+1.0
1529 if absorb > game.shield:
1530 absorb = game.shield
1531 game.shield -= absorb
1533 # taking a hit blasts us out of a starbase dock
1534 if game.condition == "docked":
1536 # but the shields may take care of it
1537 if propor > 0.1 and hit < 0.005*game.energy:
1539 # hit from this opponent got through shields, so take damage
1541 proutn(_("%d unit hit") % int(hit))
1542 if (damaged(DSRSENS) and usephasers) or game.skill<=SKILL_FAIR:
1543 proutn(_(" on the ") + crmshp())
1544 if not damaged(DSRSENS) and usephasers:
1545 prout(_(" from ") + crmena(False, enemy.type, where, enemy.location))
1547 # Decide if hit is critical
1553 if game.energy <= 0:
1554 # Returning home upon your shield, not with it...
1557 if not attempt and game.condition == "docked":
1558 prout(_("***Enemies decide against attacking your ship."))
1559 percent = 100.0*pfac*game.shield+0.5
1561 # Shields fully protect ship
1562 proutn(_("Enemy attack reduces shield strength to "))
1564 # Emit message if starship suffered hit(s)
1566 proutn(_("Energy left %2d shields ") % int(game.energy))
1569 elif not damaged(DSHIELD):
1572 proutn(_("damaged, "))
1573 prout(_("%d%%, torpedoes left %d") % (percent, game.torps))
1574 # Check if anyone was hurt
1575 if hitmax >= 200 or hittot >= 500:
1576 icas = randrange(int(hittot * 0.015))
1579 prout(_("Mc Coy- \"Sickbay to bridge. We suffered %d casualties") % icas)
1580 prout(_(" in that last attack.\""))
1582 game.state.crew -= icas
1583 # After attack, reset average distance to enemies
1584 for enemy in game.enemies:
1585 enemy.kavgd = enemy.kdist
1589 def deadkl(w, etype, mv):
1590 "Kill a Klingon, Tholian, Romulan, or Thingy."
1591 # Added mv to allow enemy to "move" before dying
1592 proutn(crmena(True, etype, "sector", mv))
1593 # Decide what kind of enemy it is and update appropriately
1595 # Chalk up a Romulan
1596 game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans -= 1
1598 game.state.nromrem -= 1
1607 # Killed some type of Klingon
1608 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
1611 game.state.kcmdr.remove(game.quadrant)
1613 if game.state.kcmdr:
1614 schedule(FTBEAM, expran(1.0*game.incom/len(game.state.kcmdr)))
1615 if is_scheduled(FCDBAS) and game.battle == game.quadrant:
1618 game.state.remkl -= 1
1620 game.state.nscrem -= 1
1621 game.state.kscmdr.invalidate()
1626 # For each kind of enemy, finish message to player
1627 prout(_(" destroyed."))
1628 if game.unwon() == 0:
1631 # Remove enemy ship from arrays describing local conditions
1632 for e in game.enemies:
1639 "Return None if target is invalid, otherwise return a course angle."
1640 if not w.valid_sector():
1644 # C code this was translated from is wacky -- why the sign reversal?
1645 delta.j = (w.j - game.sector.j)
1646 delta.i = (game.sector.i - w.i)
1647 if delta == Coord(0, 0):
1649 prout(_("Spock- \"Bridge to sickbay. Dr. McCoy,"))
1650 prout(_(" I recommend an immediate review of"))
1651 prout(_(" the Captain's psychological profile.\""))
1654 return delta.bearing()
1657 "Launch photon torpedo salvo."
1660 if damaged(DPHOTON):
1661 prout(_("Photon tubes damaged."))
1665 prout(_("No torpedoes left."))
1668 # First, get torpedo count
1671 if scanner.token == "IHALPHA":
1674 elif scanner.token == "IHEOL" or not scanner.waiting():
1675 prout(_("%d torpedoes left.") % game.torps)
1677 proutn(_("Number of torpedoes to fire- "))
1678 continue # Go back around to get a number
1679 else: # key == "IHREAL"
1681 if n <= 0: # abort command
1686 prout(_("Maximum of %d torpedoes per burst.") % MAXBURST)
1689 scanner.chew() # User requested more torps than available
1690 continue # Go back around
1691 break # All is good, go to next stage
1695 key = scanner.nexttok()
1696 if i == 0 and key == "IHEOL":
1697 break # no coordinate waiting, we will try prompting
1698 if i == 1 and key == "IHEOL":
1699 # direct all torpedoes at one target
1701 target.append(target[0])
1702 tcourse.append(tcourse[0])
1705 scanner.push(scanner.token)
1706 target.append(scanner.getcoord())
1707 if target[-1] is None:
1709 tcourse.append(targetcheck(target[-1]))
1710 if tcourse[-1] is None:
1713 if len(target) == 0:
1714 # prompt for each one
1716 proutn(_("Target sector for torpedo number %d- ") % (i+1))
1718 target.append(scanner.getcoord())
1719 if target[-1] is None:
1721 tcourse.append(targetcheck(target[-1]))
1722 if tcourse[-1] is None:
1725 # Loop for moving <n> torpedoes
1727 if game.condition != "docked":
1729 dispersion = (randreal()+randreal())*0.5 -0.5
1730 if math.fabs(dispersion) >= 0.47:
1732 dispersion *= randreal(1.2, 2.2)
1734 prouts(_("***TORPEDO NUMBER %d MISFIRES") % (i+1))
1736 prouts(_("***TORPEDO MISFIRES."))
1739 prout(_(" Remainder of burst aborted."))
1741 prout(_("***Photon tubes damaged by misfire."))
1742 game.damage[DPHOTON] = game.damfac * randreal(1.0, 3.0)
1746 elif game.shldup or game.condition == "docked":
1747 dispersion *= 1.0 + 0.0001*game.shield
1748 torpedo(game.sector, tcourse[i], dispersion, number=i, nburst=n)
1749 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
1755 "Check for phasers overheating."
1757 checkburn = (rpow-1500.0)*0.00038
1758 if withprob(checkburn):
1759 prout(_("Weapons officer Sulu- \"Phasers overheated, sir.\""))
1760 game.damage[DPHASER] = game.damfac* randreal(1.0, 2.0) * (1.0+checkburn)
1762 def checkshctrl(rpow):
1763 "Check shield control."
1766 prout(_("Shields lowered."))
1768 # Something bad has happened
1769 prouts(_("***RED ALERT! RED ALERT!"))
1771 hit = rpow*game.shield/game.inshld
1772 game.energy -= rpow+hit*0.8
1773 game.shield -= hit*0.2
1774 if game.energy <= 0.0:
1775 prouts(_("Sulu- \"Captain! Shield malf***********************\""))
1780 prouts(_("Sulu- \"Captain! Shield malfunction! Phaser fire contained!\""))
1782 prout(_("Lt. Uhura- \"Sir, all decks reporting damage.\""))
1783 icas = randrange(int(hit*0.012))
1788 prout(_("McCoy to bridge- \"Severe radiation burns, Jim."))
1789 prout(_(" %d casualties so far.\"") % icas)
1791 game.state.crew -= icas
1793 prout(_("Phaser energy dispersed by shields."))
1794 prout(_("Enemy unaffected."))
1799 "Register a phaser hit on Klingons and Romulans."
1804 if not kk < len(game.enemies):
1805 # Should never happen.
1809 dustfac = randreal(0.9, 1.0)
1810 hit = wham*math.pow(dustfac, game.enemies[kk].kdist)
1811 kpini = game.enemies[kk].power
1812 kp = math.fabs(kpini)
1813 if PHASEFAC*hit < kp:
1815 if game.enemies[kk].power < 0:
1816 game.enemies[kk].power -= -kp
1818 game.enemies[kk].power -= kp
1819 kpow = game.enemies[kk].power
1820 w = game.enemies[kk].location
1822 if not damaged(DSRSENS):
1824 proutn(_("%d unit hit on ") % int(hit))
1826 proutn(_("Very small hit on "))
1827 ienm = game.quad[w.i][w.j]
1830 proutn(crmena(False, ienm, "sector", w))
1839 else: # decide whether or not to emasculate klingon
1840 if kpow > 0 and withprob(0.9) and kpow <= randreal(0.4, 0.8)*kpini:
1841 prout(_("***Mr. Spock- \"Captain, the vessel at Sector %s")%w)
1842 prout(_(" has just lost its firepower.\""))
1843 game.enemies[kk].power = -kpow
1848 "Fire phasers at bad guys."
1852 irec = 0 # Cheating inhibitor
1861 # SR sensors and Computer are needed for automode
1862 if damaged(DSRSENS) or damaged(DCOMPTR):
1864 if game.condition == "docked":
1865 prout(_("Phasers can't be fired through base shields."))
1868 if damaged(DPHASER):
1869 prout(_("Phaser control damaged."))
1873 if damaged(DSHCTRL):
1874 prout(_("High speed shield control damaged."))
1877 if game.energy <= 200.0:
1878 prout(_("Insufficient energy to activate high-speed shield control."))
1881 prout(_("Weapons Officer Sulu- \"High-speed shield control enabled, sir.\""))
1883 # Original code so convoluted, I re-did it all
1884 # (That was Tom Almy talking about the C code, I think -- ESR)
1885 while automode == "NOTSET":
1886 key = scanner.nexttok()
1887 if key == "IHALPHA":
1888 if scanner.sees("manual"):
1889 if len(game.enemies)==0:
1890 prout(_("There is no enemy present to select."))
1893 automode = "AUTOMATIC"
1896 key = scanner.nexttok()
1897 elif scanner.sees("automatic"):
1898 if (not itarg) and len(game.enemies) != 0:
1899 automode = "FORCEMAN"
1901 if len(game.enemies)==0:
1902 prout(_("Energy will be expended into space."))
1903 automode = "AUTOMATIC"
1904 key = scanner.nexttok()
1905 elif scanner.sees("no"):
1910 elif key == "IHREAL":
1911 if len(game.enemies)==0:
1912 prout(_("Energy will be expended into space."))
1913 automode = "AUTOMATIC"
1915 automode = "FORCEMAN"
1917 automode = "AUTOMATIC"
1920 if len(game.enemies)==0:
1921 prout(_("Energy will be expended into space."))
1922 automode = "AUTOMATIC"
1924 automode = "FORCEMAN"
1926 proutn(_("Manual or automatic? "))
1931 if automode == "AUTOMATIC":
1932 if key == "IHALPHA" and scanner.sees("no"):
1934 key = scanner.nexttok()
1935 if key != "IHREAL" and len(game.enemies) != 0:
1936 prout(_("Phasers locked on target. Energy available: %.2f")%avail)
1941 for i in range(len(game.enemies)):
1942 irec += math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))*randreal(1.01, 1.06) + 1.0
1944 proutn(_("%d units required. ") % irec)
1946 proutn(_("Units to fire= "))
1947 key = scanner.nexttok()
1952 proutn(_("Energy available= %.2f") % avail)
1955 if not rpow > avail:
1961 key = scanner.nexttok()
1962 if key == "IHALPHA" and scanner.sees("no"):
1965 game.energy -= 200 # Go and do it!
1966 if checkshctrl(rpow):
1971 if len(game.enemies):
1974 for i in range(len(game.enemies)):
1978 hits[i] = math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))
1979 over = randreal(1.01, 1.06) * hits[i]
1981 powrem -= hits[i] + over
1982 if powrem <= 0 and temp < hits[i]:
1991 if extra > 0 and not game.alldone:
1993 proutn(_("*** Tholian web absorbs "))
1994 if len(game.enemies)>0:
1995 proutn(_("excess "))
1996 prout(_("phaser energy."))
1998 prout(_("%d expended on empty space.") % int(extra))
1999 elif automode == "FORCEMAN":
2002 if damaged(DCOMPTR):
2003 prout(_("Battle computer damaged, manual fire only."))
2006 prouts(_("---WORKING---"))
2008 prout(_("Short-range-sensors-damaged"))
2009 prout(_("Insufficient-data-for-automatic-phaser-fire"))
2010 prout(_("Manual-fire-must-be-used"))
2012 elif automode == "MANUAL":
2014 for k in range(len(game.enemies)):
2015 aim = game.enemies[k].location
2016 ienm = game.quad[aim.i][aim.j]
2018 proutn(_("Energy available= %.2f") % (avail-0.006))
2022 if damaged(DSRSENS) and \
2023 not game.sector.distance(aim)<2**0.5 and ienm in ('C', 'S'):
2024 prout(cramen(ienm) + _(" can't be located without short range scan."))
2027 hits[k] = 0 # prevent overflow -- thanks to Alexei Voitenko
2032 if itarg and k > kz:
2033 irec = (abs(game.enemies[k].power)/(PHASEFAC*math.pow(0.9, game.enemies[k].kdist))) * randreal(1.01, 1.06) + 1.0
2036 if not damaged(DCOMPTR):
2041 proutn(_("units to fire at %s- ") % crmena(False, ienm, "sector", aim))
2042 key = scanner.nexttok()
2043 if key == "IHALPHA" and scanner.sees("no"):
2045 key = scanner.nexttok()
2047 if key == "IHALPHA":
2051 if k == 1: # Let me say I'm baffled by this
2054 if scanner.real < 0:
2058 hits[k] = scanner.real
2059 rpow += scanner.real
2060 # If total requested is too much, inform and start over
2062 prout(_("Available energy exceeded -- try again."))
2065 key = scanner.nexttok() # scan for next value
2068 # zero energy -- abort
2071 if key == "IHALPHA" and scanner.sees("no"):
2076 game.energy -= 200.0
2077 if checkshctrl(rpow):
2081 # Say shield raised or malfunction, if necessary
2088 prout(_("Sulu- \"Sir, the high-speed shield control has malfunctioned . . ."))
2089 prouts(_(" CLICK CLICK POP . . ."))
2090 prout(_(" No response, sir!"))
2093 prout(_("Shields raised."))
2100 game.ididit = False # Nothing if we fail
2103 # Make sure there is room in the brig */
2104 if game.brigfree == 0:
2105 prout(_("Security reports the brig is already full."))
2109 prout(_("Uhura- \"We have no subspace radio communication, sir.\""))
2112 if damaged(DTRANSP):
2113 prout(_("Scotty- \"Transporter damaged, sir.\""))
2116 # find out if there are any at all
2118 prout(_("Uhura- \"Getting no response, sir.\""))
2121 # if there is more than one Klingon, find out which one */
2122 # Cruddy, just takes one at random. Should ask the captain.
2123 # Nah, just select the weakest one since it is most likely to
2124 # surrender (Tom Almy mod)
2125 klingons = [e for e in game.enemies if e.type == 'K']
2126 weakest = sorted(klingons, key=lambda e: e.power)[0]
2127 game.optime = 0.05 # This action will take some time
2128 game.ididit = True # So any others can strike back
2130 # check out that Klingon
2131 # The algorithm isn't that great and could use some more
2132 # intelligent design
2133 # x = 300 + 25*skill;
2134 x = game.energy / (weakest.power * len(klingons))
2135 #prout(_("Stats: energy = %s, kpower = %s, klingons = %s")
2136 # % (game.energy, weakest.power, len(klingons)))
2137 x *= 2.5 # would originally have been equivalent of 1.4,
2138 # but we want command to work more often, more humanely */
2139 #prout(_("Prob = %.4f" % x))
2140 # x = 100; // For testing, of course!
2141 if x < randreal(100):
2142 # guess what, he surrendered!!! */
2143 prout(_("Klingon captain at %s surrenders.") % weakest.location)
2146 prout(_("%d Klingons commit suicide rather than be taken captive.") % (200 - i))
2147 if i > game.brigfree:
2148 prout(_("%d Klingons die because there is no room for them in the brig.") % (i-brigfree))
2151 prout(_("%d captives taken") % i)
2152 deadkl(weakest.location, weakest.type, game.sector)
2157 # big surprise, he refuses to surrender */
2158 prout(_("Fat chance, captain!"))
2160 # Code from events.c begins here.
2162 # This isn't a real event queue a la BSD Trek yet -- you can only have one
2163 # event of each type active at any given time. Mostly these means we can
2164 # only have one FDISTR/FENSLV/FREPRO sequence going at any given time
2165 # BSD Trek, from which we swiped the idea, can have up to 5.
2167 def unschedule(evtype):
2168 "Remove an event from the schedule."
2169 game.future[evtype].date = FOREVER
2170 return game.future[evtype]
2172 def is_scheduled(evtype):
2173 "Is an event of specified type scheduled."
2174 return game.future[evtype].date != FOREVER
2176 def scheduled(evtype):
2177 "When will this event happen?"
2178 return game.future[evtype].date
2180 def schedule(evtype, offset):
2181 "Schedule an event of specified type."
2182 game.future[evtype].date = game.state.date + offset
2183 return game.future[evtype]
2185 def postpone(evtype, offset):
2186 "Postpone a scheduled event."
2187 game.future[evtype].date += offset
2190 "Rest period is interrupted by event."
2193 proutn(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
2195 game.resting = False
2201 "Run through the event queue looking for things to do."
2203 fintim = game.state.date + game.optime
2212 def tractorbeam(yank):
2213 "Tractor-beaming cases merge here."
2215 game.optime = (10.0/(7.5*7.5))*yank # 7.5 is yank rate (warp 7.5)
2217 prout("***" + crmshp() + _(" caught in long range tractor beam--"))
2218 # If Kirk & Co. screwing around on planet, handle
2219 atover(True) # atover(true) is Grab
2222 if game.icraft: # Caught in Galileo?
2225 # Check to see if shuttle is aboard
2226 if game.iscraft == "offship":
2229 prout(_("Galileo, left on the planet surface, is captured"))
2230 prout(_("by aliens and made into a flying McDonald's."))
2231 game.damage[DSHUTTL] = -10
2232 game.iscraft = "removed"
2234 prout(_("Galileo, left on the planet surface, is well hidden."))
2236 game.quadrant = game.state.kscmdr
2238 game.quadrant = game.state.kcmdr[i]
2239 game.sector = randplace(QUADSIZE)
2240 prout(crmshp() + _(" is pulled to Quadrant %s, Sector %s") \
2241 % (game.quadrant, game.sector))
2243 prout(_("(Remainder of rest/repair period cancelled.)"))
2244 game.resting = False
2246 if not damaged(DSHIELD) and game.shield > 0:
2247 doshield(shraise=True) # raise shields
2248 game.shldchg = False
2250 prout(_("(Shields not currently useable.)"))
2252 # Adjust finish time to time of tractor beaming?
2253 # fintim = game.state.date+game.optime
2254 attack(torps_ok=False)
2255 if not game.state.kcmdr:
2258 schedule(FTBEAM, game.optime+expran(1.5*game.intime/len(game.state.kcmdr)))
2261 "Code merges here for any commander destroying a starbase."
2262 # Not perfect, but will have to do
2263 # Handle case where base is in same quadrant as starship
2264 if game.battle == game.quadrant:
2265 game.state.chart[game.battle.i][game.battle.j].starbase = False
2266 game.quad[game.base.i][game.base.j] = '.'
2267 game.base.invalidate()
2270 prout(_("Spock- \"Captain, I believe the starbase has been destroyed.\""))
2271 elif game.state.baseq and communicating():
2272 # Get word via subspace radio
2275 prout(_("Lt. Uhura- \"Captain, Starfleet Command reports that"))
2276 proutn(_(" the starbase in Quadrant %s has been destroyed by") % game.battle)
2278 prout(_("the Klingon Super-Commander"))
2280 prout(_("a Klingon Commander"))
2281 game.state.chart[game.battle.i][game.battle.j].starbase = False
2282 # Remove Starbase from galaxy
2283 game.state.galaxy[game.battle.i][game.battle.j].starbase = False
2284 game.state.baseq = [x for x in game.state.baseq if x != game.battle]
2286 # reinstate a commander's base attack
2290 game.battle.invalidate()
2292 prout("=== EVENTS from %.2f to %.2f:" % (game.state.date, fintim))
2293 for i in range(1, NEVENTS):
2294 if i == FSNOVA: proutn("=== Supernova ")
2295 elif i == FTBEAM: proutn("=== T Beam ")
2296 elif i == FSNAP: proutn("=== Snapshot ")
2297 elif i == FBATTAK: proutn("=== Base Attack ")
2298 elif i == FCDBAS: proutn("=== Base Destroy ")
2299 elif i == FSCMOVE: proutn("=== SC Move ")
2300 elif i == FSCDBAS: proutn("=== SC Base Destroy ")
2301 elif i == FDSPROB: proutn("=== Probe Move ")
2302 elif i == FDISTR: proutn("=== Distress Call ")
2303 elif i == FENSLV: proutn("=== Enslavement ")
2304 elif i == FREPRO: proutn("=== Klingon Build ")
2306 prout("%.2f" % (scheduled(i)))
2309 radio_was_broken = damaged(DRADIO)
2312 # Select earliest extraneous event, evcode==0 if no events
2317 for l in range(1, NEVENTS):
2318 if game.future[l].date < datemin:
2321 prout("== Event %d fires" % evcode)
2322 datemin = game.future[l].date
2323 xtime = datemin-game.state.date
2325 game.energy -= xtime*500.0
2326 if game.energy <= 0:
2329 game.state.date = datemin
2330 # Decrement Federation resources and recompute remaining time
2331 game.state.remres -= (game.state.remkl+4*len(game.state.kcmdr))*xtime
2333 if game.state.remtime <= 0:
2336 # Any crew left alive?
2337 if game.state.crew <= 0:
2340 # Is life support adequate?
2341 if damaged(DLIFSUP) and game.condition != "docked":
2342 if game.lsupres < xtime and game.damage[DLIFSUP] > game.lsupres:
2345 game.lsupres -= xtime
2346 if game.damage[DLIFSUP] <= xtime:
2347 game.lsupres = game.inlsr
2350 if game.condition == "docked":
2352 # Don't fix Deathray here
2353 for l in range(NDEVICES):
2354 if game.damage[l] > 0.0 and l != DDRAY:
2355 if game.damage[l]-repair > 0.0:
2356 game.damage[l] -= repair
2358 game.damage[l] = 0.0
2359 # If radio repaired, update star chart and attack reports
2360 if radio_was_broken and not damaged(DRADIO):
2361 prout(_("Lt. Uhura- \"Captain, the sub-space radio is working and"))
2362 prout(_(" surveillance reports are coming in."))
2364 if not game.iseenit:
2368 prout(_(" The star chart is now up to date.\""))
2370 # Cause extraneous event EVCODE to occur
2371 game.optime -= xtime
2372 if evcode == FSNOVA: # Supernova
2375 schedule(FSNOVA, expran(0.5*game.intime))
2376 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2378 elif evcode == FSPY: # Check with spy to see if SC should tractor beam
2379 if game.state.nscrem == 0 or game.iscloaked or \
2380 ictbeam or istract or \
2381 game.condition == "docked" or game.isatb == 1 or game.iscate:
2383 if game.ientesc or \
2384 (game.energy<2000 and game.torps<4 and game.shield < 1250) or \
2385 (damaged(DPHASER) and (damaged(DPHOTON) or game.torps<4)) or \
2386 (damaged(DSHIELD) and \
2387 (game.energy < 2500 or damaged(DPHASER)) and \
2388 (game.torps < 5 or damaged(DPHOTON))):
2390 istract = ictbeam = True
2391 tractorbeam((game.state.kscmdr-game.quadrant).distance())
2394 elif evcode == FTBEAM: # Tractor beam
2395 if not game.state.kcmdr:
2398 i = randrange(len(game.state.kcmdr))
2399 yank = (game.state.kcmdr[i]-game.quadrant).distance()
2400 if istract or game.condition == "docked" or game.iscloaked or yank == 0:
2401 # Drats! Have to reschedule
2403 game.optime + expran(1.5*game.intime/len(game.state.kcmdr)))
2407 elif evcode == FSNAP: # Snapshot of the universe (for time warp)
2408 game.snapsht = copy.deepcopy(game.state)
2409 game.state.snap = True
2410 schedule(FSNAP, expran(0.5 * game.intime))
2411 elif evcode == FBATTAK: # Commander attacks starbase
2412 if not game.state.kcmdr or not game.state.baseq:
2417 ibq = None # Force battle location to persist past loop
2419 for ibq in game.state.baseq:
2420 for cmdr in game.state.kcmdr:
2421 if ibq == cmdr and ibq != game.quadrant and ibq != game.state.kscmdr:
2423 # no match found -- try later
2424 schedule(FBATTAK, expran(0.3*game.intime))
2429 # commander + starbase combination found -- launch attack
2431 schedule(FCDBAS, randreal(1.0, 4.0))
2432 if game.isatb: # extra time if SC already attacking
2433 postpone(FCDBAS, scheduled(FSCDBAS)-game.state.date)
2434 game.future[FBATTAK].date = game.future[FCDBAS].date + expran(0.3*game.intime)
2435 game.iseenit = False
2436 if not communicating():
2437 continue # No warning :-(
2441 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") % game.battle)
2442 prout(_(" reports that it is under attack and that it can"))
2443 prout(_(" hold out only until stardate %d.\"") % (int(scheduled(FCDBAS))))
2446 elif evcode == FSCDBAS: # Supercommander destroys base
2449 if not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].starbase:
2450 continue # WAS RETURN!
2452 game.battle = game.state.kscmdr
2454 elif evcode == FCDBAS: # Commander succeeds in destroying base
2455 if evcode == FCDBAS:
2457 if not game.state.baseq() \
2458 or not game.state.galaxy[game.battle.i][game.battle.j].starbase:
2459 game.battle.invalidate()
2461 # find the lucky pair
2462 for cmdr in game.state.kcmdr:
2463 if cmdr == game.battle:
2466 # No action to take after all
2469 elif evcode == FSCMOVE: # Supercommander moves
2470 schedule(FSCMOVE, 0.2777)
2471 if not game.ientesc and not istract and game.isatb != 1 and \
2472 (not game.iscate or not game.justin):
2474 elif evcode == FDSPROB: # Move deep space probe
2475 schedule(FDSPROB, 0.01)
2476 if not game.probe.nexttok():
2477 if not game.probe.quadrant().valid_quadrant() or \
2478 game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j].supernova:
2479 # Left galaxy or ran into supernova
2483 proutn(_("Lt. Uhura- \"The deep space probe "))
2484 if not game.probe.quadrant().valid_quadrant():
2485 prout(_("has left the galaxy.\""))
2487 prout(_("is no longer transmitting.\""))
2493 prout(_("Lt. Uhura- \"The deep space probe is now in Quadrant %s.\"") % game.probe.quadrant())
2494 pquad = game.probe.quadrant()
2495 pdest = game.state.galaxy[pquad.i][pquad.j]
2497 game.state.chart[pquad.i][pquad.j].klingons = pdest.klingons
2498 game.state.chart[pquad.i][pquad.j].starbase = pdest.starbase
2499 game.state.chart[pquad.i][pquad.j].stars = pdest.stars
2500 pdest.charted = True
2501 game.probe.moves -= 1 # One less to travel
2502 if game.probe.arrived() and game.isarmed and pdest.stars:
2503 supernova(game.probe) # fire in the hole!
2505 if game.state.galaxy[pquad.i][pquad.j].supernova:
2507 elif evcode == FDISTR: # inhabited system issues distress call
2509 # try a whole bunch of times to find something suitable
2510 for i in range(100):
2511 # need a quadrant which is not the current one,
2512 # which has some stars which are inhabited and
2513 # not already under attack, which is not
2514 # supernova'ed, and which has some Klingons in it
2515 w = randplace(GALSIZE)
2516 q = game.state.galaxy[w.i][w.j]
2517 if not (game.quadrant == w or q.planet is None or \
2518 not q.planet.inhabited or \
2519 q.supernova or q.status!="secure" or q.klingons<=0):
2522 # can't seem to find one; ignore this call
2524 prout("=== Couldn't find location for distress event.")
2526 # got one!! Schedule its enslavement
2527 ev = schedule(FENSLV, expran(game.intime))
2529 q.status = "distressed"
2530 # tell the captain about it if we can
2532 prout(_("Uhura- Captain, %s in Quadrant %s reports it is under attack") \
2533 % (q.planet, repr(w)))
2534 prout(_("by a Klingon invasion fleet."))
2537 elif evcode == FENSLV: # starsystem is enslaved
2538 ev = unschedule(FENSLV)
2539 # see if current distress call still active
2540 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2544 q.status = "enslaved"
2546 # play stork and schedule the first baby
2547 ev2 = schedule(FREPRO, expran(2.0 * game.intime))
2548 ev2.quadrant = ev.quadrant
2550 # report the disaster if we can
2552 prout(_("Uhura- We've lost contact with starsystem %s") % \
2554 prout(_("in Quadrant %s.\n") % ev.quadrant)
2555 elif evcode == FREPRO: # Klingon reproduces
2556 # If we ever switch to a real event queue, we'll need to
2557 # explicitly retrieve and restore the x and y.
2558 ev = schedule(FREPRO, expran(1.0 * game.intime))
2559 # see if current distress call still active
2560 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2564 if game.state.remkl >= MAXKLGAME:
2565 continue # full right now
2566 # reproduce one Klingon
2569 if game.klhere >= MAXKLQUAD:
2571 # this quadrant not ok, pick an adjacent one
2572 for m.i in range(w.i - 1, w.i + 2):
2573 for m.j in range(w.j - 1, w.j + 2):
2574 if not m.valid_quadrant():
2576 q = game.state.galaxy[m.i][m.j]
2577 # check for this quad ok (not full & no snova)
2578 if q.klingons >= MAXKLQUAD or q.supernova:
2581 # search for eligible quadrant failed
2586 game.state.remkl += 1
2588 if game.quadrant == w:
2590 game.enemies.append(newkling())
2591 # recompute time left
2594 if game.quadrant == w:
2595 prout(_("Spock- sensors indicate the Klingons have"))
2596 prout(_("launched a warship from %s.") % q.planet)
2598 prout(_("Uhura- Starfleet reports increased Klingon activity"))
2599 if q.planet != None:
2600 proutn(_("near %s ") % q.planet)
2601 prout(_("in Quadrant %s.") % w)
2607 key = scanner.nexttok()
2610 proutn(_("How long? "))
2615 origTime = delay = scanner.real
2618 if delay >= game.state.remtime or len(game.enemies) != 0:
2619 proutn(_("Are you sure? "))
2622 # Alternate resting periods (events) with attacks
2626 game.resting = False
2627 if not game.resting:
2628 prout(_("%d stardates left.") % int(game.state.remtime))
2630 temp = game.optime = delay
2631 if len(game.enemies):
2632 rtime = randreal(1.0, 2.0)
2636 if game.optime < delay:
2637 attack(torps_ok=False)
2645 # Repair Deathray if long rest at starbase
2646 if origTime-delay >= 9.99 and game.condition == "docked":
2647 game.damage[DDRAY] = 0.0
2648 # leave if quadrant supernovas
2649 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2651 game.resting = False
2656 ncourse = (0.0, 10.5, 12.0, 1.5, 9.0, 0.0, 3.0, 7.5, 6.0, 4.5)
2657 newc = Coord(); neighbor = Coord(); bump = Coord(0, 0)
2659 # Wow! We've supernova'ed
2660 supernova(game.quadrant)
2662 # handle initial nova
2663 game.quad[nov.i][nov.j] = '.'
2664 prout(crmena(False, '*', "sector", nov) + _(" novas."))
2665 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2666 game.state.starkl += 1
2667 # Set up queue to recursively trigger adjacent stars
2673 for offset.i in range(-1, 1+1):
2674 for offset.j in range(-1, 1+1):
2675 if offset.j == 0 and offset.i == 0:
2677 neighbor = start + offset
2678 if not neighbor.valid_sector():
2680 iquad = game.quad[neighbor.i][neighbor.j]
2681 # Empty space ends reaction
2682 if iquad in ('.', '?', ' ', 'T', '#'):
2684 elif iquad == '*': # Affect another star
2686 # This star supernovas
2687 supernova(game.quadrant)
2690 hits.append(neighbor)
2691 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2692 game.state.starkl += 1
2693 proutn(crmena(True, '*', "sector", neighbor))
2695 game.quad[neighbor.i][neighbor.j] = '.'
2697 elif iquad in ('P', '@'): # Destroy planet
2698 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
2700 game.state.nplankl += 1
2702 game.state.nworldkl += 1
2703 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2704 game.iplnet.pclass = "destroyed"
2706 game.plnet.invalidate()
2710 game.quad[neighbor.i][neighbor.j] = '.'
2711 elif iquad == 'B': # Destroy base
2712 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
2713 game.state.baseq = [x for x in game.state.baseq if x!= game.quadrant]
2714 game.base.invalidate()
2715 game.state.basekl += 1
2717 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2718 game.quad[neighbor.i][neighbor.j] = '.'
2719 elif iquad in ('E', 'F'): # Buffet ship
2720 prout(_("***Starship buffeted by nova."))
2722 if game.shield >= 2000.0:
2723 game.shield -= 2000.0
2725 diff = 2000.0 - game.shield
2729 prout(_("***Shields knocked out."))
2730 game.damage[DSHIELD] += 0.005*game.damfac*randreal()*diff
2732 game.energy -= 2000.0
2733 if game.energy <= 0:
2736 # add in course nova contributes to kicking starship
2737 bump += (game.sector-hits[-1]).sgn()
2738 elif iquad == 'K': # kill klingon
2739 deadkl(neighbor, iquad, neighbor)
2740 elif iquad in ('C','S','R'): # Damage/destroy big enemies
2742 for ll in range(len(game.enemies)):
2743 if game.enemies[ll].location == neighbor:
2744 target = game.enemies[ll]
2746 if target is not None:
2747 target.power -= 800.0 # If firepower is lost, die
2748 if target.power <= 0.0:
2749 deadkl(neighbor, iquad, neighbor)
2750 continue # neighbor loop
2751 # Else enemy gets flung by the blast wave
2752 newc = neighbor + neighbor - hits[-1]
2753 proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged"))
2754 if not newc.valid_sector():
2755 # can't leave quadrant
2758 iquad1 = game.quad[newc.i][newc.j]
2760 proutn(_(", blasted into ") + crmena(False, ' ', "sector", newc))
2762 deadkl(neighbor, iquad, newc)
2765 # can't move into something else
2768 proutn(_(", buffeted to Sector %s") % newc)
2769 game.quad[neighbor.i][neighbor.j] = '.'
2770 game.quad[newc.i][newc.j] = iquad
2772 # Starship affected by nova -- kick it away.
2774 direc = ncourse[3*(bump.i+1)+bump.j+2]
2779 scourse = course(bearing=direc, distance=dist)
2780 game.optime = scourse.time(w=4)
2782 prout(_("Force of nova displaces starship."))
2783 imove(scourse, noattack=True)
2784 game.optime = scourse.time(w=4)
2788 "Star goes supernova."
2793 # Scheduled supernova -- select star at random.
2796 for nq.i in range(GALSIZE):
2797 for nq.j in range(GALSIZE):
2798 nstars += game.state.galaxy[nq.i][nq.j].stars
2800 return # nothing to supernova exists
2801 num = randrange(nstars) + 1
2802 for nq.i in range(GALSIZE):
2803 for nq.j in range(GALSIZE):
2804 num -= game.state.galaxy[nq.i][nq.j].stars
2810 proutn("=== Super nova here?")
2813 if not nq == game.quadrant or game.justin:
2814 # it isn't here, or we just entered (treat as enroute)
2817 prout(_("Message from Starfleet Command Stardate %.2f") % game.state.date)
2818 prout(_(" Supernova in Quadrant %s; caution advised.") % nq)
2821 # we are in the quadrant!
2822 num = randrange(game.state.galaxy[nq.i][nq.j].stars) + 1
2823 for ns.i in range(QUADSIZE):
2824 for ns.j in range(QUADSIZE):
2825 if game.quad[ns.i][ns.j]=='*':
2832 prouts(_("***RED ALERT! RED ALERT!"))
2834 prout(_("***Incipient supernova detected at Sector %s") % ns)
2835 if (ns.i-game.sector.i)**2 + (ns.j-game.sector.j)**2 <= 2.1:
2836 proutn(_("Emergency override attempts t"))
2837 prouts("***************")
2841 # destroy any Klingons in supernovaed quadrant
2842 kldead = game.state.galaxy[nq.i][nq.j].klingons
2843 game.state.galaxy[nq.i][nq.j].klingons = 0
2844 if nq == game.state.kscmdr:
2845 # did in the Supercommander!
2846 game.state.nscrem = game.state.kscmdr.i = game.state.kscmdr.j = game.isatb = 0
2850 survivors = filter(lambda w: w != nq, game.state.kcmdr)
2851 comkills = len(game.state.kcmdr) - len(survivors)
2852 game.state.kcmdr = survivors
2854 if not game.state.kcmdr:
2856 game.state.remkl -= kldead
2857 # destroy Romulans and planets in supernovaed quadrant
2858 nrmdead = game.state.galaxy[nq.i][nq.j].romulans
2859 game.state.galaxy[nq.i][nq.j].romulans = 0
2860 game.state.nromrem -= nrmdead
2862 for loop in range(game.inplan):
2863 if game.state.planets[loop].quadrant == nq:
2864 game.state.planets[loop].pclass = "destroyed"
2866 # Destroy any base in supernovaed quadrant
2867 game.state.baseq = [x for x in game.state.baseq if x != nq]
2868 # If starship caused supernova, tally up destruction
2870 game.state.starkl += game.state.galaxy[nq.i][nq.j].stars
2871 game.state.basekl += game.state.galaxy[nq.i][nq.j].starbase
2872 game.state.nplankl += npdead
2873 # mark supernova in galaxy and in star chart
2874 if game.quadrant == nq or communicating():
2875 game.state.galaxy[nq.i][nq.j].supernova = True
2876 # If supernova destroys last Klingons give special message
2877 if game.unwon()==0 and not nq == game.quadrant:
2880 prout(_("Lucky you!"))
2881 proutn(_("A supernova in %s has just destroyed the last Klingons.") % nq)
2884 # if some Klingons remain, continue or die in supernova
2889 # Code from finish.c ends here.
2892 "Self-destruct maneuver. Finish with a BANG!"
2894 if damaged(DCOMPTR):
2895 prout(_("Computer damaged; cannot execute destruct sequence."))
2897 prouts(_("---WORKING---")); skip(1)
2898 prouts(_("SELF-DESTRUCT-SEQUENCE-ACTIVATED")); skip(1)
2899 prouts(" 10"); skip(1)
2900 prouts(" 9"); skip(1)
2901 prouts(" 8"); skip(1)
2902 prouts(" 7"); skip(1)
2903 prouts(" 6"); skip(1)
2905 prout(_("ENTER-CORRECT-PASSWORD-TO-CONTINUE-"))
2907 prout(_("SELF-DESTRUCT-SEQUENCE-OTHERWISE-"))
2909 prout(_("SELF-DESTRUCT-SEQUENCE-WILL-BE-ABORTED"))
2912 if game.passwd != scanner.token:
2913 prouts(_("PASSWORD-REJECTED;"))
2915 prouts(_("CONTINUITY-EFFECTED"))
2918 prouts(_("PASSWORD-ACCEPTED")); skip(1)
2919 prouts(" 5"); skip(1)
2920 prouts(" 4"); skip(1)
2921 prouts(" 3"); skip(1)
2922 prouts(" 2"); skip(1)
2923 prouts(" 1"); skip(1)
2925 prouts(_("GOODBYE-CRUEL-WORLD"))
2933 prouts(_("********* Entropy of %s maximized *********") % crmshp())
2937 if len(game.enemies) != 0:
2938 whammo = 25.0 * game.energy
2939 for l in range(len(game.enemies)):
2940 if game.enemies[l].power*game.enemies[l].kdist <= whammo:
2941 deadkl(game.enemies[l].location, game.quad[game.enemies[l].location.i][game.enemies[l].location.j], game.enemies[l].location)
2945 "Compute our rate of kils over time."
2946 elapsed = game.state.date - game.indate
2947 if elapsed == 0: # Avoid divide-by-zero error if calculated on turn 0
2950 starting = (game.inkling + game.incom + game.inscom)
2951 remaining = game.unwon()
2952 return (starting - remaining)/elapsed
2956 badpt = 5.0*game.state.starkl + \
2958 10.0*game.state.nplankl + \
2959 300*game.state.nworldkl + \
2961 100.0*game.state.basekl +\
2962 3.0*game.abandoned +\
2964 if game.ship == 'F':
2966 elif game.ship is None:
2971 # end the game, with appropriate notifications
2975 prout(_("It is stardate %.1f.") % game.state.date)
2977 if ifin == FWON: # Game has been won
2978 if game.state.nromrem != 0:
2979 prout(_("The remaining %d Romulans surrender to Starfleet Command.") %
2982 prout(_("You have smashed the Klingon invasion fleet and saved"))
2983 prout(_("the Federation."))
2984 if game.alive and game.brigcapacity-game.brigfree > 0:
2985 game.kcaptured += game.brigcapacity-game.brigfree
2986 prout(_("The %d captured Klingons are transferred to Star Fleet Command.") % (game.brigcapacity-game.brigfree))
2991 badpt = 0.0 # Close enough!
2992 # killsPerDate >= RateMax
2993 if game.state.date-game.indate < 5.0 or \
2994 killrate() >= 0.1*game.skill*(game.skill+1.0) + 0.1 + 0.008*badpt:
2996 prout(_("In fact, you have done so well that Starfleet Command"))
2997 if game.skill == SKILL_NOVICE:
2998 prout(_("promotes you one step in rank from \"Novice\" to \"Fair\"."))
2999 elif game.skill == SKILL_FAIR:
3000 prout(_("promotes you one step in rank from \"Fair\" to \"Good\"."))
3001 elif game.skill == SKILL_GOOD:
3002 prout(_("promotes you one step in rank from \"Good\" to \"Expert\"."))
3003 elif game.skill == SKILL_EXPERT:
3004 prout(_("promotes you to Commodore Emeritus."))
3006 prout(_("Now that you think you're really good, try playing"))
3007 prout(_("the \"Emeritus\" game. It will splatter your ego."))
3008 elif game.skill == SKILL_EMERITUS:
3010 proutn(_("Computer- "))
3011 prouts(_("ERROR-ERROR-ERROR-ERROR"))
3013 prouts(_(" YOUR-SKILL-HAS-EXCEEDED-THE-CAPACITY-OF-THIS-PROGRAM"))
3015 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
3017 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
3019 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
3021 prouts(_(" THIS-PROGRAM-MUST?- MUST ? - SUR? ? -? VI"))
3023 prout(_("Now you can retire and write your own Star Trek game!"))
3025 elif game.skill >= SKILL_EXPERT:
3026 if game.thawed and not game.idebug:
3027 prout(_("You cannot get a citation, so..."))
3029 proutn(_("Do you want your Commodore Emeritus Citation printed? "))
3033 # Only grant long life if alive (original didn't!)
3035 prout(_("LIVE LONG AND PROSPER."))
3040 elif ifin == FDEPLETE: # Federation Resources Depleted
3041 prout(_("Your time has run out and the Federation has been"))
3042 prout(_("conquered. Your starship is now Klingon property,"))
3043 prout(_("and you are put on trial as a war criminal. On the"))
3044 proutn(_("basis of your record, you are "))
3045 if game.unwon()*3.0 > (game.inkling + game.incom + game.inscom):
3046 prout(_("acquitted."))
3048 prout(_("LIVE LONG AND PROSPER."))
3050 prout(_("found guilty and"))
3051 prout(_("sentenced to death by slow torture."))
3055 elif ifin == FLIFESUP:
3056 prout(_("Your life support reserves have run out, and"))
3057 prout(_("you die of thirst, starvation, and asphyxiation."))
3058 prout(_("Your starship is a derelict in space."))
3060 prout(_("Your energy supply is exhausted."))
3062 prout(_("Your starship is a derelict in space."))
3063 elif ifin == FBATTLE:
3064 prout(_("The %s has been destroyed in battle.") % crmshp())
3066 prout(_("Dulce et decorum est pro patria mori."))
3068 prout(_("You have made three attempts to cross the negative energy"))
3069 prout(_("barrier which surrounds the galaxy."))
3071 prout(_("Your navigation is abominable."))
3074 prout(_("Your starship has been destroyed by a nova."))
3075 prout(_("That was a great shot."))
3077 elif ifin == FSNOVAED:
3078 prout(_("The %s has been fried by a supernova.") % crmshp())
3079 prout(_("...Not even cinders remain..."))
3080 elif ifin == FABANDN:
3081 prout(_("You have been captured by the Klingons. If you still"))
3082 prout(_("had a starbase to be returned to, you would have been"))
3083 prout(_("repatriated and given another chance. Since you have"))
3084 prout(_("no starbases, you will be mercilessly tortured to death."))
3085 elif ifin == FDILITHIUM:
3086 prout(_("Your starship is now an expanding cloud of subatomic particles"))
3087 elif ifin == FMATERIALIZE:
3088 prout(_("Starbase was unable to re-materialize your starship."))
3089 prout(_("Sic transit gloria mundi"))
3090 elif ifin == FPHASER:
3091 prout(_("The %s has been cremated by its own phasers.") % crmshp())
3093 prout(_("You and your landing party have been"))
3094 prout(_("converted to energy, dissipating through space."))
3095 elif ifin == FMINING:
3096 prout(_("You are left with your landing party on"))
3097 prout(_("a wild jungle planet inhabited by primitive cannibals."))
3099 prout(_("They are very fond of \"Captain Kirk\" soup."))
3101 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
3102 elif ifin == FDPLANET:
3103 prout(_("You and your mining party perish."))
3105 prout(_("That was a great shot."))
3108 prout(_("The Galileo is instantly annihilated by the supernova."))
3109 prout(_("You and your mining party are atomized."))
3111 prout(_("Mr. Spock takes command of the %s and") % crmshp())
3112 prout(_("joins the Romulans, wreaking terror on the Federation."))
3113 elif ifin == FPNOVA:
3114 prout(_("You and your mining party are atomized."))
3116 prout(_("Mr. Spock takes command of the %s and") % crmshp())
3117 prout(_("joins the Romulans, wreaking terror on the Federation."))
3118 elif ifin == FSTRACTOR:
3119 prout(_("The shuttle craft Galileo is also caught,"))
3120 prout(_("and breaks up under the strain."))
3122 prout(_("Your debris is scattered for millions of miles."))
3123 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
3125 prout(_("The mutants attack and kill Spock."))
3126 prout(_("Your ship is captured by Klingons, and"))
3127 prout(_("your crew is put on display in a Klingon zoo."))
3128 elif ifin == FTRIBBLE:
3129 prout(_("Tribbles consume all remaining water,"))
3130 prout(_("food, and oxygen on your ship."))
3132 prout(_("You die of thirst, starvation, and asphyxiation."))
3133 prout(_("Your starship is a derelict in space."))
3135 prout(_("Your ship is drawn to the center of the black hole."))
3136 prout(_("You are crushed into extremely dense matter."))
3137 elif ifin == FCLOAK:
3139 prout(_("You have violated the Treaty of Algeron."))
3140 prout(_("The Romulan Empire can never trust you again."))
3142 prout(_("Your last crew member has died."))
3143 if ifin != FWON and ifin != FCLOAK and game.iscloaked:
3144 prout(_("Your ship was cloaked so your subspace radio did not receive anything."))
3145 prout(_("You may have missed some warning messages."))
3147 if game.ship == 'F':
3149 elif game.ship == 'E':
3152 if game.unwon() != 0:
3153 goodies = game.state.remres/game.inresor
3154 baddies = (game.state.remkl + 2.0*len(game.state.kcmdr))/(game.inkling+2.0*game.incom)
3155 if goodies/baddies >= randreal(1.0, 1.5):
3156 prout(_("As a result of your actions, a treaty with the Klingon"))
3157 prout(_("Empire has been signed. The terms of the treaty are"))
3158 if goodies/baddies >= randreal(3.0):
3159 prout(_("favorable to the Federation."))
3161 prout(_("Congratulations!"))
3163 prout(_("highly unfavorable to the Federation."))
3165 prout(_("The Federation will be destroyed."))
3167 prout(_("Since you took the last Klingon with you, you are a"))
3168 prout(_("martyr and a hero. Someday maybe they'll erect a"))
3169 prout(_("statue in your memory. Rest in peace, and try not"))
3170 prout(_("to think about pigeons."))
3173 scanner.chew() # Clean up leftovers
3176 "Compute player's score."
3177 timused = game.state.date - game.indate
3178 if (timused == 0 or game.unwon() != 0) and timused < 5.0:
3180 game.perdate = killrate()
3181 ithperd = 500*game.perdate + 0.5
3184 iwon = 100*game.skill
3185 if game.ship == 'E':
3187 elif game.ship == 'F':
3191 game.score = 10*(game.inkling - game.state.remkl) \
3192 + 50*(game.incom - len(game.state.kcmdr)) \
3194 + 20*(game.inrom - game.state.nromrem) \
3195 + 200*(game.inscom - game.state.nscrem) \
3196 - game.state.nromrem \
3197 + 3 * game.kcaptured \
3202 prout(_("Your score --"))
3203 if game.inrom - game.state.nromrem:
3204 prout(_("%6d Romulans destroyed %5d") %
3205 (game.inrom - game.state.nromrem, 20*(game.inrom - game.state.nromrem)))
3206 if game.state.nromrem and game.gamewon:
3207 prout(_("%6d Romulans captured %5d") %
3208 (game.state.nromrem, game.state.nromrem))
3209 if game.inkling - game.state.remkl:
3210 prout(_("%6d ordinary Klingons destroyed %5d") %
3211 (game.inkling - game.state.remkl, 10*(game.inkling - game.state.remkl)))
3212 if game.incom - len(game.state.kcmdr):
3213 prout(_("%6d Klingon commanders destroyed %5d") %
3214 (game.incom - len(game.state.kcmdr), 50*(game.incom - len(game.state.kcmdr))))
3216 prout(_("%d Klingons captured %5d") %
3217 (game.kcaptured, 3 * game.kcaptured))
3218 if game.inscom - game.state.nscrem:
3219 prout(_("%6d Super-Commander destroyed %5d") %
3220 (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem)))
3222 prout(_("%6.2f Klingons per stardate %5d") %
3223 (game.perdate, ithperd))
3224 if game.state.starkl:
3225 prout(_("%6d stars destroyed by your action %5d") %
3226 (game.state.starkl, -5*game.state.starkl))
3227 if game.state.nplankl:
3228 prout(_("%6d planets destroyed by your action %5d") %
3229 (game.state.nplankl, -10*game.state.nplankl))
3230 if (game.options & OPTION_WORLDS) and game.state.nworldkl:
3231 prout(_("%6d inhabited planets destroyed by your action %5d") %
3232 (game.state.nworldkl, -300*game.state.nworldkl))
3233 if game.state.basekl:
3234 prout(_("%6d bases destroyed by your action %5d") %
3235 (game.state.basekl, -100*game.state.basekl))
3237 prout(_("%6d calls for help from starbase %5d") %
3238 (game.nhelp, -45*game.nhelp))
3240 prout(_("%6d casualties incurred %5d") %
3241 (game.casual, -game.casual))
3243 prout(_("%6d crew abandoned in space %5d") %
3244 (game.abandoned, -3*game.abandoned))
3246 prout(_("%6d ship(s) lost or destroyed %5d") %
3247 (klship, -100*klship))
3250 prout(_("1 Treaty of Algeron violation -100"))
3252 prout(_("%6d Treaty of Algeron violations %5d\n") %
3253 (ncviol, -100*ncviol))
3255 prout(_("Penalty for getting yourself killed -200"))
3257 proutn(_("Bonus for winning "))
3258 if game.skill == SKILL_NOVICE: proutn(_("Novice game "))
3259 elif game.skill == SKILL_FAIR: proutn(_("Fair game "))
3260 elif game.skill == SKILL_GOOD: proutn(_("Good game "))
3261 elif game.skill == SKILL_EXPERT: proutn(_("Expert game "))
3262 elif game.skill == SKILL_EMERITUS: proutn(_("Emeritus game"))
3263 prout(" %5d" % iwon)
3265 prout(_("TOTAL SCORE %5d") % game.score)
3268 "Emit winner's commemmorative plaque."
3271 proutn(_("File or device name for your plaque: "))
3274 fp = open(winner, "w")
3277 prout(_("Invalid name."))
3279 proutn(_("Enter name to go on plaque (up to 30 characters): "))
3281 # The 38 below must be 64 for 132-column paper
3282 nskip = 38 - len(winner)/2
3283 fp.write("\n\n\n\n")
3284 # --------DRAW ENTERPRISE PICTURE.
3285 fp.write(" EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n" )
3286 fp.write(" EEE E : : : E\n" )
3287 fp.write(" EE EEE E : : NCC-1701 : E\n")
3288 fp.write("EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEE : : : E\n")
3289 fp.write(" E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n")
3290 fp.write(" EEEEEEEEE EEEEEEEEEEEEE E E\n")
3291 fp.write(" EEEEEEE EEEEE E E E E\n")
3292 fp.write(" EEE E E E E\n")
3293 fp.write(" E E E E\n")
3294 fp.write(" EEEEEEEEEEEEE E E\n")
3295 fp.write(" EEE : EEEEEEE EEEEEEEE\n")
3296 fp.write(" :E : EEEE E\n")
3297 fp.write(" .-E -:----- E\n")
3298 fp.write(" :E : E\n")
3299 fp.write(" EE : EEEEEEEE\n")
3300 fp.write(" EEEEEEEEEEEEEEEEEEEEEEE\n")
3302 fp.write(_(" U. S. S. ENTERPRISE\n"))
3303 fp.write("\n\n\n\n")
3304 fp.write(_(" For demonstrating outstanding ability as a starship captain\n"))
3306 fp.write(_(" Starfleet Command bestows to you\n"))
3308 fp.write("%*s%s\n\n" % (nskip, "", winner))
3309 fp.write(_(" the rank of\n\n"))
3310 fp.write(_(" \"Commodore Emeritus\"\n\n"))
3312 if game.skill == SKILL_EXPERT:
3313 fp.write(_(" Expert level\n\n"))
3314 elif game.skill == SKILL_EMERITUS:
3315 fp.write(_("Emeritus level\n\n"))
3317 fp.write(_(" Cheat level\n\n"))
3318 timestring = time.ctime()
3319 fp.write(_(" This day of %.6s %.4s, %.8s\n\n") %
3320 (timestring+4, timestring+20, timestring+11))
3321 fp.write(_(" Your score: %d\n\n") % game.score)
3322 fp.write(_(" Klingons per stardate: %.2f\n") % game.perdate)
3325 # Code from io.c begins here
3327 rows = linecount = 0 # for paging
3330 fullscreen_window = None
3331 srscan_window = None # Short range scan
3332 report_window = None # Report legends for status window
3333 status_window = None # The status window itself
3334 lrscan_window = None # Long range scan
3335 message_window = None # Main window for scrolling text
3336 prompt_window = None # Prompt window at bottom of display
3341 # for some recent versions of python2, the following enables UTF8
3342 # for the older ones we probably need to set C locale, and python3
3343 # has no problems at all
3344 if sys.version_info[0] < 3:
3345 locale.setlocale(locale.LC_ALL, "")
3346 gettext.bindtextdomain("sst", "/usr/local/share/locale")
3347 gettext.textdomain("sst")
3348 if not (game.options & OPTION_CURSES):
3349 ln_env = os.getenv("LINES")
3355 stdscr = curses.initscr()
3359 if game.options & OPTION_COLOR:
3360 curses.start_color()
3361 curses.use_default_colors()
3362 curses.init_pair(curses.COLOR_BLACK, curses.COLOR_BLACK, -1)
3363 curses.init_pair(curses.COLOR_GREEN, curses.COLOR_GREEN, -1)
3364 curses.init_pair(curses.COLOR_RED, curses.COLOR_RED, -1)
3365 curses.init_pair(curses.COLOR_CYAN, curses.COLOR_CYAN, -1)
3366 curses.init_pair(curses.COLOR_WHITE, curses.COLOR_WHITE, -1)
3367 curses.init_pair(curses.COLOR_MAGENTA, curses.COLOR_MAGENTA, -1)
3368 curses.init_pair(curses.COLOR_BLUE, curses.COLOR_BLUE, -1)
3369 curses.init_pair(curses.COLOR_YELLOW, curses.COLOR_YELLOW, -1)
3370 global fullscreen_window, srscan_window, report_window, status_window
3371 global lrscan_window, message_window, prompt_window
3372 (rows, _columns) = stdscr.getmaxyx()
3373 fullscreen_window = stdscr
3374 srscan_window = curses.newwin(12, 25, 0, 0)
3375 report_window = curses.newwin(11, 0, 1, 25)
3376 status_window = curses.newwin(10, 0, 1, 39)
3377 lrscan_window = curses.newwin(5, 0, 0, 64)
3378 message_window = curses.newwin(0, 0, 12, 0)
3379 prompt_window = curses.newwin(1, 0, rows-2, 0)
3380 message_window.scrollok(True)
3381 setwnd(fullscreen_window)
3385 if game.options & OPTION_CURSES:
3386 stdscr.keypad(False)
3392 "Wait for user action -- OK to do nothing if on a TTY"
3393 if game.options & OPTION_CURSES:
3398 prouts(_("[ANNOUNCEMENT ARRIVING...]"))
3402 if game.skill > SKILL_FAIR:
3403 prompt = _("[CONTINUE?]")
3405 prompt = _("[PRESS ENTER TO CONTINUE]")
3407 if game.options & OPTION_CURSES:
3409 setwnd(prompt_window)
3410 prompt_window.clear()
3411 prompt_window.addstr(prompt)
3412 prompt_window.getstr()
3413 prompt_window.clear()
3414 prompt_window.refresh()
3415 setwnd(message_window)
3418 sys.stdout.write('\n')
3422 sys.stdout.write('\n' * rows)
3426 "Skip i lines. Pause game if this would cause a scrolling event."
3427 for _dummy in range(i):
3428 if game.options & OPTION_CURSES:
3429 (y, _x) = curwnd.getyx()
3432 except curses.error:
3437 if rows and linecount >= rows:
3440 sys.stdout.write('\n')
3442 def proutn(proutntline):
3443 "Utter a line with no following line feed."
3444 if game.options & OPTION_CURSES:
3445 (y, x) = curwnd.getyx()
3446 (my, _mx) = curwnd.getmaxyx()
3447 if curwnd == message_window and y >= my - 2:
3450 # Uncomment this to debug curses problems
3452 logfp.write("#curses: at %s proutn(%s)\n" % ((y, x), repr(proutntline)))
3453 curwnd.addstr(proutntline)
3456 sys.stdout.write(proutntline)
3459 def prout(proutline):
3463 def prouts(proutsline):
3465 for c in proutsline:
3466 if not replayfp or replayfp.closed: # Don't slow down replays
3469 if game.options & OPTION_CURSES:
3473 if not replayfp or replayfp.closed:
3477 "Get a line of input."
3478 if game.options & OPTION_CURSES:
3479 linein = curwnd.getstr() + "\n"
3482 if replayfp and not replayfp.closed:
3484 linein = replayfp.readline()
3487 prout("*** Replay finished")
3490 elif linein[0] != "#":
3494 linein = my_input() + "\n"
3503 "Change windows -- OK for this to be a no-op in tty mode."
3505 if game.options & OPTION_CURSES:
3506 # Uncomment this to debug curses problems
3508 if wnd == fullscreen_window:
3509 legend = "fullscreen"
3510 elif wnd == srscan_window:
3512 elif wnd == report_window:
3514 elif wnd == status_window:
3516 elif wnd == lrscan_window:
3518 elif wnd == message_window:
3520 elif wnd == prompt_window:
3524 logfp.write("#curses: setwnd(%s)\n" % legend)
3526 # Some curses implementations get confused when you try this.
3528 curses.curs_set(wnd in (fullscreen_window, message_window, prompt_window))
3529 except curses.error:
3533 "Clear to end of line -- can be a no-op in tty mode"
3534 if game.options & OPTION_CURSES:
3539 "Clear screen -- can be a no-op in tty mode."
3541 if game.options & OPTION_CURSES:
3547 def textcolor(color=DEFAULT):
3548 if (game.options & OPTION_COLOR) and (game.options & OPTION_CURSES):
3549 if color == DEFAULT:
3551 elif color == BLACK:
3552 curwnd.attron(curses.color_pair(curses.COLOR_BLACK))
3554 curwnd.attron(curses.color_pair(curses.COLOR_BLUE))
3555 elif color == GREEN:
3556 curwnd.attron(curses.color_pair(curses.COLOR_GREEN))
3558 curwnd.attron(curses.color_pair(curses.COLOR_CYAN))
3560 curwnd.attron(curses.color_pair(curses.COLOR_RED))
3561 elif color == MAGENTA:
3562 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA))
3563 elif color == BROWN:
3564 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW))
3565 elif color == LIGHTGRAY:
3566 curwnd.attron(curses.color_pair(curses.COLOR_WHITE))
3567 elif color == DARKGRAY:
3568 curwnd.attron(curses.color_pair(curses.COLOR_BLACK) | curses.A_BOLD)
3569 elif color == LIGHTBLUE:
3570 curwnd.attron(curses.color_pair(curses.COLOR_BLUE) | curses.A_BOLD)
3571 elif color == LIGHTGREEN:
3572 curwnd.attron(curses.color_pair(curses.COLOR_GREEN) | curses.A_BOLD)
3573 elif color == LIGHTCYAN:
3574 curwnd.attron(curses.color_pair(curses.COLOR_CYAN) | curses.A_BOLD)
3575 elif color == LIGHTRED:
3576 curwnd.attron(curses.color_pair(curses.COLOR_RED) | curses.A_BOLD)
3577 elif color == LIGHTMAGENTA:
3578 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA) | curses.A_BOLD)
3579 elif color == YELLOW:
3580 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW) | curses.A_BOLD)
3581 elif color == WHITE:
3582 curwnd.attron(curses.color_pair(curses.COLOR_WHITE) | curses.A_BOLD)
3585 if (game.options & OPTION_COLOR) and (game.options & OPTION_CURSES):
3586 curwnd.attron(curses.A_REVERSE)
3589 # Things past this point have policy implications.
3593 "Hook to be called after moving to redraw maps."
3594 if game.options & OPTION_CURSES:
3597 setwnd(srscan_window)
3601 setwnd(status_window)
3602 status_window.clear()
3603 status_window.move(0, 0)
3604 setwnd(report_window)
3605 report_window.clear()
3606 report_window.move(0, 0)
3608 setwnd(lrscan_window)
3609 lrscan_window.clear()
3610 lrscan_window.move(0, 0)
3611 lrscan(silent=False)
3613 def put_srscan_sym(w, sym):
3614 "Emit symbol for short-range scan."
3615 srscan_window.move(w.i+1, w.j*2+2)
3616 srscan_window.addch(sym)
3617 srscan_window.refresh()
3620 "Enemy fall down, go boom."
3621 if game.options & OPTION_CURSES:
3623 setwnd(srscan_window)
3624 srscan_window.attron(curses.A_REVERSE)
3625 put_srscan_sym(w, game.quad[w.i][w.j])
3629 srscan_window.attroff(curses.A_REVERSE)
3630 put_srscan_sym(w, game.quad[w.i][w.j])
3631 curses.delay_output(500)
3632 setwnd(message_window)
3635 "Sound and visual effects for teleportation."
3636 if game.options & OPTION_CURSES:
3638 setwnd(message_window)
3640 prouts(" . . . . . ")
3641 if game.options & OPTION_CURSES:
3642 #curses.delay_output(1000)
3646 def tracktorpedo(w, step, i, n, iquad):
3647 "Torpedo-track animation."
3648 if not game.options & OPTION_CURSES:
3652 proutn(_("Track for torpedo number %d- ") % (i+1))
3655 proutn(_("Torpedo track- "))
3656 elif step==4 or step==9:
3660 if not damaged(DSRSENS) or game.condition=="docked":
3661 if i != 0 and step == 1:
3664 if (iquad=='.') or (iquad==' '):
3665 put_srscan_sym(w, '+')
3669 put_srscan_sym(w, iquad)
3671 curwnd.attron(curses.A_REVERSE)
3672 put_srscan_sym(w, iquad)
3676 curwnd.attroff(curses.A_REVERSE)
3677 put_srscan_sym(w, iquad)
3682 "Display the current galaxy chart."
3683 if game.options & OPTION_CURSES:
3684 setwnd(message_window)
3685 message_window.clear()
3687 if game.options & OPTION_TTY:
3692 def prstat(txt, data):
3694 if game.options & OPTION_CURSES:
3696 setwnd(status_window)
3698 proutn(" " * (NSYM - len(txt)))
3701 if game.options & OPTION_CURSES:
3702 setwnd(report_window)
3704 # Code from moving.c begins here
3706 def imove(icourse=None, noattack=False):
3707 "Movement execution for warp, impulse, supernova, and tractor-beam events."
3710 def newquadrant(noattack):
3711 # Leaving quadrant -- allow final enemy attack
3712 # Don't set up attack if being pushed by nova or cloaked
3713 if len(game.enemies) != 0 and not noattack and not game.iscloaked:
3715 for enemy in game.enemies:
3716 finald = (w - enemy.location).distance()
3717 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3718 # Stas Sergeev added the condition
3719 # that attacks only happen if Klingons
3720 # are present and your skill is good.
3721 if game.skill > SKILL_GOOD and game.klhere > 0 and not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3722 attack(torps_ok=False)
3725 # check for edge of galaxy
3731 if icourse.final.i < 0:
3732 icourse.final.i = -icourse.final.i
3734 if icourse.final.j < 0:
3735 icourse.final.j = -icourse.final.j
3737 if icourse.final.i >= GALSIZE*QUADSIZE:
3738 icourse.final.i = (GALSIZE*QUADSIZE*2) - icourse.final.i
3740 if icourse.final.j >= GALSIZE*QUADSIZE:
3741 icourse.final.j = (GALSIZE*QUADSIZE*2) - icourse.final.j
3749 if game.nkinks == 3:
3750 # Three strikes -- you're out!
3754 prout(_("YOU HAVE ATTEMPTED TO CROSS THE NEGATIVE ENERGY BARRIER"))
3755 prout(_("AT THE EDGE OF THE GALAXY. THE THIRD TIME YOU TRY THIS,"))
3756 prout(_("YOU WILL BE DESTROYED."))
3757 # Compute final position in new quadrant
3758 if trbeam: # Don't bother if we are to be beamed
3760 game.quadrant = icourse.final.quadrant()
3761 game.sector = icourse.final.sector()
3763 prout(_("Entering Quadrant %s.") % game.quadrant)
3764 game.quad[game.sector.i][game.sector.j] = game.ship
3766 if game.skill>SKILL_NOVICE:
3767 attack(torps_ok=False)
3769 def check_collision(h):
3770 iquad = game.quad[h.i][h.j]
3772 # object encountered in flight path
3773 stopegy = 50.0*icourse.distance/game.optime
3774 if iquad in ('T', 'K', 'C', 'S', 'R', '?'):
3775 for enemy in game.enemies:
3776 if enemy.location == game.sector:
3777 collision(rammed=False, enemy=enemy)
3779 # This should not happen
3780 prout(_("Which way did he go?"))
3784 prouts(_("***RED ALERT! RED ALERT!"))
3786 proutn("***" + crmshp())
3787 proutn(_(" pulled into black hole at Sector %s") % h)
3788 # Getting pulled into a black hole was certain
3789 # death in Almy's original. Stas Sergeev added a
3790 # possibility that you'll get timewarped instead.
3792 for m in range(NDEVICES):
3793 if game.damage[m]>0:
3795 probf=math.pow(1.4,(game.energy+game.shield)/5000.0-1.0)*math.pow(1.3,1.0/(n+1)-1.0)
3796 if (game.options & OPTION_BLKHOLE) and withprob(1-probf):
3806 prout(_(" encounters Tholian web at %s;") % h)
3808 prout(_(" blocked by object at %s;") % h)
3809 proutn(_("Emergency stop required "))
3810 prout(_("%2d units of energy.") % int(stopegy))
3811 game.energy -= stopegy
3812 if game.energy <= 0:
3819 prout(_("Helmsman Sulu- \"Leaving standard orbit.\""))
3820 game.inorbit = False
3821 # If tractor beam is to occur, don't move full distance
3822 if game.state.date+game.optime >= scheduled(FTBEAM):
3824 # We can't be tractor beamed if cloaked,
3825 # so move the event into the future
3826 postpone(FTBEAM, game.optime + expran(1.5*game.intime/len(game.kcmdr)))
3830 game.condition = "red"
3831 icourse.distance = icourse.distance*(scheduled(FTBEAM)-game.state.date)/game.optime + 0.1
3832 game.optime = scheduled(FTBEAM) - game.state.date + 1e-5
3834 game.quad[game.sector.i][game.sector.j] = '.'
3835 for _m in range(icourse.moves):
3837 w = icourse.sector()
3838 if icourse.origin.quadrant() != icourse.location.quadrant():
3839 newquadrant(noattack)
3841 elif check_collision(w):
3842 print("Collision detected")
3846 # We're in destination quadrant -- compute new average enemy distances
3847 game.quad[game.sector.i][game.sector.j] = game.ship
3849 for enemy in game.enemies:
3850 finald = (w-enemy.location).distance()
3851 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3852 enemy.kdist = finald
3854 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3855 attack(torps_ok=False)
3856 for enemy in game.enemies:
3857 enemy.kavgd = enemy.kdist
3860 setwnd(message_window)
3864 "Dock our ship at a starbase."
3866 if game.condition == "docked" and verbose:
3867 prout(_("Already docked."))
3870 prout(_("You must first leave standard orbit."))
3872 if not game.base.is_valid() or abs(game.sector.i-game.base.i) > 1 or abs(game.sector.j-game.base.j) > 1:
3873 prout(crmshp() + _(" not adjacent to base."))
3876 prout(_("You cannot dock while cloaked."))
3878 game.condition = "docked"
3882 if game.energy < game.inenrg:
3883 game.energy = game.inenrg
3884 game.shield = game.inshld
3885 game.torps = game.intorps
3886 game.lsupres = game.inlsr
3887 game.state.crew = FULLCREW
3888 if game.brigcapacity-game.brigfree > 0:
3889 prout(_("%d captured Klingons transferred to base") % (game.brigcapacity-game.brigfree))
3890 game.kcaptured += game.brigcapacity-game.brigfree
3891 game.brigfree = game.brigcapacity
3892 if communicating() and \
3893 ((is_scheduled(FCDBAS) or game.isatb == 1) and not game.iseenit):
3894 # get attack report from base
3895 prout(_("Lt. Uhura- \"Captain, an important message from the starbase:\""))
3899 def cartesian(loc1=None, loc2=None):
3901 return game.quadrant * QUADSIZE + game.sector
3903 return game.quadrant * QUADSIZE + loc1
3905 return loc1 * QUADSIZE + loc2
3907 def getcourse(isprobe):
3908 "Get a course and distance from the user."
3910 dquad = copy.copy(game.quadrant)
3911 navmode = "unspecified"
3915 if game.landed and not isprobe:
3916 prout(_("Dummy! You can't leave standard orbit until you"))
3917 proutn(_("are back aboard the ship."))
3920 while navmode == "unspecified":
3921 if damaged(DNAVSYS):
3923 prout(_("Computer damaged; manual navigation only"))
3925 prout(_("Computer damaged; manual movement only"))
3930 key = scanner.nexttok()
3932 proutn(_("Manual or automatic- "))
3935 elif key == "IHALPHA":
3936 if scanner.sees("manual"):
3938 key = scanner.nexttok()
3940 elif scanner.sees("automatic"):
3941 navmode = "automatic"
3942 key = scanner.nexttok()
3950 prout(_("(Manual navigation assumed.)"))
3952 prout(_("(Manual movement assumed.)"))
3956 if navmode == "automatic":
3957 while key == "IHEOL":
3959 proutn(_("Target quadrant or quadrant§or- "))
3961 proutn(_("Destination sector or quadrant§or- "))
3964 key = scanner.nexttok()
3968 xi = int(round(scanner.real))-1
3969 key = scanner.nexttok()
3973 xj = int(round(scanner.real))-1
3974 key = scanner.nexttok()
3976 # both quadrant and sector specified
3977 xk = int(round(scanner.real))-1
3978 key = scanner.nexttok()
3982 xl = int(round(scanner.real))-1
3988 # only one pair of numbers was specified
3990 # only quadrant specified -- go to center of dest quad
3993 dsect.j = dsect.i = 4 # preserves 1-origin behavior
3995 # only sector specified
3999 if not dquad.valid_quadrant() or not dsect.valid_sector():
4006 prout(_("Helmsman Sulu- \"Course locked in for Sector %s.\"") % dsect)
4008 prout(_("Ensign Chekov- \"Course laid in, Captain.\""))
4009 # the actual deltas get computed here
4010 delta.j = dquad.j-game.quadrant.j + (dsect.j-game.sector.j)/(QUADSIZE*1.0)
4011 delta.i = game.quadrant.i-dquad.i + (game.sector.i-dsect.i)/(QUADSIZE*1.0)
4013 while key == "IHEOL":
4014 proutn(_("X and Y displacements- "))
4017 key = scanner.nexttok()
4020 delta.j = scanner.real
4024 key = scanner.nexttok()
4026 delta.i = scanner.real
4029 # Check for zero movement
4030 if delta.i == 0 and delta.j == 0:
4033 if itemp == "verbose" and not isprobe:
4035 prout(_("Helmsman Sulu- \"Aye, Sir.\""))
4037 return course(bearing=delta.bearing(), distance=delta.distance())
4040 def __init__(self, bearing, distance, origin=None):
4041 self.distance = distance
4042 self.bearing = bearing
4044 self.origin = cartesian(game.quadrant, game.sector)
4046 self.origin = origin
4047 # The bearing() code we inherited from FORTRAN is actually computing
4048 # clockface directions!
4049 if self.bearing < 0.0:
4050 self.bearing += 12.0
4051 self.angle = ((15.0 - self.bearing) * 0.5235988)
4052 self.increment = Coord(-math.sin(self.angle), math.cos(self.angle))
4053 bigger = max(abs(self.increment.i), abs(self.increment.j))
4054 self.increment /= bigger
4055 self.moves = int(round(10*self.distance*bigger))
4057 self.final = (self.location + self.moves*self.increment).roundtogrid()
4058 self.location = self.origin
4059 self.nextlocation = None
4061 self.location = self.origin
4064 return self.location.roundtogrid() == self.final
4066 "Next step on course."
4068 self.nextlocation = self.location + self.increment
4069 samequad = (self.location.quadrant() == self.nextlocation.quadrant())
4070 self.location = self.nextlocation
4073 return self.location.quadrant()
4075 return self.location.sector()
4077 return self.distance*(w**3)*(game.shldup+1)
4079 return 10.0*self.distance/w**2
4082 "Move under impulse power."
4084 if damaged(DIMPULS):
4087 prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
4089 if game.energy > 30.0:
4091 icourse = getcourse(isprobe=False)
4094 power = 20.0 + 100.0*icourse.distance
4097 if power >= game.energy:
4098 # Insufficient power for trip
4100 prout(_("First Officer Spock- \"Captain, the impulse engines"))
4101 prout(_("require 20.0 units to engage, plus 100.0 units per"))
4102 if game.energy > 30:
4103 proutn(_("quadrant. We can go, therefore, a maximum of %d") %
4104 int(0.01 * (game.energy-20.0)-0.05))
4105 prout(_(" quadrants.\""))
4107 prout(_("quadrant. They are, therefore, useless.\""))
4110 # Make sure enough time is left for the trip
4111 game.optime = icourse.distance/0.095
4112 if game.optime >= game.state.remtime:
4113 prout(_("First Officer Spock- \"Captain, our speed under impulse"))
4114 prout(_("power is only 0.95 sectors per stardate. Are you sure"))
4115 proutn(_("we dare spend the time?\" "))
4118 # Activate impulse engines and pay the cost
4119 imove(icourse, noattack=False)
4123 power = 20.0 + 100.0*icourse.distance
4124 game.energy -= power
4125 game.optime = icourse.distance/0.095
4126 if game.energy <= 0:
4130 def warp(wcourse, involuntary):
4131 "ove under warp drive."
4132 blooey = False; twarp = False
4133 if not involuntary: # Not WARPX entry
4138 prout(_("Engineer Scott- \"The warp engines can not be used while cloaked, Sir.\""))
4140 if game.damage[DWARPEN] > 10.0:
4143 prout(_("Engineer Scott- \"The warp engines are damaged, Sir.\""))
4145 if damaged(DWARPEN) and game.warpfac > 4.0:
4148 prout(_("Engineer Scott- \"Sorry, Captain. Until this damage"))
4149 prout(_(" is repaired, I can only give you warp 4.\""))
4151 # Read in course and distance
4154 wcourse = getcourse(isprobe=False)
4157 # Make sure starship has enough energy for the trip
4158 # Note: this formula is slightly different from the C version,
4159 # and lets you skate a bit closer to the edge.
4160 if wcourse.power(game.warpfac) >= game.energy:
4161 # Insufficient power for trip
4164 prout(_("Engineering to bridge--"))
4165 if not game.shldup or 0.5*wcourse.power(game.warpfac) > game.energy:
4166 iwarp = (game.energy/(wcourse.distance+0.05)) ** 0.333333333
4168 prout(_("We can't do it, Captain. We don't have enough energy."))
4170 proutn(_("We don't have enough energy, but we could do it at warp %d") % iwarp)
4173 prout(_("if you'll lower the shields."))
4177 prout(_("We haven't the energy to go that far with the shields up."))
4179 # Make sure enough time is left for the trip
4180 game.optime = wcourse.time(game.warpfac)
4181 if game.optime >= 0.8*game.state.remtime:
4183 prout(_("First Officer Spock- \"Captain, I compute that such"))
4184 proutn(_(" a trip would require approximately %2.0f") %
4185 (100.0*game.optime/game.state.remtime))
4186 prout(_(" percent of our"))
4187 proutn(_(" remaining time. Are you sure this is wise?\" "))
4193 if game.warpfac > 6.0:
4194 # Decide if engine damage will occur
4195 # ESR: Seems wrong. Probability of damage goes *down* with distance?
4196 prob = wcourse.distance*(6.0-game.warpfac)**2/66.666666666
4197 if prob > randreal():
4199 wcourse.distance = randreal(wcourse.distance)
4200 # Decide if time warp will occur
4201 if 0.5*wcourse.distance*math.pow(7.0,game.warpfac-10.0) > randreal():
4203 if game.idebug and game.warpfac==10 and not twarp:
4205 proutn("=== Force time warp? ")
4209 # If time warp or engine damage, check path
4210 # If it is obstructed, don't do warp or damage
4211 look = wcourse.moves
4215 w = wcourse.sector()
4216 if not w.valid_sector():
4218 if game.quad[w.i][w.j] != '.':
4222 # Activate Warp Engines and pay the cost
4223 imove(wcourse, noattack=False)
4226 game.energy -= wcourse.power(game.warpfac)
4227 if game.energy <= 0:
4229 game.optime = wcourse.time(game.warpfac)
4233 game.damage[DWARPEN] = game.damfac * randreal(1.0, 4.0)
4235 prout(_("Engineering to bridge--"))
4236 prout(_(" Scott here. The warp engines are damaged."))
4237 prout(_(" We'll have to reduce speed to warp 4."))
4242 "Change the warp factor."
4244 key=scanner.nexttok()
4248 proutn(_("Warp factor- "))
4252 if game.damage[DWARPEN] > 10.0:
4253 prout(_("Warp engines inoperative."))
4255 if damaged(DWARPEN) and scanner.real > 4.0:
4256 prout(_("Engineer Scott- \"I'm doing my best, Captain,"))
4257 prout(_(" but right now we can only go warp 4.\""))
4259 if scanner.real > 10.0:
4260 prout(_("Helmsman Sulu- \"Our top speed is warp 10, Captain.\""))
4262 if scanner.real < 1.0:
4263 prout(_("Helmsman Sulu- \"We can't go below warp 1, Captain.\""))
4265 oldfac = game.warpfac
4266 game.warpfac = scanner.real
4267 if game.warpfac <= oldfac or game.warpfac <= 6.0:
4268 prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\"") %
4271 if game.warpfac < 8.00:
4272 prout(_("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\""))
4274 if game.warpfac == 10.0:
4275 prout(_("Engineer Scott- \"Aye, Captain, we'll try it.\""))
4277 prout(_("Engineer Scott- \"Aye, Captain, but our engines may not take it.\""))
4281 "Cope with being tossed out of quadrant by supernova or yanked by beam."
4283 # is captain on planet?
4285 if damaged(DTRANSP):
4288 prout(_("Scotty rushes to the transporter controls."))
4290 prout(_("But with the shields up it's hopeless."))
4292 prouts(_("His desperate attempt to rescue you . . ."))
4297 prout(_("SUCCEEDS!"))
4300 proutn(_("The crystals mined were "))
4308 # Check to see if captain in shuttle craft
4313 # Inform captain of attempt to reach safety
4317 prouts(_("***RED ALERT! RED ALERT!"))
4319 proutn(_("The %s has stopped in a quadrant containing") % crmshp())
4320 prouts(_(" a supernova."))
4322 prout(_("***Emergency automatic override attempts to hurl ")+crmshp())
4323 prout(_("safely out of quadrant."))
4324 if not damaged(DRADIO):
4325 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
4326 # Try to use warp engines
4327 if damaged(DWARPEN):
4329 prout(_("Warp engines damaged."))
4332 game.warpfac = randreal(6.0, 8.0)
4333 prout(_("Warp factor set to %d") % int(game.warpfac))
4334 power = 0.75*game.energy
4335 dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1))
4336 dist = max(dist, randreal(math.sqrt(2)))
4337 bugout = course(bearing=randreal(12), distance=dist) # How dumb!
4338 game.optime = bugout.time(game.warpfac)
4340 game.inorbit = False
4341 warp(bugout, involuntary=True)
4343 # This is bad news, we didn't leave quadrant.
4347 prout(_("Insufficient energy to leave quadrant."))
4350 # Repeat if another snova
4351 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
4354 finish(FWON) # Snova killed remaining enemy.
4357 "Let's do the time warp again."
4358 prout(_("***TIME WARP ENTERED."))
4359 if game.state.snap and withprob(0.5):
4361 prout(_("You are traveling backwards in time %d stardates.") %
4362 int(game.state.date-game.snapsht.date))
4363 game.state = game.snapsht
4364 game.state.snap = False
4365 if len(game.state.kcmdr):
4366 schedule(FTBEAM, expran(game.intime/len(game.state.kcmdr)))
4367 schedule(FBATTAK, expran(0.3*game.intime))
4368 schedule(FSNOVA, expran(0.5*game.intime))
4369 # next snapshot will be sooner
4370 schedule(FSNAP, expran(0.25*game.state.remtime))
4372 if game.state.nscrem:
4373 schedule(FSCMOVE, 0.2777)
4377 game.battle.invalidate()
4378 # Make sure Galileo is consistant -- Snapshot may have been taken
4379 # when on planet, which would give us two Galileos!
4381 for l in range(game.inplan):
4382 if game.state.planets[l].known == "shuttle_down":
4384 if game.iscraft == "onship" and game.ship=='E':
4385 prout(_("Chekov- \"Security reports the Galileo has disappeared, Sir!"))
4386 game.iscraft = "offship"
4387 # Likewise, if in the original time the Galileo was abandoned, but
4388 # was on ship earlier, it would have vanished -- let's restore it.
4389 if game.iscraft == "offship" and not gotit and game.damage[DSHUTTL] >= 0.0:
4390 prout(_("Chekov- \"Security reports the Galileo has reappeared in the dock!\""))
4391 game.iscraft = "onship"
4392 # There used to be code to do the actual reconstrction here,
4393 # but the starchart is now part of the snapshotted galaxy state.
4394 prout(_("Spock has reconstructed a correct star chart from memory"))
4396 # Go forward in time
4397 game.optime = expran(0.5*game.intime)
4398 prout(_("You are traveling forward in time %d stardates.") % int(game.optime))
4399 # cheat to make sure no tractor beams occur during time warp
4400 postpone(FTBEAM, game.optime)
4401 game.damage[DRADIO] += game.optime
4403 events() # Stas Sergeev added this -- do pending events
4406 "Launch deep-space probe."
4407 # New code to launch a deep space probe
4408 if game.nprobes == 0:
4411 if game.ship == 'E':
4412 prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\""))
4414 prout(_("Ye Faerie Queene has no deep space probes."))
4419 prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\""))
4421 if is_scheduled(FDSPROB):
4424 if damaged(DRADIO) and game.condition != "docked":
4425 prout(_("Spock- \"Records show the previous probe has not yet"))
4426 prout(_(" reached its destination.\""))
4428 prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""))
4430 key = scanner.nexttok()
4432 if game.nprobes == 1:
4433 prout(_("1 probe left."))
4435 prout(_("%d probes left") % game.nprobes)
4436 proutn(_("Are you sure you want to fire a probe? "))
4439 game.isarmed = False
4440 if key == "IHALPHA" and scanner.token == "armed":
4442 key = scanner.nexttok()
4443 elif key == "IHEOL":
4444 proutn(_("Arm NOVAMAX warhead? "))
4446 elif key == "IHREAL": # first element of course
4447 scanner.push(scanner.token)
4449 game.probe = getcourse(isprobe=True)
4453 schedule(FDSPROB, 0.01) # Time to move one sector
4454 prout(_("Ensign Chekov- \"The deep space probe is launched, Captain.\""))
4459 "Yell for help from nearest starbase."
4460 # There's more than one way to move in this game!
4462 # Test for conditions which prevent calling for help
4463 if game.condition == "docked":
4464 prout(_("Lt. Uhura- \"But Captain, we're already docked.\""))
4467 prout(_("Subspace radio damaged."))
4469 if not game.state.baseq:
4470 prout(_("Lt. Uhura- \"Captain, I'm not getting any response from Starbase.\""))
4473 prout(_("You must be aboard the %s.") % crmshp())
4475 # OK -- call for help from nearest starbase
4478 # There's one in this quadrant
4479 ddist = (game.base - game.sector).distance()
4481 ibq = None # Force base-quadrant game to persist past loop
4483 for ibq in game.state.baseq:
4484 xdist = QUADSIZE * (ibq - game.quadrant).distance()
4488 prout(_("No starbases remain. You are alone in a hostile galaxy."))
4490 # Since starbase not in quadrant, set up new quadrant
4493 # dematerialize starship
4494 game.quad[game.sector.i][game.sector.j]='.'
4495 proutn(_("Starbase in Quadrant %s responds--%s dematerializes") \
4496 % (game.quadrant, crmshp()))
4497 game.sector.invalidate()
4498 for m in range(1, 5+1):
4499 w = game.base.scatter()
4500 if w.valid_sector() and game.quad[w.i][w.j]=='.':
4501 # found one -- finish up
4504 if not game.sector.is_valid():
4505 prout(_("You have been lost in space..."))
4506 finish(FMATERIALIZE)
4508 # Give starbase three chances to rematerialize starship
4509 probf = math.pow((1.0 - math.pow(0.98,ddist)), 0.33333333)
4510 for m in range(1, 3+1):
4511 if m == 1: proutn(_("1st"))
4512 elif m == 2: proutn(_("2nd"))
4513 elif m == 3: proutn(_("3rd"))
4514 proutn(_(" attempt to re-materialize ") + crmshp())
4515 game.quad[game.sector.i][game.sector.j]=('-','o','O')[m-1]
4518 if randreal() > probf:
4522 curses.delay_output(500)
4524 game.quad[game.sector.i][game.sector.j]='?'
4527 setwnd(message_window)
4528 finish(FMATERIALIZE)
4530 game.quad[game.sector.i][game.sector.j]=game.ship
4532 prout(_("succeeds."))
4536 prout(_("Lt. Uhura- \"Captain, we made it!\""))
4541 if game.condition=="docked":
4543 prout(_("You cannot abandon Ye Faerie Queene."))
4546 # Must take shuttle craft to exit
4547 if game.damage[DSHUTTL]==-1:
4548 prout(_("Ye Faerie Queene has no shuttle craft."))
4550 if game.damage[DSHUTTL]<0:
4551 prout(_("Shuttle craft now serving Big Macs."))
4553 if game.damage[DSHUTTL]>0:
4554 prout(_("Shuttle craft damaged."))
4557 prout(_("You must be aboard the ship."))
4559 if game.iscraft != "onship":
4560 prout(_("Shuttle craft not currently available."))
4562 # Emit abandon ship messages
4564 prouts(_("***ABANDON SHIP! ABANDON SHIP!"))
4566 prouts(_("***ALL HANDS ABANDON SHIP!"))
4568 prout(_("Captain and crew escape in shuttle craft."))
4569 if not game.state.baseq:
4570 # Oops! no place to go...
4573 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
4575 if not (game.options & OPTION_WORLDS) and not damaged(DTRANSP):
4576 prout(_("Remainder of ship's complement beam down"))
4577 prout(_("to nearest habitable planet."))
4578 elif q.planet != None and not damaged(DTRANSP):
4579 prout(_("Remainder of ship's complement beam down to %s.") %
4582 prout(_("Entire crew of %d left to die in outer space.") %
4584 game.casual += game.state.crew
4585 game.abandoned += game.state.crew
4586 # If at least one base left, give 'em the Faerie Queene
4588 game.icrystl = False # crystals are lost
4589 game.nprobes = 0 # No probes
4590 prout(_("You are captured by Klingons and released to"))
4591 prout(_("the Federation in a prisoner-of-war exchange."))
4592 nb = randrange(len(game.state.baseq))
4593 # Set up quadrant and position FQ adjacient to base
4594 if not game.quadrant == game.state.baseq[nb]:
4595 game.quadrant = game.state.baseq[nb]
4596 game.sector.i = game.sector.j = 5
4599 # position next to base by trial and error
4600 game.quad[game.sector.i][game.sector.j] = '.'
4602 for l in range(QUADSIZE):
4603 game.sector = game.base.scatter()
4604 if game.sector.valid_sector() and \
4605 game.quad[game.sector.i][game.sector.j] == '.':
4608 break # found a spot
4609 game.sector.i=QUADSIZE/2
4610 game.sector.j=QUADSIZE/2
4612 # Get new commission
4613 game.quad[game.sector.i][game.sector.j] = game.ship = 'F'
4614 game.state.crew = FULLCREW
4615 prout(_("Starfleet puts you in command of another ship,"))
4616 prout(_("the Faerie Queene, which is antiquated but,"))
4617 prout(_("still useable."))
4619 prout(_("The dilithium crystals have been moved."))
4621 game.iscraft = "offship" # Galileo disappears
4623 game.condition="docked"
4624 for l in range(NDEVICES):
4625 game.damage[l] = 0.0
4626 game.damage[DSHUTTL] = -1
4627 game.energy = game.inenrg = 3000.0
4628 game.shield = game.inshld = 1250.0
4629 game.torps = game.intorps = 6
4630 game.lsupres=game.inlsr=3.0
4633 game.brigfree = game.brigcapacity = 300
4636 # Code from planets.c begins here.
4639 "Abort a lengthy operation if an event interrupts it."
4642 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.justin:
4647 "Report on (uninhabited) planets in the galaxy."
4651 prout(_("Spock- \"Planet report follows, Captain.\""))
4653 for i in range(game.inplan):
4654 if game.state.planets[i].pclass == "destroyed":
4656 if (game.state.planets[i].known != "unknown" \
4657 and not game.state.planets[i].inhabited) \
4660 if game.idebug and game.state.planets[i].known=="unknown":
4661 proutn("(Unknown) ")
4662 proutn(_("Quadrant %s") % game.state.planets[i].quadrant)
4663 proutn(_(" class "))
4664 proutn(game.state.planets[i].pclass)
4666 if game.state.planets[i].crystals != "present":
4668 prout(_("dilithium crystals present."))
4669 if game.state.planets[i].known=="shuttle_down":
4670 prout(_(" Shuttle Craft Galileo on surface."))
4672 prout(_("No information available."))
4675 "Enter standard orbit."
4679 prout(_("Already in standard orbit."))
4681 if damaged(DWARPEN) and damaged(DIMPULS):
4682 prout(_("Both warp and impulse engines damaged."))
4684 if not game.plnet.is_valid():
4685 prout("There is no planet in this sector.")
4687 if abs(game.sector.i-game.plnet.i)>1 or abs(game.sector.j-game.plnet.j)>1:
4688 prout(crmshp() + _(" not adjacent to planet."))
4691 game.optime = randreal(0.02, 0.05)
4692 prout(_("Helmsman Sulu- \"Entering standard orbit, Sir.\""))
4696 game.height = randreal(1400, 8600)
4697 prout(_("Sulu- \"Entered orbit at altitude %.2f kilometers.\"") % game.height)
4702 "Examine planets in this quadrant."
4703 if damaged(DSRSENS):
4704 if game.options & OPTION_TTY:
4705 prout(_("Short range sensors damaged."))
4707 if game.iplnet is None:
4708 if game.options & OPTION_TTY:
4709 prout(_("Spock- \"No planet in this quadrant, Captain.\""))
4711 if game.iplnet.known == "unknown":
4712 prout(_("Spock- \"Sensor scan for Quadrant %s-") % game.quadrant)
4714 prout(_(" Planet at Sector %s is of class %s.") %
4715 (game.plnet, game.iplnet.pclass))
4716 if game.iplnet.known=="shuttle_down":
4717 prout(_(" Sensors show Galileo still on surface."))
4718 proutn(_(" Readings indicate"))
4719 if game.iplnet.crystals != "present":
4721 prout(_(" dilithium crystals present.\""))
4722 if game.iplnet.known == "unknown":
4723 game.iplnet.known = "known"
4724 elif game.iplnet.inhabited:
4725 prout(_("Spock- \"The inhabited planet %s ") % game.iplnet.name)
4726 prout(_(" is located at Sector %s, Captain.\"") % game.plnet)
4729 "Use the transporter."
4733 if damaged(DTRANSP):
4734 prout(_("Transporter damaged."))
4735 if not damaged(DSHUTTL) and (game.iplnet.known=="shuttle_down" or game.iscraft == "onship"):
4737 proutn(_("Spock- \"May I suggest the shuttle craft, Sir?\" "))
4741 if not game.inorbit:
4742 prout(crmshp() + _(" not in standard orbit."))
4745 prout(_("Impossible to transport through shields."))
4747 if game.iplnet.known=="unknown":
4748 prout(_("Spock- \"Captain, we have no information on this planet"))
4749 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4750 prout(_(" you may not go down.\""))
4752 if not game.landed and game.iplnet.crystals=="absent":
4753 prout(_("Spock- \"Captain, I fail to see the logic in"))
4754 prout(_(" exploring a planet with no dilithium crystals."))
4755 proutn(_(" Are you sure this is wise?\" "))
4759 if not (game.options & OPTION_PLAIN):
4760 nrgneed = 50 * game.skill + game.height / 100.0
4761 if nrgneed > game.energy:
4762 prout(_("Engineering to bridge--"))
4763 prout(_(" Captain, we don't have enough energy for transportation."))
4765 if not game.landed and nrgneed * 2 > game.energy:
4766 prout(_("Engineering to bridge--"))
4767 prout(_(" Captain, we have enough energy only to transport you down to"))
4768 prout(_(" the planet, but there wouldn't be an energy for the trip back."))
4769 if game.iplnet.known == "shuttle_down":
4770 prout(_(" Although the Galileo shuttle craft may still be on a surface."))
4771 proutn(_(" Are you sure this is wise?\" "))
4776 # Coming from planet
4777 if game.iplnet.known=="shuttle_down":
4778 proutn(_("Spock- \"Wouldn't you rather take the Galileo?\" "))
4782 prout(_("Your crew hides the Galileo to prevent capture by aliens."))
4783 prout(_("Landing party assembled, ready to beam up."))
4785 prout(_("Kirk whips out communicator..."))
4786 prouts(_("BEEP BEEP BEEP"))
4788 prout(_("\"Kirk to enterprise- Lock on coordinates...energize.\""))
4791 prout(_("Scotty- \"Transporter room ready, Sir.\""))
4793 prout(_("Kirk and landing party prepare to beam down to planet surface."))
4795 prout(_("Kirk- \"Energize.\""))
4798 prouts("WWHOOOIIIIIRRRRREEEE.E.E. . . . . . .")
4800 if not withprob(0.98):
4801 prouts("BOOOIIIOOOIIOOOOIIIOIING . . .")
4803 prout(_("Scotty- \"Oh my God! I've lost them.\""))
4806 prouts(". . . . . . .E.E.EEEERRRRRIIIIIOOOHWW")
4807 game.landed = not game.landed
4808 game.energy -= nrgneed
4810 prout(_("Transport complete."))
4811 if game.landed and game.iplnet.known=="shuttle_down":
4812 prout(_("The shuttle craft Galileo is here!"))
4813 if not game.landed and game.imine:
4820 "Strip-mine a world for dilithium."
4824 prout(_("Mining party not on planet."))
4826 if game.iplnet.crystals == "mined":
4827 prout(_("This planet has already been strip-mined for dilithium."))
4829 elif game.iplnet.crystals == "absent":
4830 prout(_("No dilithium crystals on this planet."))
4833 prout(_("You've already mined enough crystals for this trip."))
4835 if game.icrystl and game.cryprob == 0.05:
4836 prout(_("With all those fresh crystals aboard the ") + crmshp())
4837 prout(_("there's no reason to mine more at this time."))
4839 game.optime = randreal(0.1, 0.3)*(ord(game.iplnet.pclass)-ord("L"))
4842 prout(_("Mining operation complete."))
4843 game.iplnet.crystals = "mined"
4844 game.imine = game.ididit = True
4847 "Use dilithium crystals."
4851 if not game.icrystl:
4852 prout(_("No dilithium crystals available."))
4854 if game.energy >= 1000:
4855 prout(_("Spock- \"Captain, Starfleet Regulations prohibit such an operation"))
4856 prout(_(" except when Condition Yellow exists."))
4858 prout(_("Spock- \"Captain, I must warn you that loading"))
4859 prout(_(" raw dilithium crystals into the ship's power"))
4860 prout(_(" system may risk a severe explosion."))
4861 proutn(_(" Are you sure this is wise?\" "))
4866 prout(_("Engineering Officer Scott- \"(GULP) Aye Sir."))
4867 prout(_(" Mr. Spock and I will try it.\""))
4869 prout(_("Spock- \"Crystals in place, Sir."))
4870 prout(_(" Ready to activate circuit.\""))
4872 prouts(_("Scotty- \"Keep your fingers crossed, Sir!\""))
4874 if withprob(game.cryprob):
4875 prouts(_(" \"Activating now! - - No good! It's***"))
4877 prouts(_("***RED ALERT! RED A*L********************************"))
4880 prouts(_("****************** KA-BOOM!!!! *******************"))
4884 game.energy += randreal(5000.0, 5500.0)
4885 prouts(_(" \"Activating now! - - "))
4886 prout(_("The instruments"))
4887 prout(_(" are going crazy, but I think it's"))
4888 prout(_(" going to work!! Congratulations, Sir!\""))
4893 "Use shuttlecraft for planetary jaunt."
4896 if damaged(DSHUTTL):
4897 if game.damage[DSHUTTL] == -1.0:
4898 if game.inorbit and game.iplnet.known == "shuttle_down":
4899 prout(_("Ye Faerie Queene has no shuttle craft bay to dock it at."))
4901 prout(_("Ye Faerie Queene had no shuttle craft."))
4902 elif game.damage[DSHUTTL] > 0:
4903 prout(_("The Galileo is damaged."))
4904 else: # game.damage[DSHUTTL] < 0
4905 prout(_("Shuttle craft is now serving Big Macs."))
4907 if not game.inorbit:
4908 prout(crmshp() + _(" not in standard orbit."))
4910 if (game.iplnet.known != "shuttle_down") and game.iscraft != "onship":
4911 prout(_("Shuttle craft not currently available."))
4913 if not game.landed and game.iplnet.known=="shuttle_down":
4914 prout(_("You will have to beam down to retrieve the shuttle craft."))
4916 if game.shldup or game.condition == "docked":
4917 prout(_("Shuttle craft cannot pass through shields."))
4919 if game.iplnet.known=="unknown":
4920 prout(_("Spock- \"Captain, we have no information on this planet"))
4921 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4922 prout(_(" you may not fly down.\""))
4924 game.optime = 3.0e-5*game.height
4925 if game.optime >= 0.8*game.state.remtime:
4926 prout(_("First Officer Spock- \"Captain, I compute that such"))
4927 proutn(_(" a maneuver would require approximately %2d%% of our") % \
4928 int(100*game.optime/game.state.remtime))
4929 prout(_("remaining time."))
4930 proutn(_("Are you sure this is wise?\" "))
4936 if game.iscraft == "onship":
4938 if not damaged(DTRANSP):
4939 proutn(_("Spock- \"Would you rather use the transporter?\" "))
4943 proutn(_("Shuttle crew"))
4945 proutn(_("Rescue party"))
4946 prout(_(" boards Galileo and swoops toward planet surface."))
4947 game.iscraft = "offship"
4951 game.iplnet.known="shuttle_down"
4952 prout(_("Trip complete."))
4955 # Ready to go back to ship
4956 prout(_("You and your mining party board the"))
4957 prout(_("shuttle craft for the trip back to the Enterprise."))
4959 prouts(_("The short hop begins . . ."))
4961 game.iplnet.known="known"
4967 game.iscraft = "onship"
4973 prout(_("Trip complete."))
4976 # Kirk on ship and so is Galileo
4977 prout(_("Mining party assembles in the hangar deck,"))
4978 prout(_("ready to board the shuttle craft \"Galileo\"."))
4980 prouts(_("The hangar doors open; the trip begins."))
4983 game.iscraft = "offship"
4986 game.iplnet.known = "shuttle_down"
4989 prout(_("Trip complete."))
4993 "Use the big zapper."
4997 if game.ship != 'E':
4998 prout(_("Ye Faerie Queene has no death ray."))
5000 if len(game.enemies)==0:
5001 prout(_("Sulu- \"But Sir, there are no enemies in this quadrant.\""))
5004 prout(_("Death Ray is damaged."))
5006 prout(_("Spock- \"Captain, the 'Experimental Death Ray'"))
5007 prout(_(" is highly unpredictible. Considering the alternatives,"))
5008 proutn(_(" are you sure this is wise?\" "))
5011 prout(_("Spock- \"Acknowledged.\""))
5014 prouts(_("WHOOEE ... WHOOEE ... WHOOEE ... WHOOEE"))
5016 prout(_("Crew scrambles in emergency preparation."))
5017 prout(_("Spock and Scotty ready the death ray and"))
5018 prout(_("prepare to channel all ship's power to the device."))
5020 prout(_("Spock- \"Preparations complete, sir.\""))
5021 prout(_("Kirk- \"Engage!\""))
5023 prouts(_("WHIRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"))
5026 if game.options & OPTION_PLAIN:
5030 prouts(_("Sulu- \"Captain! It's working!\""))
5032 while len(game.enemies) > 0:
5033 deadkl(game.enemies[1].location, game.quad[game.enemies[1].location.i][game.enemies[1].location.j],game.enemies[1].location)
5034 prout(_("Ensign Chekov- \"Congratulations, Captain!\""))
5035 if game.unwon() == 0:
5037 if (game.options & OPTION_PLAIN) == 0:
5038 prout(_("Spock- \"Captain, I believe the `Experimental Death Ray'"))
5040 prout(_(" is still operational.\""))
5042 prout(_(" has been rendered nonfunctional.\""))
5043 game.damage[DDRAY] = 39.95
5045 r = randreal() # Pick failure method
5047 prouts(_("Sulu- \"Captain! It's working!\""))
5049 prouts(_("***RED ALERT! RED ALERT!"))
5051 prout(_("***MATTER-ANTIMATTER IMPLOSION IMMINENT!"))
5053 prouts(_("***RED ALERT! RED A*L********************************"))
5056 prouts(_("****************** KA-BOOM!!!! *******************"))
5061 prouts(_("Sulu- \"Captain! Yagabandaghangrapl, brachriigringlanbla!\""))
5063 prout(_("Lt. Uhura- \"Graaeek! Graaeek!\""))
5065 prout(_("Spock- \"Fascinating! . . . All humans aboard"))
5066 prout(_(" have apparently been transformed into strange mutations."))
5067 prout(_(" Vulcans do not seem to be affected."))
5069 prout(_("Kirk- \"Raauch! Raauch!\""))
5073 prouts(_("Sulu- \"Captain! It's --WHAT?!?!\""))
5075 proutn(_("Spock- \"I believe the word is"))
5076 prouts(_(" *ASTONISHING*"))
5077 prout(_(" Mr. Sulu."))
5078 for i in range(QUADSIZE):
5079 for j in range(QUADSIZE):
5080 if game.quad[i][j] == '.':
5081 game.quad[i][j] = '?'
5082 prout(_(" Captain, our quadrant is now infested with"))
5083 prouts(_(" - - - - - - *THINGS*."))
5085 prout(_(" I have no logical explanation.\""))
5087 prouts(_("Sulu- \"Captain! The Death Ray is creating tribbles!\""))
5089 prout(_("Scotty- \"There are so many tribbles down here"))
5090 prout(_(" in Engineering, we can't move for 'em, Captain.\""))
5094 # Code from reports.c begins here
5096 def attackreport(curt):
5097 "eport status of bases under attack."
5099 if is_scheduled(FCDBAS):
5100 prout(_("Starbase in Quadrant %s is currently under Commander attack.") % game.battle)
5101 prout(_("It can hold out until Stardate %d.") % int(scheduled(FCDBAS)))
5102 elif game.isatb == 1:
5103 prout(_("Starbase in Quadrant %s is under Super-commander attack.") % game.state.kscmdr)
5104 prout(_("It can hold out until Stardate %d.") % int(scheduled(FSCDBAS)))
5106 prout(_("No Starbase is currently under attack."))
5108 if is_scheduled(FCDBAS):
5109 proutn(_("Base in %s attacked by C. Alive until %.1f") % (game.battle, scheduled(FCDBAS)))
5111 proutn(_("Base in %s attacked by S. Alive until %.1f") % (game.state.kscmdr, scheduled(FSCDBAS)))
5115 # report on general game status
5117 s1 = (game.thawed and _("thawed ")) or ""
5118 s2 = {1:"short", 2:"medium", 4:"long"}[game.length]
5119 s3 = (None, _("novice"), _("fair"),
5120 _("good"), _("expert"), _("emeritus"))[game.skill]
5121 prout(_("You %s a %s%s %s game.") % ((_("were playing"), _("are playing"))[game.alldone], s1, s2, s3))
5122 if game.skill>SKILL_GOOD and game.thawed and not game.alldone:
5123 prout(_("No plaque is allowed."))
5125 prout(_("This is tournament game %d.") % game.tourn)
5126 prout(_("Your secret password is \"%s\"") % game.passwd)
5127 proutn(_("%d of %d Klingons have been killed") % (((game.inkling + game.incom + game.inscom) - game.unwon()),
5128 (game.inkling + game.incom + game.inscom)))
5129 if game.incom - len(game.state.kcmdr):
5130 prout(_(", including %d Commander%s.") % (game.incom - len(game.state.kcmdr), (_("s"), "")[(game.incom - len(game.state.kcmdr))==1]))
5131 elif game.inkling - game.state.remkl + (game.inscom - game.state.nscrem) > 0:
5132 prout(_(", but no Commanders."))
5135 if game.skill > SKILL_FAIR:
5136 prout(_("The Super Commander has %sbeen destroyed.") % ("", _("not "))[game.state.nscrem])
5137 if len(game.state.baseq) != game.inbase:
5139 if game.inbase-len(game.state.baseq)==1:
5140 proutn(_("has been 1 base"))
5142 proutn(_("have been %d bases") % (game.inbase-len(game.state.baseq)))
5143 prout(_(" destroyed, %d remaining.") % len(game.state.baseq))
5145 prout(_("There are %d bases.") % game.inbase)
5146 if communicating() or game.iseenit:
5147 # Don't report this if not seen and
5148 # either the radio is dead or not at base!
5152 prout(_("%d casualt%s suffered so far.") % (game.casual, ("y", "ies")[game.casual!=1]))
5153 if game.brigcapacity != game.brigfree:
5154 embriggened = brigcapacity-brigfree
5155 if embriggened == 1:
5156 prout(_("1 Klingon in brig"))
5158 prout(_("%d Klingons in brig.") % embriggened)
5159 if game.kcaptured == 0:
5161 elif game.kcaptured == 1:
5162 prout(_("1 captured Klingon turned in to Starfleet."))
5164 prout(_("%d captured Klingons turned in to Star Fleet.") % game.kcaptured)
5166 prout(_("There were %d call%s for help.") % (game.nhelp, ("" , _("s"))[game.nhelp!=1]))
5167 if game.ship == 'E':
5168 proutn(_("You have "))
5170 proutn("%d" % (game.nprobes))
5173 proutn(_(" deep space probe"))
5177 if communicating() and is_scheduled(FDSPROB):
5179 proutn(_("An armed deep space probe is in "))
5181 proutn(_("A deep space probe is in "))
5182 prout("Quadrant %s." % game.probe.quadrant())
5184 if game.cryprob <= .05:
5185 prout(_("Dilithium crystals aboard ship... not yet used."))
5189 while game.cryprob > ai:
5192 prout(_("Dilithium crystals have been used %d time%s.") % \
5193 (i, (_("s"), "")[i==1]))
5197 "Long-range sensor scan."
5198 if damaged(DLRSENS):
5199 # Now allow base's sensors if docked
5200 if game.condition != "docked":
5202 prout(_("LONG-RANGE SENSORS DAMAGED."))
5205 prout(_("Starbase's long-range scan"))
5207 prout(_("Long-range scan"))
5208 for x in range(game.quadrant.i-1, game.quadrant.i+2):
5211 for y in range(game.quadrant.j-1, game.quadrant.j+2):
5212 if not Coord(x, y).valid_quadrant():
5216 if not damaged(DRADIO):
5217 game.state.galaxy[x][y].charted = True
5218 game.state.chart[x][y].klingons = game.state.galaxy[x][y].klingons
5219 game.state.chart[x][y].starbase = game.state.galaxy[x][y].starbase
5220 game.state.chart[x][y].stars = game.state.galaxy[x][y].stars
5221 if not silent and game.state.galaxy[x][y].supernova:
5224 proutn(" %3d" % (game.state.chart[x][y].klingons*100 + game.state.chart[x][y].starbase * 10 + game.state.chart[x][y].stars))
5232 for i in range(NDEVICES):
5235 prout(_("\tDEVICE\t\t\t-REPAIR TIMES-"))
5236 prout(_("\t\t\tIN FLIGHT\t\tDOCKED"))
5238 prout(" %-26s\t%8.2f\t\t%8.2f" % (device[i],
5239 game.damage[i]+0.05,
5240 DOCKFAC*game.damage[i]+0.005))
5242 prout(_("All devices functional."))
5245 "Update the chart in the Enterprise's computer from galaxy data."
5246 game.lastchart = game.state.date
5247 for i in range(GALSIZE):
5248 for j in range(GALSIZE):
5249 if game.state.galaxy[i][j].charted:
5250 game.state.chart[i][j].klingons = game.state.galaxy[i][j].klingons
5251 game.state.chart[i][j].starbase = game.state.galaxy[i][j].starbase
5252 game.state.chart[i][j].stars = game.state.galaxy[i][j].stars
5255 "Display the star chart."
5257 if (game.options & OPTION_AUTOSCAN):
5261 if game.lastchart < game.state.date and game.condition == "docked":
5262 prout(_("Spock- \"I revised the Star Chart from the starbase's records.\""))
5264 prout(_(" STAR CHART FOR THE KNOWN GALAXY"))
5265 if game.state.date > game.lastchart:
5266 prout(_("(Last surveillance update %d stardates ago).") % ((int)(game.state.date-game.lastchart)))
5267 prout(" 1 2 3 4 5 6 7 8")
5268 for i in range(GALSIZE):
5269 proutn("%d |" % (i+1))
5270 for j in range(GALSIZE):
5271 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5275 if game.state.galaxy[i][j].supernova:
5277 elif not game.state.galaxy[i][j].charted and game.state.galaxy[i][j].starbase:
5279 elif game.state.galaxy[i][j].charted:
5280 show = "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars)
5284 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5292 def sectscan(goodScan, i, j):
5293 "Light up an individual dot in a sector."
5294 if goodScan or (abs(i-game.sector.i)<= 1 and abs(j-game.sector.j) <= 1):
5295 if game.quad[i][j] in ('E', 'F'):
5298 textcolor({"green":GREEN,
5302 "dead":BROWN}[game.condition])
5304 textcolor({'?':LIGHTMAGENTA,
5310 }.get(game.quad[i][j], DEFAULT))
5311 proutn("%c " % game.quad[i][j])
5317 "Emit status report lines"
5318 if not req or req == 1:
5319 prstat(_("Stardate"), _("%.1f, Time Left %.2f") \
5320 % (game.state.date, game.state.remtime))
5321 if not req or req == 2:
5322 if game.condition != "docked":
5324 prstat(_("Condition"), _("%s, %i DAMAGES") % \
5325 (game.condition.upper(), sum([x > 0 for x in game.damage])))
5327 prout(_(", CLOAKED"))
5328 if not req or req == 3:
5329 prstat(_("Position"), "%s , %s" % (game.quadrant, game.sector))
5330 if not req or req == 4:
5331 if damaged(DLIFSUP):
5332 if game.condition == "docked":
5333 s = _("DAMAGED, Base provides")
5335 s = _("DAMAGED, reserves=%4.2f") % game.lsupres
5338 prstat(_("Life Support"), s)
5339 if not req or req == 5:
5340 prstat(_("Warp Factor"), "%.1f" % game.warpfac)
5341 if not req or req == 6:
5343 if game.icrystl and (game.options & OPTION_SHOWME):
5344 extra = _(" (have crystals)")
5345 prstat(_("Energy"), "%.2f%s" % (game.energy, extra))
5346 if not req or req == 7:
5347 prstat(_("Torpedoes"), "%d" % (game.torps))
5348 if not req or req == 8:
5349 if damaged(DSHIELD):
5355 data = _(" %d%% %.1f units") \
5356 % (int((100.0*game.shield)/game.inshld + 0.5), game.shield)
5357 prstat(_("Shields"), s+data)
5358 if not req or req == 9:
5359 prstat(_("Klingons Left"), "%d" % game.unwon())
5360 if not req or req == 10:
5361 if game.options & OPTION_WORLDS:
5362 plnet = game.state.galaxy[game.quadrant.i][game.quadrant.j].planet
5363 if plnet and plnet.inhabited:
5364 prstat(_("Major system"), plnet.name)
5366 prout(_("Sector is uninhabited"))
5367 elif not req or req == 11:
5368 attackreport(not req)
5371 "Request specified status data, a historical relic from slow TTYs."
5372 requests = ("da","co","po","ls","wa","en","to","sh","kl","sy", "ti")
5373 while scanner.nexttok() == "IHEOL":
5374 proutn(_("Information desired? "))
5376 if scanner.token in requests:
5377 status(requests.index(scanner.token))
5379 prout(_("UNRECOGNIZED REQUEST. Legal requests are:"))
5380 prout((" date, condition, position, lsupport, warpfactor,"))
5381 prout((" energy, torpedoes, shields, klingons, system, time."))
5386 if damaged(DSRSENS):
5387 # Allow base's sensors if docked
5388 if game.condition != "docked":
5389 prout(_(" S.R. SENSORS DAMAGED!"))
5392 prout(_(" [Using Base's sensors]"))
5394 prout(_(" Short-range scan"))
5395 if goodScan and communicating():
5396 game.state.chart[game.quadrant.i][game.quadrant.j].klingons = game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons
5397 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase
5398 game.state.chart[game.quadrant.i][game.quadrant.j].stars = game.state.galaxy[game.quadrant.i][game.quadrant.j].stars
5399 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
5400 prout(" 1 2 3 4 5 6 7 8 9 10")
5401 if game.condition != "docked":
5403 for i in range(QUADSIZE):
5404 proutn("%2d " % (i+1))
5405 for j in range(QUADSIZE):
5406 sectscan(goodScan, i, j)
5410 "Use computer to get estimated time of arrival for a warp jump."
5411 w1 = Coord(); w2 = Coord()
5413 if damaged(DCOMPTR):
5414 prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR."))
5417 if scanner.nexttok() != "IHREAL":
5420 proutn(_("Destination quadrant and/or sector? "))
5421 if scanner.nexttok()!="IHREAL":
5424 w1.j = int(scanner.real-0.5)
5425 if scanner.nexttok() != "IHREAL":
5428 w1.i = int(scanner.real-0.5)
5429 if scanner.nexttok() == "IHREAL":
5430 w2.j = int(scanner.real-0.5)
5431 if scanner.nexttok() != "IHREAL":
5434 w2.i = int(scanner.real-0.5)
5436 if game.quadrant.j>w1.i:
5440 if game.quadrant.i>w1.j:
5444 if not w1.valid_quadrant() or not w2.valid_sector():
5447 dist = math.sqrt((w1.j-game.quadrant.j+(w2.j-game.sector.j)/(QUADSIZE*1.0))**2+
5448 (w1.i-game.quadrant.i+(w2.i-game.sector.i)/(QUADSIZE*1.0))**2)
5451 prout(_("Answer \"no\" if you don't know the value:"))
5454 proutn(_("Time or arrival date? "))
5455 if scanner.nexttok()=="IHREAL":
5456 ttime = scanner.real
5457 if ttime > game.state.date:
5458 ttime -= game.state.date # Actually a star date
5459 twarp=(math.floor(math.sqrt((10.0*dist)/ttime)*10.0)+1.0)/10.0
5460 if ttime <= 1e-10 or twarp > 10:
5461 prout(_("We'll never make it, sir."))
5468 proutn(_("Warp factor? "))
5469 if scanner.nexttok()== "IHREAL":
5471 twarp = scanner.real
5472 if twarp<1.0 or twarp > 10.0:
5476 prout(_("Captain, certainly you can give me one of these."))
5479 ttime = (10.0*dist)/twarp**2
5480 tpower = dist*twarp*twarp*twarp*(game.shldup+1)
5481 if tpower >= game.energy:
5482 prout(_("Insufficient energy, sir."))
5483 if not game.shldup or tpower > game.energy*2.0:
5486 proutn(_("New warp factor to try? "))
5487 if scanner.nexttok() == "IHREAL":
5489 twarp = scanner.real
5490 if twarp<1.0 or twarp > 10.0:
5498 prout(_("But if you lower your shields,"))
5499 proutn(_("remaining"))
5502 proutn(_("Remaining"))
5503 prout(_(" energy will be %.2f.") % (game.energy-tpower))
5505 prout(_("And we will arrive at stardate %.2f.") % (game.state.date+ttime))
5507 prout(_("Any warp speed is adequate."))
5509 prout(_("Minimum warp needed is %.2f,") % (twarp))
5510 prout(_("and we will arrive at stardate %.2f.") % (game.state.date+ttime))
5511 if game.state.remtime < ttime:
5512 prout(_("Unfortunately, the Federation will be destroyed by then."))
5514 prout(_("You'll be taking risks at that speed, Captain"))
5515 if (game.isatb==1 and game.state.kscmdr == w1 and \
5516 scheduled(FSCDBAS)< ttime+game.state.date) or \
5517 (scheduled(FCDBAS)<ttime+game.state.date and game.battle == w1):
5518 prout(_("The starbase there will be destroyed by then."))
5519 proutn(_("New warp factor to try? "))
5520 if scanner.nexttok() == "IHREAL":
5522 twarp = scanner.real
5523 if twarp<1.0 or twarp > 10.0:
5531 # Code from setup.c begins here
5534 "Issue a historically correct banner."
5536 prout(_("-SUPER- STAR TREK"))
5538 # From the FORTRAN original
5539 # prout(_("Latest update-21 Sept 78"))
5545 scanner.push("emsave.trk")
5546 key = scanner.nexttok()
5548 proutn(_("File name: "))
5549 key = scanner.nexttok()
5550 if key != "IHALPHA":
5553 if '.' not in scanner.token:
5554 scanner.token += ".trk"
5556 fp = open(scanner.token, "wb")
5558 prout(_("Can't freeze game as file %s") % scanner.token)
5560 pickle.dump(game, fp)
5565 "Retrieve saved game."
5568 key = scanner.nexttok()
5570 proutn(_("File name: "))
5571 key = scanner.nexttok()
5572 if key != "IHALPHA":
5575 if '.' not in scanner.token:
5576 scanner.token += ".trk"
5578 fp = open(scanner.token, "rb")
5580 prout(_("Can't thaw game in %s") % scanner.token)
5582 game = pickle.load(fp)
5587 # I used <http://www.memory-alpha.org> to find planets
5588 # with references in ST:TOS. Earth and the Alpha Centauri
5589 # Colony have been omitted.
5591 # Some planets marked Class G and P here will be displayed as class M
5592 # because of the way planets are generated. This is a known bug.
5595 _("Andoria (Fesoan)"), # several episodes
5596 _("Tellar Prime (Miracht)"), # TOS: "Journey to Babel"
5597 _("Vulcan (T'Khasi)"), # many episodes
5598 _("Medusa"), # TOS: "Is There in Truth No Beauty?"
5599 _("Argelius II (Nelphia)"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5600 _("Ardana"), # TOS: "The Cloud Minders"
5601 _("Catulla (Cendo-Prae)"), # TOS: "The Way to Eden"
5602 _("Gideon"), # TOS: "The Mark of Gideon"
5603 _("Aldebaran III"), # TOS: "The Deadly Years"
5604 _("Alpha Majoris I"), # TOS: "Wolf in the Fold"
5605 _("Altair IV"), # TOS: "Amok Time
5606 _("Ariannus"), # TOS: "Let That Be Your Last Battlefield"
5607 _("Benecia"), # TOS: "The Conscience of the King"
5608 _("Beta Niobe I (Sarpeidon)"), # TOS: "All Our Yesterdays"
5609 _("Alpha Carinae II"), # TOS: "The Ultimate Computer"
5610 _("Capella IV (Kohath)"), # TOS: "Friday's Child" (Class G)
5611 _("Daran V"), # TOS: "For the World is Hollow and I Have Touched the Sky"
5612 _("Deneb II"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5613 _("Eminiar VII"), # TOS: "A Taste of Armageddon"
5614 _("Gamma Canaris IV"), # TOS: "Metamorphosis"
5615 _("Gamma Tranguli VI (Vaalel)"), # TOS: "The Apple"
5616 _("Ingraham B"), # TOS: "Operation: Annihilate"
5617 _("Janus IV"), # TOS: "The Devil in the Dark"
5618 _("Makus III"), # TOS: "The Galileo Seven"
5619 _("Marcos XII"), # TOS: "And the Children Shall Lead",
5620 _("Omega IV"), # TOS: "The Omega Glory"
5621 _("Regulus V"), # TOS: "Amok Time
5622 _("Deneva"), # TOS: "Operation -- Annihilate!"
5623 # Worlds from BSD Trek
5624 _("Rigel II"), # TOS: "Shore Leave" ("III" in BSD)
5625 _("Beta III"), # TOS: "The Return of the Archons"
5626 _("Triacus"), # TOS: "And the Children Shall Lead",
5627 _("Exo III"), # TOS: "What Are Little Girls Made Of?" (Class P)
5629 # _("Hansen's Planet"), # TOS: "The Galileo Seven"
5630 # _("Taurus IV"), # TOS: "The Galileo Seven" (class G)
5631 # _("Antos IV (Doraphane)"), # TOS: "Whom Gods Destroy", "Who Mourns for Adonais?"
5632 # _("Izar"), # TOS: "Whom Gods Destroy"
5633 # _("Tiburon"), # TOS: "The Way to Eden"
5634 # _("Merak II"), # TOS: "The Cloud Minders"
5635 # _("Coridan (Desotriana)"), # TOS: "Journey to Babel"
5636 # _("Iotia"), # TOS: "A Piece of the Action"
5640 _("S. R. Sensors"), \
5641 _("L. R. Sensors"), \
5643 _("Photon Tubes"), \
5644 _("Life Support"), \
5645 _("Warp Engines"), \
5646 _("Impulse Engines"), \
5648 _("Subspace Radio"), \
5649 _("Shuttle Craft"), \
5651 _("Navigation System"), \
5653 _("Shield Control"), \
5656 _("Cloaking Device"), \
5660 "Prepare to play, set up cosmos."
5662 # Decide how many of everything
5664 return # frozen game
5665 # Prepare the Enterprise
5666 game.alldone = game.gamewon = game.shldchg = game.shldup = False
5668 game.state.crew = FULLCREW
5669 game.energy = game.inenrg = 5000.0
5670 game.shield = game.inshld = 2500.0
5673 game.quadrant = randplace(GALSIZE)
5674 game.sector = randplace(QUADSIZE)
5675 game.torps = game.intorps = 10
5676 game.nprobes = randrange(2, 5)
5678 for i in range(NDEVICES):
5679 game.damage[i] = 0.0
5680 # Set up assorted game parameters
5681 game.battle = Coord()
5682 game.state.date = game.indate = 100.0 * randreal(20, 51)
5683 game.nkinks = game.nhelp = game.casual = game.abandoned = 0
5684 game.iscate = game.resting = game.imine = game.icrystl = game.icraft = False
5685 game.isatb = game.state.nplankl = 0
5686 game.state.starkl = game.state.basekl = game.state.nworldkl = 0
5687 game.iscraft = "onship"
5692 game.state.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
5694 game.state.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
5696 game.state.planets = [] # Planet information
5697 game.state.baseq = [] # Base quadrant coordinates
5698 game.state.kcmdr = [] # Commander quadrant coordinates
5699 game.statekscmdr = Coord() # Supercommander quadrant coordinates
5701 # Starchart is functional but we've never seen it
5702 game.lastchart = FOREVER
5703 # Put stars in the galaxy
5705 for i in range(GALSIZE):
5706 for j in range(GALSIZE):
5707 # Can't have more stars per quadrant than fit in one decimal digit,
5708 # if we do the chart representation will break.
5709 k = randrange(1, min(10, QUADSIZE**2/10))
5711 game.state.galaxy[i][j].stars = k
5712 # Locate star bases in galaxy
5714 prout("=== Allocating %d bases" % game.inbase)
5715 for i in range(game.inbase):
5718 w = randplace(GALSIZE)
5719 if not game.state.galaxy[w.i][w.j].starbase:
5722 # C version: for (j = i-1; j > 0; j--)
5723 # so it did them in the opposite order.
5724 for j in range(1, i):
5725 # Improved placement algorithm to spread out bases
5726 distq = (w - game.state.baseq[j]).distance()
5727 if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75):
5730 prout("=== Abandoning base #%d at %s" % (i, w))
5732 elif distq < 6.0 * (BASEMAX+1-game.inbase):
5734 prout("=== Saving base #%d, close to #%d" % (i, j))
5738 prout("=== Placing base #%d in quadrant %s" % (i, w))
5739 game.state.baseq.append(w)
5740 game.state.galaxy[w.i][w.j].starbase = game.state.chart[w.i][w.j].starbase = True
5741 # Position ordinary Klingon Battle Cruisers
5743 klumper = 0.25*game.skill*(9.0-game.length)+1.0
5744 if klumper > MAXKLQUAD:
5748 klump = (1.0 - r*r)*klumper
5753 w = randplace(GALSIZE)
5754 if not game.state.galaxy[w.i][w.j].supernova and \
5755 game.state.galaxy[w.i][w.j].klingons + klump <= MAXKLQUAD:
5757 game.state.galaxy[w.i][w.j].klingons += int(klump)
5760 # Position Klingon Commander Ships
5761 for i in range(game.incom):
5763 w = randplace(GALSIZE)
5764 if not welcoming(w) or w in game.state.kcmdr:
5766 if (game.state.galaxy[w.i][w.j].klingons or withprob(0.25)):
5768 game.state.galaxy[w.i][w.j].klingons += 1
5769 game.state.kcmdr.append(w)
5770 # Locate planets in galaxy
5771 for i in range(game.inplan):
5773 w = randplace(GALSIZE)
5774 if game.state.galaxy[w.i][w.j].planet is None:
5778 new.crystals = "absent"
5779 if (game.options & OPTION_WORLDS) and i < NINHAB:
5780 new.pclass = "M" # All inhabited planets are class M
5781 new.crystals = "absent"
5783 new.name = systnames[i]
5784 new.inhabited = True
5786 new.pclass = ("M", "N", "O")[randrange(0, 3)]
5788 new.crystals = "present"
5789 new.known = "unknown"
5790 new.inhabited = False
5791 game.state.galaxy[w.i][w.j].planet = new
5792 game.state.planets.append(new)
5794 for i in range(game.state.nromrem):
5795 w = randplace(GALSIZE)
5796 game.state.galaxy[w.i][w.j].romulans += 1
5797 # Place the Super-Commander if needed
5798 if game.state.nscrem > 0:
5800 w = randplace(GALSIZE)
5803 game.state.kscmdr = w
5804 game.state.galaxy[w.i][w.j].klingons += 1
5805 # Initialize times for extraneous events
5806 schedule(FSNOVA, expran(0.5 * game.intime))
5807 schedule(FTBEAM, expran(1.5 * (game.intime / len(game.state.kcmdr))))
5808 schedule(FSNAP, randreal(1.0, 2.0)) # Force an early snapshot
5809 schedule(FBATTAK, expran(0.3*game.intime))
5811 if game.state.nscrem:
5812 schedule(FSCMOVE, 0.2777)
5817 if (game.options & OPTION_WORLDS) and game.skill >= SKILL_GOOD:
5818 schedule(FDISTR, expran(1.0 + game.intime))
5823 # Place thing (in tournament game, we don't want one!)
5824 # New in SST2K: never place the Thing near a starbase.
5825 # This makes sense and avoids a special case in the old code.
5827 if game.tourn is None:
5829 thing = randplace(GALSIZE)
5830 if thing not in game.state.baseq:
5833 game.state.snap = False
5834 if game.skill == SKILL_NOVICE:
5835 prout(_("It is stardate %d. The Federation is being attacked by") % int(game.state.date))
5836 prout(_("a deadly Klingon invasion force. As captain of the United"))
5837 prout(_("Starship U.S.S. Enterprise, it is your mission to seek out"))
5838 prout(_("and destroy this invasion force of %d battle cruisers.") % ((game.inkling + game.incom + game.inscom)))
5839 prout(_("You have an initial allotment of %d stardates to complete") % int(game.intime))
5840 prout(_("your mission. As you proceed you may be given more time."))
5842 prout(_("You will have %d supporting starbases.") % (game.inbase))
5843 proutn(_("Starbase locations- "))
5845 prout(_("Stardate %d.") % int(game.state.date))
5847 prout(_("%d Klingons.") % (game.inkling + game.incom + game.inscom))
5848 prout(_("An unknown number of Romulans."))
5849 if game.state.nscrem:
5850 prout(_("And one (GULP) Super-Commander."))
5851 prout(_("%d stardates.") % int(game.intime))
5852 proutn(_("%d starbases in ") % game.inbase)
5853 for i in range(game.inbase):
5854 proutn(repr(game.state.baseq[i]))
5857 proutn(_("The Enterprise is currently in Quadrant %s") % game.quadrant)
5858 proutn(_(" Sector %s") % game.sector)
5860 prout(_("Good Luck!"))
5861 if game.state.nscrem:
5862 prout(_(" YOU'LL NEED IT."))
5865 setwnd(message_window)
5867 if len(game.enemies) - (thing == game.quadrant) - (game.tholian != None):
5869 if game.neutz: # bad luck to start in a Romulan Neutral Zone
5870 attack(torps_ok=False)
5873 "Choose your game type."
5875 game.tourn = game.length = 0
5877 game.skill = SKILL_NONE
5878 # Do not chew here, we want to use command-line tokens
5879 if not scanner.inqueue: # Can start with command line options
5880 proutn(_("Would you like a regular, tournament, or saved game? "))
5882 if scanner.sees("tournament"):
5883 while scanner.nexttok() == "IHEOL":
5884 proutn(_("Type in tournament number-"))
5885 if scanner.real == 0:
5887 continue # We don't want a blank entry
5888 game.tourn = int(round(scanner.real))
5889 random.seed(scanner.real)
5891 logfp.write("# random.seed(%d)\n" % scanner.real)
5893 if scanner.sees("saved") or scanner.sees("frozen"):
5897 if game.passwd is None:
5899 if not game.alldone:
5900 game.thawed = True # No plaque if not finished
5904 if scanner.sees("regular"):
5906 proutn(_("What is \"%s\"? ") % scanner.token)
5908 while game.length==0 or game.skill==SKILL_NONE:
5909 if scanner.nexttok() == "IHALPHA":
5910 if scanner.sees("short"):
5912 elif scanner.sees("medium"):
5914 elif scanner.sees("long"):
5916 elif scanner.sees("novice"):
5917 game.skill = SKILL_NOVICE
5918 elif scanner.sees("fair"):
5919 game.skill = SKILL_FAIR
5920 elif scanner.sees("good"):
5921 game.skill = SKILL_GOOD
5922 elif scanner.sees("expert"):
5923 game.skill = SKILL_EXPERT
5924 elif scanner.sees("emeritus"):
5925 game.skill = SKILL_EMERITUS
5927 proutn(_("What is \""))
5928 proutn(scanner.token)
5933 proutn(_("Would you like a Short, Medium, or Long game? "))
5934 elif game.skill == SKILL_NONE:
5935 proutn(_("Are you a Novice, Fair, Good, Expert, or Emeritus player? "))
5936 # Choose game options -- added by ESR for SST2K
5937 if scanner.nexttok() != "IHALPHA":
5939 proutn(_("Choose your game style (plain, almy, fancy or just press enter): "))
5941 if scanner.sees("plain"):
5942 # Approximates the UT FORTRAN version.
5943 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)
5944 game.options |= OPTION_PLAIN
5945 elif scanner.sees("almy"):
5946 # Approximates Tom Almy's version.
5947 game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS | OPTION_COLOR)
5948 game.options |= OPTION_ALMY
5949 elif scanner.sees("fancy") or scanner.sees("\n"):
5951 elif len(scanner.token):
5952 proutn(_("What is \"%s\"?") % scanner.token)
5954 if game.passwd == "debug":
5956 prout("=== Debug mode enabled.")
5957 # Use parameters to generate initial values of things
5958 game.damfac = 0.5 * game.skill
5959 game.inbase = randrange(BASEMIN, BASEMAX+1)
5961 if game.options & OPTION_PLANETS:
5962 game.inplan += randrange(MAXUNINHAB/2, MAXUNINHAB+1)
5963 if game.options & OPTION_WORLDS:
5964 game.inplan += int(NINHAB)
5965 game.state.nromrem = game.inrom = randrange(2 * game.skill)
5966 game.state.nscrem = game.inscom = (game.skill > SKILL_FAIR)
5967 game.state.remtime = 7.0 * game.length
5968 game.intime = game.state.remtime
5969 game.state.remkl = game.inkling = 2.0*game.intime*((game.skill+1 - 2*randreal())*game.skill*0.1+.15)
5970 game.incom = min(MINCMDR, int(game.skill + 0.0625*game.inkling*randreal()))
5971 game.state.remres = (game.inkling+4*game.incom)*game.intime
5972 game.inresor = game.state.remres
5973 if game.inkling > 50:
5977 def dropin(iquad=None):
5978 "Drop a feature on a random dot in the current quadrant."
5980 w = randplace(QUADSIZE)
5981 if game.quad[w.i][w.j] == '.':
5983 if iquad is not None:
5984 game.quad[w.i][w.j] = iquad
5988 "Update our alert status."
5989 game.condition = "green"
5990 if game.energy < 1000.0:
5991 game.condition = "yellow"
5992 if game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons or game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans:
5993 game.condition = "red"
5995 game.condition="dead"
5998 "Drop new Klingon into current quadrant."
5999 return Enemy('K', loc=dropin(), power=randreal(300,450)+25.0*game.skill)
6002 "Sort enemies by distance so 'nearest' is meaningful."
6003 game.enemies.sort(key=lambda x: x.kdist)
6006 "Set up a new state of quadrant, for when we enter or re-enter it."
6009 game.neutz = game.inorbit = game.landed = False
6010 game.ientesc = game.iseenit = game.isviolreported = False
6011 # Create a blank quadrant
6012 game.quad = fill2d(QUADSIZE, lambda i, j: '.')
6014 # Attempt to escape Super-commander, so tbeam back!
6017 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
6018 # cope with supernova
6021 game.klhere = q.klingons
6022 game.irhere = q.romulans
6024 game.quad[game.sector.i][game.sector.j] = game.ship
6027 # Position ordinary Klingons
6028 for _i in range(game.klhere):
6030 # If we need a commander, promote a Klingon
6031 for cmdr in game.state.kcmdr:
6032 if cmdr == game.quadrant:
6033 e = game.enemies[game.klhere-1]
6034 game.quad[e.location.i][e.location.j] = 'C'
6035 e.power = randreal(950,1350) + 50.0*game.skill
6037 # If we need a super-commander, promote a Klingon
6038 if game.quadrant == game.state.kscmdr:
6040 game.quad[e.location.i][e.location.j] = 'S'
6041 e.power = randreal(1175.0, 1575.0) + 125.0*game.skill
6042 game.iscate = (game.state.remkl > 1)
6043 # Put in Romulans if needed
6044 for _i in range(q.romulans):
6045 Enemy('R', loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill)
6046 # If quadrant needs a starbase, put it in
6048 game.base = dropin('B')
6049 # If quadrant needs a planet, put it in
6051 game.iplnet = q.planet
6052 if not q.planet.inhabited:
6053 game.plnet = dropin('P')
6055 game.plnet = dropin('@')
6056 # Check for condition
6059 if game.irhere > 0 and game.klhere == 0:
6061 if not damaged(DRADIO):
6063 prout(_("LT. Uhura- \"Captain, an urgent message."))
6064 prout(_(" I'll put it on audio.\" CLICK"))
6066 prout(_("INTRUDER! YOU HAVE VIOLATED THE ROMULAN NEUTRAL ZONE."))
6067 prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!"))
6068 # Put in THING if needed
6069 if thing == game.quadrant:
6070 Enemy(etype='?', loc=dropin(),
6071 power=randreal(6000,6500.0)+250.0*game.skill)
6072 if not damaged(DSRSENS):
6074 prout(_("Mr. Spock- \"Captain, this is most unusual."))
6075 prout(_(" Please examine your short-range scan.\""))
6076 # Decide if quadrant needs a Tholian; lighten up if skill is low
6077 if game.options & OPTION_THOLIAN:
6078 if (game.skill < SKILL_GOOD and withprob(0.02)) or \
6079 (game.skill == SKILL_GOOD and withprob(0.05)) or \
6080 (game.skill > SKILL_GOOD and withprob(0.08)):
6083 w.i = withprob(0.5) * (QUADSIZE-1)
6084 w.j = withprob(0.5) * (QUADSIZE-1)
6085 if game.quad[w.i][w.j] == '.':
6087 game.tholian = Enemy(etype='T', loc=w,
6088 power=randrange(100, 500) + 25.0*game.skill)
6089 # Reserve unoccupied corners
6090 if game.quad[0][0]=='.':
6091 game.quad[0][0] = 'X'
6092 if game.quad[0][QUADSIZE-1]=='.':
6093 game.quad[0][QUADSIZE-1] = 'X'
6094 if game.quad[QUADSIZE-1][0]=='.':
6095 game.quad[QUADSIZE-1][0] = 'X'
6096 if game.quad[QUADSIZE-1][QUADSIZE-1]=='.':
6097 game.quad[QUADSIZE-1][QUADSIZE-1] = 'X'
6099 # And finally the stars
6100 for _i in range(q.stars):
6102 # Put in a few black holes
6103 for _i in range(1, 3+1):
6106 # Take out X's in corners if Tholian present
6108 if game.quad[0][0]=='X':
6109 game.quad[0][0] = '.'
6110 if game.quad[0][QUADSIZE-1]=='X':
6111 game.quad[0][QUADSIZE-1] = '.'
6112 if game.quad[QUADSIZE-1][0]=='X':
6113 game.quad[QUADSIZE-1][0] = '.'
6114 if game.quad[QUADSIZE-1][QUADSIZE-1]=='X':
6115 game.quad[QUADSIZE-1][QUADSIZE-1] = '.'
6118 "Set the self-destruct password."
6119 if game.options & OPTION_PLAIN:
6122 proutn(_("Please type in a secret password- "))
6124 game.passwd = scanner.token
6125 if game.passwd != None:
6129 game.passwd += chr(ord('a')+randrange(26))
6130 game.passwd += chr(ord('a')+randrange(26))
6131 game.passwd += chr(ord('a')+randrange(26))
6133 # Code from sst.c begins here
6136 ("SRSCAN", OPTION_TTY),
6137 ("STATUS", OPTION_TTY),
6138 ("REQUEST", OPTION_TTY),
6139 ("LRSCAN", OPTION_TTY),
6151 ("SENSORS", OPTION_PLANETS),
6152 ("ORBIT", OPTION_PLANETS),
6153 ("TRANSPORT", OPTION_PLANETS),
6154 ("MINE", OPTION_PLANETS),
6155 ("CRYSTALS", OPTION_PLANETS),
6156 ("SHUTTLE", OPTION_PLANETS),
6157 ("PLANETS", OPTION_PLANETS),
6162 ("PROBE", OPTION_PROBE),
6164 ("FREEZE", 0), # Synonym for SAVE
6168 ("CAPTURE", OPTION_CAPTURE),
6169 ("CLOAK", OPTION_CLOAK),
6172 ("SOS", 0), # Synonym for MAYDAY
6173 ("CALL", 0), # Synonym for MAYDAY
6181 "Generate a list of legal commands."
6182 prout(_("LEGAL COMMANDS ARE:"))
6184 for (key, opt) in commands:
6185 if not opt or (opt & game.options):
6186 proutn("%-12s " % key)
6188 if emitted % 5 == 4:
6193 "Browse on-line help."
6194 key = scanner.nexttok()
6197 setwnd(prompt_window)
6198 proutn(_("Help on what command? "))
6199 key = scanner.nexttok()
6200 setwnd(message_window)
6203 cmds = [x[0] for x in commands]
6204 if scanner.token.upper() in cmds or scanner.token.upper() == "ABBREV":
6211 cmd = scanner.token.upper()
6212 for directory in docpath:
6214 fp = open(os.path.join(directory, "sst.doc"), "r")
6219 prout(_("Spock- \"Captain, that information is missing from the"))
6220 prout(_(" computer. You need to find sst.doc and put it somewhere"))
6221 proutn(_(" in these directories: %s") % ":".join(docpath))
6223 # This used to continue: "You need to find SST.DOC and put
6224 # it in the current directory."
6227 linebuf = fp.readline()
6229 prout(_("Spock- \"Captain, there is no information on that command.\""))
6232 if linebuf[0] == '%' and linebuf[1] == '%' and linebuf[2] == ' ':
6233 linebuf = linebuf[3:].strip()
6234 if cmd.upper() == linebuf:
6237 prout(_("Spock- \"Captain, I've found the following information:\""))
6240 linebuf = fp.readline()
6241 if "******" in linebuf:
6247 "Command-interpretation loop."
6249 if game.irhere and game.state.date >= ALGERON and not game.isviolreported and game.iscloaked:
6250 prout(_("The Romulan ship discovers you are breaking the Treaty of Algeron!"))
6252 game.isviolreported = True
6253 while True: # command loop
6255 while True: # get a command
6257 game.optime = game.justin = False
6259 setwnd(prompt_window)
6262 if scanner.nexttok() == "IHEOL":
6263 if game.options & OPTION_CURSES:
6266 elif scanner.token == "":
6270 setwnd(message_window)
6272 abandon_passed = False
6273 cmd = "" # Force cmd to persist after loop
6274 opt = 0 # Force opt to persist after loop
6275 for (cmd, opt) in commands:
6276 # commands after ABANDON cannot be abbreviated
6277 if cmd == "ABANDON":
6278 abandon_passed = True
6279 if cmd == scanner.token.upper() or (not abandon_passed \
6280 and cmd.startswith(scanner.token.upper())):
6285 elif opt and not (opt & game.options):
6289 prout("COMMAND> %s" % cmd)
6290 if cmd == "SRSCAN": # srscan
6292 elif cmd == "STATUS": # status
6294 elif cmd == "REQUEST": # status request
6296 elif cmd == "LRSCAN": # long range scan
6297 lrscan(silent=False)
6298 elif cmd == "PHASERS": # phasers
6303 elif cmd in ("TORPEDO", "PHOTONS"): # photon torpedos
6308 elif cmd == "MOVE": # move under warp
6309 warp(wcourse=None, involuntary=False)
6310 elif cmd == "SHIELDS": # shields
6311 doshield(shraise=False)
6314 game.shldchg = False
6315 elif cmd == "DOCK": # dock at starbase
6318 attack(torps_ok=False)
6319 elif cmd == "DAMAGES": # damage reports
6321 elif cmd == "CHART": # chart
6323 elif cmd == "IMPULSE": # impulse
6325 elif cmd == "REST": # rest
6329 elif cmd == "WARP": # warp
6331 elif cmd == "SENSORS": # sensors
6333 elif cmd == "ORBIT": # orbit
6337 elif cmd == "TRANSPORT": # transport "beam"
6339 elif cmd == "MINE": # mine
6343 elif cmd == "CRYSTALS": # crystals
6347 elif cmd == "SHUTTLE": # shuttle
6351 elif cmd == "PLANETS": # Planet list
6353 elif cmd == "REPORT": # Game Report
6355 elif cmd == "COMPUTER": # use COMPUTER!
6357 elif cmd == "COMMANDS":
6359 elif cmd == "EMEXIT": # Emergency exit
6360 clrscr() # Hide screen
6361 freeze(True) # forced save
6362 raise SystemExit(1) # And quick exit
6363 elif cmd == "PROBE":
6364 probe() # Launch probe
6367 elif cmd == "ABANDON": # Abandon Ship
6369 elif cmd == "DESTRUCT": # Self Destruct
6371 elif cmd == "SAVE": # Save Game
6374 if game.skill > SKILL_GOOD:
6375 prout(_("WARNING--Saved games produce no plaques!"))
6376 elif cmd == "DEATHRAY": # Try a desparation measure
6380 elif cmd == "CAPTURE":
6382 elif cmd == "CLOAK":
6384 elif cmd == "DEBUGCMD": # What do we want for debug???
6386 elif cmd == "MAYDAY": # Call for help
6391 game.alldone = True # quit the game
6394 elif cmd == "SCORE":
6395 score() # see current score
6398 break # Game has ended
6399 if game.optime != 0.0:
6402 break # Events did us in
6403 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6406 if hitme and not game.justin:
6407 attack(torps_ok=True)
6410 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6421 "Emit the name of an enemy or feature."
6422 if ch == 'R': s = _("Romulan")
6423 elif ch == 'K': s = _("Klingon")
6424 elif ch == 'C': s = _("Commander")
6425 elif ch == 'S': s = _("Super-commander")
6426 elif ch == '*': s = _("Star")
6427 elif ch == 'P': s = _("Planet")
6428 elif ch == 'B': s = _("Starbase")
6429 elif ch == ' ': s = _("Black hole")
6430 elif ch == 'T': s = _("Tholian")
6431 elif ch == '#': s = _("Tholian web")
6432 elif ch == '?': s = _("Stranger")
6433 elif ch == '@': s = _("Inhabited World")
6434 else: s = "Unknown??"
6437 def crmena(loud, enemy, loctype, w):
6438 "Emit the name of an enemy and his location."
6442 buf += cramen(enemy) + _(" at ")
6443 if loctype == "quadrant":
6444 buf += _("Quadrant ")
6445 elif loctype == "sector":
6447 return buf + repr(w)
6450 "Emit our ship name."
6451 return{'E':_("Enterprise"),'F':_("Faerie Queene")}.get(game.ship,"Ship???")
6454 "Emit a line of stars"
6455 prouts("******************************************************")
6459 return -avrage*math.log(1e-7 + randreal())
6461 def randplace(size):
6462 "Choose a random location."
6464 w.i = randrange(size)
6465 w.j = randrange(size)
6475 # Get a token from the user
6478 # Fill the token quue if nothing here
6479 while not self.inqueue:
6481 if curwnd==prompt_window:
6483 setwnd(message_window)
6490 self.inqueue = sline.lstrip().split() + ["\n"]
6491 # From here on in it's all looking at the queue
6492 self.token = self.inqueue.pop(0)
6493 if self.token == "\n":
6497 self.real = float(self.token)
6498 self.type = "IHREAL"
6503 self.token = self.token.lower()
6504 self.type = "IHALPHA"
6507 def append(self, tok):
6508 self.inqueue.append(tok)
6509 def push(self, tok):
6510 self.inqueue.insert(0, tok)
6514 # Demand input for next scan
6516 self.real = self.token = None
6518 # compares s to item and returns true if it matches to the length of s
6519 return s.startswith(self.token)
6521 # Round token value to nearest integer
6522 return int(round(self.real))
6526 if self.type != "IHREAL":
6531 if self.type != "IHREAL":
6537 return "<sstcanner: token=%s, type=%s, queue=%s>" % (self.token, self.type, self.inqueue)
6540 "Yes-or-no confirmation."
6544 if scanner.token == 'y':
6546 if scanner.token == 'n':
6549 proutn(_("Please answer with \"y\" or \"n\": "))
6552 "Complain about unparseable input."
6555 prout(_("Beg your pardon, Captain?"))
6558 "Access to the internals for debugging."
6559 proutn("Reset levels? ")
6561 if game.energy < game.inenrg:
6562 game.energy = game.inenrg
6563 game.shield = game.inshld
6564 game.torps = game.intorps
6565 game.lsupres = game.inlsr
6566 proutn("Reset damage? ")
6568 for i in range(NDEVICES):
6569 if game.damage[i] > 0.0:
6570 game.damage[i] = 0.0
6571 proutn("Toggle debug flag? ")
6573 game.idebug = not game.idebug
6575 prout("Debug output ON")
6577 prout("Debug output OFF")
6578 proutn("Cause selective damage? ")
6580 for i in range(NDEVICES):
6581 proutn("Kill %s?" % device[i])
6583 key = scanner.nexttok()
6584 if key == "IHALPHA" and scanner.sees("y"):
6585 game.damage[i] = 10.0
6586 proutn("Examine/change events? ")
6591 FSNOVA: "Supernova ",
6594 FBATTAK: "Base Attack ",
6595 FCDBAS: "Base Destroy ",
6596 FSCMOVE: "SC Move ",
6597 FSCDBAS: "SC Base Destroy ",
6598 FDSPROB: "Probe Move ",
6599 FDISTR: "Distress Call ",
6600 FENSLV: "Enslavement ",
6601 FREPRO: "Klingon Build ",
6603 for i in range(1, NEVENTS):
6606 proutn("%.2f" % (scheduled(i)-game.state.date))
6607 if i == FENSLV or i == FREPRO:
6609 proutn(" in %s" % ev.quadrant)
6614 key = scanner.nexttok()
6618 elif key == "IHREAL":
6619 ev = schedule(i, scanner.real)
6620 if i == FENSLV or i == FREPRO:
6622 proutn("In quadrant- ")
6623 key = scanner.nexttok()
6624 # "IHEOL" says to leave coordinates as they are
6627 prout("Event %d canceled, no x coordinate." % (i))
6630 w.i = int(round(scanner.real))
6631 key = scanner.nexttok()
6633 prout("Event %d canceled, no y coordinate." % (i))
6636 w.j = int(round(scanner.real))
6639 proutn("Induce supernova here? ")
6641 game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova = True
6644 if __name__ == '__main__':
6646 #global line, thing, game
6650 game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY)
6651 if os.getenv("TERM"):
6652 game.options |= OPTION_CURSES
6654 game.options |= OPTION_TTY
6655 seed = int(time.time())
6656 (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:txV")
6658 for (switch, val) in options:
6661 replayfp = open(val, "r")
6663 sys.stderr.write("sst: can't open replay file %s\n" % val)
6666 line = replayfp.readline().strip()
6667 (leader, __, seed) = line.split()
6669 sys.stderr.write("sst2k: seed set to %s\n" % seed)
6670 line = replayfp.readline().strip()
6671 arguments += line.split()[2:]
6674 sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
6676 game.options |= OPTION_TTY
6677 game.options &=~ OPTION_CURSES
6678 elif switch == '-s':
6680 elif switch == '-t':
6681 game.options |= OPTION_TTY
6682 game.options &=~ OPTION_CURSES
6683 elif switch == '-x':
6685 elif switch == '-V':
6686 print("SST2K", version)
6689 sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n")
6691 # where to save the input in case of bugs
6692 if "TMPDIR" in os.environ:
6693 tmpdir = os.environ['TMPDIR']
6697 logfp = open(os.path.join(tmpdir, "sst-input.log"), "w")
6699 sys.stderr.write("sst: warning, can't open logfile\n")
6702 logfp.write("# seed %s\n" % seed)
6703 logfp.write("# options %s\n" % " ".join(arguments))
6704 logfp.write("# SST2K version %s\n" % version)
6705 logfp.write("# recorded by %s@%s on %s\n" % \
6706 (getpass.getuser(),socket.gethostname(),time.ctime()))
6708 scanner = sstscanner()
6709 for arg in arguments:
6713 while True: # Play a game
6714 setwnd(fullscreen_window)
6720 game.alldone = False
6728 if game.tourn and game.alldone:
6729 proutn(_("Do you want your score recorded?"))
6735 proutn(_("Do you want to play again? "))
6739 prout(_("May the Great Bird of the Galaxy roost upon your home planet."))
6743 except KeyboardInterrupt: