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 # Guard prevents failure on Tholian or thingy
323 if self in game.enemies:
324 game.enemies.remove(self)
327 return "<%s,%s.%f>" % (self.type, self.location, self.power) # For debugging
331 self.options = None # Game options
332 self.state = Snapshot() # A snapshot structure
333 self.snapsht = Snapshot() # Last snapshot taken for time-travel purposes
334 self.quad = None # contents of our quadrant
335 self.damage = [0.0] * NDEVICES # damage encountered
336 self.future = [] # future events
340 self.future.append(Event())
341 self.passwd = None # Self Destruct password
343 self.quadrant = None # where we are in the large
344 self.sector = None # where we are in the small
345 self.tholian = None # Tholian enemy object
346 self.base = None # position of base in current quadrant
347 self.battle = None # base coordinates being attacked
348 self.plnet = None # location of planet in quadrant
349 self.gamewon = False # Finished!
350 self.ididit = False # action taken -- allows enemy to attack
351 self.alive = False # we are alive (not killed)
352 self.justin = False # just entered quadrant
353 self.shldup = False # shields are up
354 self.shldchg = False # shield is changing (affects efficiency)
355 self.iscate = False # super commander is here
356 self.ientesc = False # attempted escape from supercommander
357 self.resting = False # rest time
358 self.icraft = False # Kirk in Galileo
359 self.landed = False # party on planet (true), on ship (false)
360 self.alldone = False # game is now finished
361 self.neutz = False # Romulan Neutral Zone
362 self.isarmed = False # probe is armed
363 self.inorbit = False # orbiting a planet
364 self.imine = False # mining
365 self.icrystl = False # dilithium crystals aboard
366 self.iseenit = False # seen base attack report
367 self.thawed = False # thawed game
368 self.condition = None # "green", "yellow", "red", "docked", "dead"
369 self.iscraft = None # "onship", "offship", "removed"
370 self.skill = None # Player skill level
371 self.inkling = 0 # initial number of klingons
372 self.inbase = 0 # initial number of bases
373 self.incom = 0 # initial number of commanders
374 self.inscom = 0 # initial number of commanders
375 self.inrom = 0 # initial number of commanders
376 self.instar = 0 # initial stars
377 self.intorps = 0 # initial/max torpedoes
378 self.torps = 0 # number of torpedoes
379 self.ship = 0 # ship type -- 'E' is Enterprise
380 self.abandoned = 0 # count of crew abandoned in space
381 self.length = 0 # length of game
382 self.klhere = 0 # klingons here
383 self.casual = 0 # causalties
384 self.nhelp = 0 # calls for help
385 self.nkinks = 0 # count of energy-barrier crossings
386 self.iplnet = None # planet # in quadrant
387 self.inplan = 0 # initial planets
388 self.irhere = 0 # Romulans in quadrant
389 self.isatb = 0 # =2 if super commander is attacking base
390 self.tourn = None # tournament number
391 self.nprobes = 0 # number of probes available
392 self.inresor = 0.0 # initial resources
393 self.intime = 0.0 # initial time
394 self.inenrg = 0.0 # initial/max energy
395 self.inshld = 0.0 # initial/max shield
396 self.inlsr = 0.0 # initial life support resources
397 self.indate = 0.0 # initial date
398 self.energy = 0.0 # energy level
399 self.shield = 0.0 # shield level
400 self.warpfac = 0.0 # warp speed
401 self.lsupres = 0.0 # life support reserves
402 self.optime = 0.0 # time taken by current operation
403 self.damfac = 0.0 # damage factor
404 self.lastchart = 0.0 # time star chart was last updated
405 self.cryprob = 0.0 # probability that crystal will work
406 self.probe = None # object holding probe course info
407 self.height = 0.0 # height of orbit around planet
408 self.score = 0.0 # overall score
409 self.perdate = 0.0 # rate of kills
410 self.idebug = False # Debugging instrumentation enabled?
411 self.statekscmdr = None # No SuperCommander coordinates yet.
412 self.brigcapacity = 400 # Enterprise brig capacity
413 self.brigfree = 400 # How many klingons can we put in the brig?
414 self.kcaptured = 0 # Total Klingons captured, for scoring.
415 self.iscloaked = False # Cloaking device on?
416 self.ncviol = 0 # Algreon treaty violations
417 self.isviolreported = False # We have been warned
419 # Stas thinks this should be (C expression):
420 # game.state.remkl + len(game.state.kcmdr) > 0 ?
421 # game.state.remres/(game.state.remkl + 4*len(game.state.kcmdr)) : 99
422 # He says the existing expression is prone to divide-by-zero errors
423 # after killing the last klingon when score is shown -- perhaps also
424 # if the only remaining klingon is SCOM.
425 self.state.remtime = self.state.remres/(self.state.remkl + 4*len(self.state.kcmdr))
427 "Are there Klingons remaining?"
428 return self.state.remkl + len(self.state.kcmdr) + self.state.nscrem
455 return random.random() < p
457 def randrange(*args):
458 return random.randrange(*args)
463 v *= args[0] # from [0, args[0])
465 v = args[0] + v*(args[1]-args[0]) # from [args[0], args[1])
468 # Code from ai.c begins here
471 "Would this quadrant welcome another Klingon?"
472 return iq.valid_quadrant() and \
473 not game.state.galaxy[iq.i][iq.j].supernova and \
474 game.state.galaxy[iq.i][iq.j].klingons < MAXKLQUAD
476 def tryexit(enemy, look, irun):
477 "A bad guy attempts to bug out."
479 iq.i = game.quadrant.i+(look.i+(QUADSIZE-1))/QUADSIZE - 1
480 iq.j = game.quadrant.j+(look.j+(QUADSIZE-1))/QUADSIZE - 1
481 if not welcoming(iq):
483 if enemy.type == 'R':
484 return False # Romulans cannot escape!
486 # avoid intruding on another commander's territory
487 if enemy.type == 'C':
488 if iq in game.state.kcmdr:
490 # refuse to leave if currently attacking starbase
491 if game.battle == game.quadrant:
493 # don't leave if over 1000 units of energy
494 if enemy.power > 1000.0:
496 oldloc = copy.copy(enemy.location)
497 # handle local matters related to escape
500 if game.condition != "docked":
502 # Handle global matters related to escape
503 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
504 game.state.galaxy[iq.i][iq.j].klingons += 1
505 if enemy.type == 'S':
509 schedule(FSCMOVE, 0.2777)
511 game.state.kscmdr = iq
513 for cmdr in game.state.kcmdr:
514 if cmdr == game.quadrant:
515 game.state.kcmdr.append(iq)
517 # report move out of quadrant.
518 return [(True, enemy, oldloc, iq)]
520 # The bad-guy movement algorithm:
522 # 1. Enterprise has "force" based on condition of phaser and photon torpedoes.
523 # If both are operating full strength, force is 1000. If both are damaged,
524 # force is -1000. Having shields down subtracts an additional 1000.
526 # 2. Enemy has forces equal to the energy of the attacker plus
527 # 100*(K+R) + 500*(C+S) - 400 for novice through good levels OR
528 # 346*K + 400*R + 500*(C+S) - 400 for expert and emeritus.
530 # Attacker Initial energy levels (nominal):
531 # Klingon Romulan Commander Super-Commander
532 # Novice 400 700 1200
534 # Good 450 800 1300 1750
535 # Expert 475 850 1350 1875
536 # Emeritus 500 900 1400 2000
537 # VARIANCE 75 200 200 200
539 # Enemy vessels only move prior to their attack. In Novice - Good games
540 # only commanders move. In Expert games, all enemy vessels move if there
541 # is a commander present. In Emeritus games all enemy vessels move.
543 # 3. If Enterprise is not docked, an aggressive action is taken if enemy
544 # forces are 1000 greater than Enterprise.
546 # Agressive action on average cuts the distance between the ship and
547 # the enemy to 1/4 the original.
549 # 4. At lower energy advantage, movement units are proportional to the
550 # advantage with a 650 advantage being to hold ground, 800 to move forward
551 # 1, 950 for two, 150 for back 4, etc. Variance of 100.
553 # If docked, is reduced by roughly 1.75*game.skill, generally forcing a
554 # retreat, especially at high skill levels.
556 # 5. Motion is limited to skill level, except for SC hi-tailing it out.
558 def movebaddy(enemy):
559 "Tactical movement for the bad guys."
563 # This should probably be just (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
564 if game.skill >= SKILL_EXPERT:
565 nbaddys = (((game.quadrant in game.state.kcmdr)*2 + (game.state.kscmdr==game.quadrant)*2+game.klhere*1.23+game.irhere*1.5)/2.0)
567 nbaddys = (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
568 old_dist = enemy.kdist
569 mdist = int(old_dist + 0.5) # Nearest integer distance
570 # If SC, check with spy to see if should hi-tail it
571 if enemy.type == 'S' and \
572 (enemy.power <= 500.0 or (game.condition=="docked" and not damaged(DPHOTON))):
576 # decide whether to advance, retreat, or hold position
577 forces = enemy.power+100.0*len(game.enemies)+400*(nbaddys-1)
579 forces += 1000 # Good for enemy if shield is down!
580 if not damaged(DPHASER) or not damaged(DPHOTON):
581 if damaged(DPHASER): # phasers damaged
584 forces -= 0.2*(game.energy - 2500.0)
585 if damaged(DPHOTON): # photon torpedoes damaged
588 forces -= 50.0*game.torps
590 # phasers and photon tubes both out!
593 if forces <= 1000.0 and game.condition != "docked": # Typical situation
594 motion = ((forces + randreal(200))/150.0) - 5.0
596 if forces > 1000.0: # Very strong -- move in for kill
597 motion = (1.0 - randreal())**2 * old_dist + 1.0
598 if game.condition == "docked" and (game.options & OPTION_BASE): # protected by base -- back off !
599 motion -= game.skill*(2.0-randreal()**2)
601 proutn("=== MOTION = %d, FORCES = %1.2f, " % (motion, forces))
602 # don't move if no motion
605 # Limit motion according to skill
606 if abs(motion) > game.skill:
611 # calculate preferred number of steps
612 nsteps = abs(int(motion))
613 if motion > 0 and nsteps > mdist:
614 nsteps = mdist # don't overshoot
615 if nsteps > QUADSIZE:
616 nsteps = QUADSIZE # This shouldn't be necessary
618 nsteps = 1 # This shouldn't be necessary
620 proutn("NSTEPS = %d:" % nsteps)
621 # Compute preferred values of delta X and Y
622 m = game.sector - enemy.location
623 if 2.0 * abs(m.i) < abs(m.j):
625 if 2.0 * abs(m.j) < abs(game.sector.i-enemy.location.i):
627 m = (motion * m).sgn()
628 goto = enemy.location
630 for ll in range(nsteps):
632 proutn(" %d" % (ll+1))
633 # Check if preferred position available
644 attempts = 0 # Settle mysterious hang problem
645 while attempts < 20 and not success:
647 if look.i < 0 or look.i >= QUADSIZE:
649 return tryexit(enemy, look, irun)
650 if krawli == m.i or m.j == 0:
652 look.i = goto.i + krawli
654 elif look.j < 0 or look.j >= QUADSIZE:
656 return tryexit(enemy, look, irun)
657 if krawlj == m.j or m.i == 0:
659 look.j = goto.j + krawlj
661 elif (game.options & OPTION_RAMMING) and game.quad[look.i][look.j] != '.':
662 # See if enemy should ram ship
663 if game.quad[look.i][look.j] == game.ship and \
664 (enemy.type == 'C' or enemy.type == 'S'):
665 collision(rammed=True, enemy=enemy)
667 if krawli != m.i and m.j != 0:
668 look.i = goto.i + krawli
670 elif krawlj != m.j and m.i != 0:
671 look.j = goto.j + krawlj
674 break # we have failed
685 # Enemy moved, but is still in sector
686 return [(False, enemy, old_dist, goto)]
689 "Sequence Klingon tactical movement."
692 # Figure out which Klingon is the commander (or Supercommander)
695 if game.quadrant in game.state.kcmdr:
696 for enemy in game.enemies:
697 if enemy.type == 'C':
698 tacmoves += movebaddy(enemy)
699 if game.state.kscmdr == game.quadrant:
700 for enemy in game.enemies:
701 if enemy.type == 'S':
702 tacmoves += movebaddy(enemy)
704 # If skill level is high, move other Klingons and Romulans too!
705 # Move these last so they can base their actions on what the
707 if game.skill >= SKILL_EXPERT and (game.options & OPTION_MVBADDY):
708 for enemy in game.enemies:
709 if enemy.type in ('K', 'R'):
710 tacmoves += movebaddy(enemy)
713 def movescom(iq, avoid):
714 "Supercommander movement helper."
715 # Avoid quadrants with bases if we want to avoid Enterprise
716 if not welcoming(iq) or (avoid and iq in game.state.baseq):
718 if game.justin and not game.iscate:
721 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons -= 1
722 game.state.kscmdr = iq
723 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons += 1
724 if game.state.kscmdr == game.quadrant:
725 # SC has scooted, remove him from current quadrant
730 for enemy in game.enemies:
731 if enemy.type == 'S':
734 if game.condition != "docked":
737 # check for a helpful planet
738 for i in range(game.inplan):
739 if game.state.planets[i].quadrant == game.state.kscmdr and \
740 game.state.planets[i].crystals == "present":
742 game.state.planets[i].pclass = "destroyed"
743 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].planet = None
746 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
747 proutn(_(" a planet in Quadrant %s has been destroyed") % game.state.kscmdr)
748 prout(_(" by the Super-commander.\""))
750 return True # looks good!
752 def supercommander():
753 "Move the Super Commander."
760 prout("== SUPERCOMMANDER")
761 # Decide on being active or passive
762 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 \
763 (game.state.date-game.indate) < 3.0)
764 if not game.iscate and avoid:
765 # compute move away from Enterprise
766 idelta = game.state.kscmdr-game.quadrant
767 if idelta.distance() > 2.0:
769 idelta.i = game.state.kscmdr.j-game.quadrant.j
770 idelta.j = game.quadrant.i-game.state.kscmdr.i
772 # compute distances to starbases
773 if not game.state.baseq:
777 sc = game.state.kscmdr
778 for (i, base) in enumerate(game.state.baseq):
779 basetbl.append((i, (base - sc).distance()))
780 if game.state.baseq > 1:
781 basetbl.sort(key=lambda x: x[1])
782 # look for nearest base without a commander, no Enterprise, and
783 # without too many Klingons, and not already under attack.
784 ifindit = iwhichb = 0
785 for (i2, base) in enumerate(game.state.baseq):
786 i = basetbl[i2][0] # bug in original had it not finding nearest
787 if base == game.quadrant or base == game.battle or not welcoming(base):
789 # if there is a commander, and no other base is appropriate,
790 # we will take the one with the commander
791 for cmdr in game.state.kcmdr:
792 if base == cmdr and ifindit != 2:
796 else: # no commander -- use this one
801 return # Nothing suitable -- wait until next time
802 ibq = game.state.baseq[iwhichb]
803 # decide how to move toward base
804 idelta = ibq - game.state.kscmdr
805 # Maximum movement is 1 quadrant in either or both axes
806 idelta = idelta.sgn()
807 # try moving in both x and y directions
808 # there was what looked like a bug in the Almy C code here,
809 # but it might be this translation is just wrong.
810 iq = game.state.kscmdr + idelta
811 if not movescom(iq, avoid):
812 # failed -- try some other maneuvers
813 if idelta.i == 0 or idelta.j == 0:
816 iq.j = game.state.kscmdr.j + 1
817 if not movescom(iq, avoid):
818 iq.j = game.state.kscmdr.j - 1
821 iq.i = game.state.kscmdr.i + 1
822 if not movescom(iq, avoid):
823 iq.i = game.state.kscmdr.i - 1
826 # try moving just in x or y
827 iq.j = game.state.kscmdr.j
828 if not movescom(iq, avoid):
829 iq.j = game.state.kscmdr.j + idelta.j
830 iq.i = game.state.kscmdr.i
833 if len(game.state.baseq) == 0:
836 for ibq in game.state.baseq:
837 if ibq == game.state.kscmdr and game.state.kscmdr == game.battle:
840 return # no, don't attack base!
843 schedule(FSCDBAS, randreal(1.0, 3.0))
844 if is_scheduled(FCDBAS):
845 postpone(FSCDBAS, scheduled(FCDBAS)-game.state.date)
846 if not communicating():
850 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") \
852 prout(_(" reports that it is under attack from the Klingon Super-commander."))
853 proutn(_(" It can survive until stardate %d.\"") \
854 % int(scheduled(FSCDBAS)))
857 prout(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
861 game.optime = 0.0 # actually finished
863 # Check for intelligence report
864 if not game.idebug and \
866 (not communicating()) or \
867 not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].charted):
870 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
871 proutn(_(" the Super-commander is in Quadrant %s,") % game.state.kscmdr)
876 if not game.tholian or game.justin:
879 if game.tholian.location.i == 0 and game.tholian.location.j == 0:
882 elif game.tholian.location.i == 0 and game.tholian.location.j == QUADSIZE-1:
885 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == QUADSIZE-1:
888 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == 0:
892 # something is wrong!
893 game.tholian.move(None)
894 prout("***Internal error: Tholian in a bad spot.")
896 # do nothing if we are blocked
897 if game.quad[tid.i][tid.j] not in ('.', '#'):
899 here = copy.copy(game.tholian.location)
900 delta = (tid - game.tholian.location).sgn()
902 while here.i != tid.i:
904 if game.quad[here.i][here.j] == '.':
905 game.tholian.move(here)
907 while here.j != tid.j:
909 if game.quad[here.i][here.j] == '.':
910 game.tholian.move(here)
911 # check to see if all holes plugged
912 for i in range(QUADSIZE):
913 if game.quad[0][i] != '#' and game.quad[0][i] != 'T':
915 if game.quad[QUADSIZE-1][i] != '#' and game.quad[QUADSIZE-1][i] != 'T':
917 if game.quad[i][0] != '#' and game.quad[i][0] != 'T':
919 if game.quad[i][QUADSIZE-1] != '#' and game.quad[i][QUADSIZE-1] != 'T':
921 # All plugged up -- Tholian splits
922 game.quad[game.tholian.location.i][game.tholian.location.j] = '#'
924 prout(crmena(True, 'T', "sector", game.tholian) + _(" completes web."))
925 game.tholian.move(None)
928 # Code from battle.c begins here
931 "Change cloaking-device status."
933 prout(_("Ye Faerie Queene hath no cloaking device."));
936 key = scanner.nexttok()
944 if scanner.sees("on"):
946 prout(_("The cloaking device has already been switched on."))
949 elif scanner.sees("off"):
950 if not game.iscloaked:
951 prout(_("The cloaking device has already been switched off."))
958 if not game.iscloaked:
959 proutn(_("Switch cloaking device on? "))
964 proutn(_("Switch cloaking device off? "))
971 if action == "CLOFF":
972 if game.irhere and game.state.date >= ALGERON and not game.isviolreported:
973 prout(_("Spock- \"Captain, the Treaty of Algeron is in effect.\n Are you sure this is wise?\""))
976 prout("Engineer Scott- \"Aye, Sir.\"");
977 game.iscloaked = False;
978 if game.irhere and game.state.date >= ALGERON and not game.isviolreported:
979 prout(_("The Romulan ship discovers you are breaking the Treaty of Algeron!"))
981 game.isviolreported = True
983 #if (neutz and game.state.date >= ALGERON) finish(FCLOAK);
988 prout(_("Engineer Scott- \"The cloaking device is damaged, Sir.\""))
991 if game.condition == "docked":
992 prout(_("You cannot cloak while docked."))
994 if game.state.date >= ALGERON and not game.isviolreported:
995 prout(_("Spock- \"Captain, using the cloaking device is a violation"))
996 prout(_(" of the Treaty of Algeron. Considering the alternatives,"))
997 proutn(_(" are you sure this is wise? "))
1000 prout(_("Engineer Scott- \"Cloaking device has engaging, Sir...\""))
1002 prout(_("Engineer Scott- \"Cloaking device has engaged, Sir.\""))
1003 game.iscloaked = True
1005 if game.irhere and game.state.date >= ALGERON and not game.isviolreported:
1006 prout(_("The Romulan ship discovers you are breaking the Treaty of Algeron!"))
1008 game.isviolreported = True
1010 def doshield(shraise):
1011 "Change shield status."
1017 key = scanner.nexttok()
1018 if key == "IHALPHA":
1019 if scanner.sees("transfer"):
1022 if damaged(DSHIELD):
1023 prout(_("Shields damaged and down."))
1025 if scanner.sees("up"):
1027 elif scanner.sees("down"):
1029 if action == "NONE":
1030 proutn(_("Do you wish to change shield energy? "))
1033 elif damaged(DSHIELD):
1034 prout(_("Shields damaged and down."))
1037 proutn(_("Shields are up. Do you want them down? "))
1044 proutn(_("Shields are down. Do you want them up? "))
1050 if action == "SHUP": # raise shields
1052 prout(_("Shields already up."))
1056 if game.condition != "docked":
1058 prout(_("Shields raised."))
1059 if game.energy <= 0:
1061 prout(_("Shields raising uses up last of energy."))
1066 elif action == "SHDN":
1068 prout(_("Shields already down."))
1072 prout(_("Shields lowered."))
1075 elif action == "NRG":
1076 while scanner.nexttok() != "IHREAL":
1078 proutn(_("Energy to transfer to shields- "))
1083 if nrg > game.energy:
1084 prout(_("Insufficient ship energy."))
1087 if game.shield+nrg >= game.inshld:
1088 prout(_("Shield energy maximized."))
1089 if game.shield+nrg > game.inshld:
1090 prout(_("Excess energy requested returned to ship energy"))
1091 game.energy -= game.inshld-game.shield
1092 game.shield = game.inshld
1094 if nrg < 0.0 and game.energy-nrg > game.inenrg:
1095 # Prevent shield drain loophole
1097 prout(_("Engineering to bridge--"))
1098 prout(_(" Scott here. Power circuit problem, Captain."))
1099 prout(_(" I can't drain the shields."))
1102 if game.shield+nrg < 0:
1103 prout(_("All shield energy transferred to ship."))
1104 game.energy += game.shield
1107 proutn(_("Scotty- \""))
1109 prout(_("Transferring energy to shields.\""))
1111 prout(_("Draining energy from shields.\""))
1117 "Choose a device to damage, at random."
1119 105, # DSRSENS: short range scanners 10.5%
1120 105, # DLRSENS: long range scanners 10.5%
1121 120, # DPHASER: phasers 12.0%
1122 120, # DPHOTON: photon torpedoes 12.0%
1123 25, # DLIFSUP: life support 2.5%
1124 65, # DWARPEN: warp drive 6.5%
1125 70, # DIMPULS: impulse engines 6.5%
1126 135, # DSHIELD: deflector shields 13.5%
1127 30, # DRADIO: subspace radio 3.0%
1128 45, # DSHUTTL: shuttle 4.5%
1129 15, # DCOMPTR: computer 1.5%
1130 20, # NAVCOMP: navigation system 2.0%
1131 75, # DTRANSP: transporter 7.5%
1132 20, # DSHCTRL: high-speed shield controller 2.0%
1133 10, # DDRAY: death ray 1.0%
1134 30, # DDSP: deep-space probes 3.0%
1135 10, # DCLOAK: the cloaking device 1.0
1137 assert(sum(weights) == 1000)
1138 idx = randrange(1000)
1140 for (i, w) in enumerate(weights):
1144 return None # we should never get here
1146 def collision(rammed, enemy):
1147 "Collision handling for rammong events."
1148 prouts(_("***RED ALERT! RED ALERT!"))
1150 prout(_("***COLLISION IMMINENT."))
1154 hardness = {'R':1.5, 'C':2.0, 'S':2.5, 'T':0.5, '?':4.0}.get(enemy.type, 1.0)
1156 proutn(_(" rammed by "))
1159 proutn(crmena(False, enemy.type, "sector", enemy.location))
1161 proutn(_(" (original position)"))
1163 deadkl(enemy.location, enemy.type, game.sector)
1164 proutn("***" + crmshp() + " heavily damaged.")
1165 icas = randrange(10, 30)
1166 prout(_("***Sickbay reports %d casualties") % icas)
1168 game.state.crew -= icas
1169 # In the pre-SST2K version, all devices got equiprobably damaged,
1170 # which was silly. Instead, pick up to half the devices at
1171 # random according to our weighting table,
1172 ncrits = randrange(NDEVICES/2)
1176 if game.damage[dev] < 0:
1178 extradm = (10.0*hardness*randreal()+1.0)*game.damfac
1179 # Damage for at least time of travel!
1180 game.damage[dev] += game.optime + extradm
1182 prout(_("***Shields are down."))
1183 if game.state.remkl + len(game.state.kcmdr) + game.state.nscrem:
1190 def torpedo(origin, bearing, dispersion, number, nburst):
1191 "Let a photon torpedo fly"
1192 if not damaged(DSRSENS) or game.condition == "docked":
1193 setwnd(srscan_window)
1195 setwnd(message_window)
1196 ac = bearing + 0.25*dispersion # dispersion is a random variable
1197 bullseye = (15.0 - bearing)*0.5235988
1198 track = course(bearing=ac, distance=QUADSIZE, origin=cartesian(origin))
1199 bumpto = Coord(0, 0)
1200 # Loop to move a single torpedo
1201 setwnd(message_window)
1202 for step in range(1, QUADSIZE*2):
1203 if not track.nexttok():
1206 if not w.valid_sector():
1208 iquad = game.quad[w.i][w.j]
1209 tracktorpedo(w, step, number, nburst, iquad)
1213 setwnd(message_window)
1214 if not damaged(DSRSENS) or game.condition == "docked":
1215 skip(1) # start new line after text track
1216 if iquad in ('E', 'F'): # Hit our ship
1218 prout(_("Torpedo hits %s.") % crmshp())
1219 hit = 700.0 + randreal(100) - \
1220 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1221 newcnd() # we're blown out of dock
1222 if game.landed or game.condition == "docked":
1223 return hit # Cheat if on a planet
1224 # In the C/FORTRAN version, dispersion was 2.5 radians, which
1225 # is 143 degrees, which is almost exactly 4.8 clockface units
1226 displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
1227 displacement.nexttok()
1228 bumpto = displacement.sector()
1229 if not bumpto.valid_sector():
1231 if game.quad[bumpto.i][bumpto.j] == ' ':
1234 if game.quad[bumpto.i][bumpto.j] != '.':
1235 # can't move into object
1237 game.sector = bumpto
1239 game.quad[w.i][w.j] = '.'
1240 game.quad[bumpto.i][bumpto.j] = iquad
1241 prout(_(" displaced by blast to Sector %s ") % bumpto)
1242 for enemy in game.enemies:
1243 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1246 elif iquad in ('C', 'S', 'R', 'K'): # Hit a regular enemy
1248 if iquad in ('C', 'S') and withprob(0.05):
1249 prout(crmena(True, iquad, "sector", w) + _(" uses anti-photon device;"))
1250 prout(_(" torpedo neutralized."))
1252 for enemy in game.enemies:
1253 if w == enemy.location:
1254 kp = math.fabs(enemy.power)
1255 h1 = 700.0 + randrange(100) - \
1256 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1264 if enemy.power == 0:
1267 proutn(crmena(True, iquad, "sector", w))
1268 displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
1269 displacement.nexttok()
1270 bumpto = displacement.sector()
1271 if not bumpto.valid_sector():
1272 prout(_(" damaged but not destroyed."))
1274 if game.quad[bumpto.i][bumpto.j] == ' ':
1275 prout(_(" buffeted into black hole."))
1276 deadkl(w, iquad, bumpto)
1277 if game.quad[bumpto.i][bumpto.j] != '.':
1278 prout(_(" damaged but not destroyed."))
1280 prout(_(" damaged-- displaced by blast to Sector %s ")%bumpto)
1281 enemy.location = bumpto
1282 game.quad[w.i][w.j] = '.'
1283 game.quad[bumpto.i][bumpto.j] = iquad
1284 for enemy in game.enemies:
1285 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1289 prout("Internal error, no enemy where expected!")
1292 elif iquad == 'B': # Hit a base
1294 prout(_("***STARBASE DESTROYED.."))
1295 game.state.baseq = [x for x in game.state.baseq if x != game.quadrant]
1296 game.quad[w.i][w.j] = '.'
1297 game.base.invalidate()
1298 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
1299 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = False
1300 game.state.basekl += 1
1303 elif iquad == 'P': # Hit a planet
1304 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1305 game.state.nplankl += 1
1306 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1307 game.iplnet.pclass = "destroyed"
1309 game.plnet.invalidate()
1310 game.quad[w.i][w.j] = '.'
1312 # captain perishes on planet
1315 elif iquad == '@': # Hit an inhabited world -- very bad!
1316 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1317 game.state.nworldkl += 1
1318 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1319 game.iplnet.pclass = "destroyed"
1321 game.plnet.invalidate()
1322 game.quad[w.i][w.j] = '.'
1324 # captain perishes on planet
1326 prout(_("The torpedo destroyed an inhabited planet."))
1328 elif iquad == '*': # Hit a star
1332 prout(crmena(True, '*', "sector", w) + _(" unaffected by photon blast."))
1334 elif iquad == '?': # Hit a thingy
1335 if not (game.options & OPTION_THINGY) or withprob(0.3):
1337 prouts(_("AAAAIIIIEEEEEEEEAAAAAAAAUUUUUGGGGGHHHHHHHHHHHH!!!"))
1339 prouts(_(" HACK! HACK! HACK! *CHOKE!* "))
1341 proutn(_("Mr. Spock-"))
1342 prouts(_(" \"Fascinating!\""))
1346 # Stas Sergeev added the possibility that
1347 # you can shove the Thingy and piss it off.
1348 # It then becomes an enemy and may fire at you.
1351 elif iquad == ' ': # Black hole
1353 prout(crmena(True, ' ', "sector", w) + _(" swallows torpedo."))
1355 elif iquad == '#': # hit the web
1357 prout(_("***Torpedo absorbed by Tholian web."))
1359 elif iquad == 'T': # Hit a Tholian
1360 h1 = 700.0 + randrange(100) - \
1361 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1364 game.quad[w.i][w.j] = '.'
1369 proutn(crmena(True, 'T', "sector", w))
1371 prout(_(" survives photon blast."))
1373 prout(_(" disappears."))
1374 game.tholian.move(None)
1375 game.quad[w.i][w.j] = '#'
1380 proutn("Don't know how to handle torpedo collision with ")
1381 proutn(crmena(True, iquad, "sector", w))
1386 setwnd(message_window)
1387 prout(_("Torpedo missed."))
1391 "Critical-hit resolution."
1392 if hit < (275.0-25.0*game.skill)*randreal(1.0, 1.5):
1394 ncrit = int(1.0 + hit/(500.0+randreal(100)))
1395 proutn(_("***CRITICAL HIT--"))
1396 # Select devices and cause damage
1401 # Cheat to prevent shuttle damage unless on ship
1402 if not (game.damage[j]<0.0 or (j == DSHUTTL and game.iscraft != "onship") or (j == DCLOAK and game.ship != 'E' or j == DDRAY)):
1405 extradm = (hit*game.damfac)/(ncrit*randreal(75, 100))
1406 game.damage[j] += extradm
1409 for (i, j) in enumerate(cdam):
1411 if skipcount % 3 == 2 and i < len(cdam)-1:
1416 prout(_(" damaged."))
1417 if damaged(DSHIELD) and game.shldup:
1418 prout(_("***Shields knocked down."))
1420 if damaged(DCLOAK) and game.iscloaked:
1421 prout(_("***Cloaking device rendered inoperative."))
1422 game.iscloaked = False
1424 def attack(torps_ok):
1425 # bad guy attacks us
1426 # torps_ok == False forces use of phasers in an attack
1429 # game could be over at this point, check
1439 prout("=== ATTACK!")
1440 # Tholian gets to move before attacking
1443 # if you have just entered the RNZ, you'll get a warning
1444 if game.neutz: # The one chance not to be attacked
1447 # commanders get a chance to tac-move towards you
1448 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:
1449 for (bugout, enemy, old, goto) in moveklings():
1451 # we know about this if either short or long range
1452 # sensors are working
1453 if damaged(DSRSENS) and damaged(DLRSENS) \
1454 and game.condition != "docked":
1455 prout(crmena(True, enemy.type, "sector", old) + \
1456 (_(" escapes to Quadrant %s (and regains strength).") % goto))
1457 else: # Enemy still in-sector
1458 if enemy.move(goto):
1459 if not damaged(DSRSENS) or game.condition == "docked":
1460 proutn(_("*** %s from Sector %s") % (cramen(enemy.type), enemy.location))
1461 if enemy.kdist < old:
1462 proutn(_(" advances to "))
1464 proutn(_(" retreats to "))
1465 prout("Sector %s." % goto)
1467 # if no enemies remain after movement, we're done
1468 if len(game.enemies) == 0 or (len(game.enemies) == 1 and thing.at(game.quadrant) and not thing.angered):
1470 # set up partial hits if attack happens during shield status change
1471 pfac = 1.0/game.inshld
1473 chgfac = 0.25 + randreal(0.5)
1475 # message verbosity control
1476 if game.skill <= SKILL_FAIR:
1478 for enemy in game.enemies:
1480 continue # too weak to attack
1481 # compute hit strength and diminish shield power
1483 # Increase chance of photon torpedos if docked or enemy energy is low
1484 if game.condition == "docked":
1486 if enemy.power < 500:
1488 if enemy.type == 'T' or (enemy.type == '?' and not thing.angered):
1490 # different enemies have different probabilities of throwing a torp
1491 usephasers = not torps_ok or \
1492 (enemy.type == 'K' and r > 0.0005) or \
1493 (enemy.type == 'C' and r > 0.015) or \
1494 (enemy.type == 'R' and r > 0.3) or \
1495 (enemy.type == 'S' and r > 0.07) or \
1496 (enemy.type == '?' and r > 0.05)
1497 if usephasers: # Enemy uses phasers
1498 if game.condition == "docked":
1499 continue # Don't waste the effort!
1500 attempt = True # Attempt to attack
1501 dustfac = randreal(0.8, 0.85)
1502 hit = enemy.power*math.pow(dustfac, enemy.kavgd)
1504 else: # Enemy uses photon torpedo
1505 # We should be able to make the bearing() method work here
1506 pcourse = 1.90985*math.atan2(game.sector.j-enemy.location.j, enemy.location.i-game.sector.i)
1508 proutn(_("***TORPEDO INCOMING"))
1509 if not damaged(DSRSENS):
1510 proutn(_(" From ") + crmena(False, enemy.type, where, enemy.location))
1513 dispersion = (randreal()+randreal())*0.5 - 0.5
1514 dispersion += 0.002*enemy.power*dispersion
1515 hit = torpedo(enemy.location, pcourse, dispersion, number=1, nburst=1)
1516 if game.unwon() == 0:
1517 finish(FWON) # Klingons did themselves in!
1518 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.alldone:
1519 return # Supernova or finished
1522 # incoming phaser or torpedo, shields may dissipate it
1523 if game.shldup or game.shldchg or game.condition == "docked":
1524 # shields will take hits
1525 propor = pfac * game.shield
1526 if game.condition == "docked":
1530 hitsh = propor*chgfac*hit+1.0
1532 if absorb > game.shield:
1533 absorb = game.shield
1534 game.shield -= absorb
1536 # taking a hit blasts us out of a starbase dock
1537 if game.condition == "docked":
1539 # but the shields may take care of it
1540 if propor > 0.1 and hit < 0.005*game.energy:
1542 # hit from this opponent got through shields, so take damage
1544 proutn(_("%d unit hit") % int(hit))
1545 if (damaged(DSRSENS) and usephasers) or game.skill<=SKILL_FAIR:
1546 proutn(_(" on the ") + crmshp())
1547 if not damaged(DSRSENS) and usephasers:
1548 prout(_(" from ") + crmena(False, enemy.type, where, enemy.location))
1550 # Decide if hit is critical
1556 if game.energy <= 0:
1557 # Returning home upon your shield, not with it...
1560 if not attempt and game.condition == "docked":
1561 prout(_("***Enemies decide against attacking your ship."))
1562 percent = 100.0*pfac*game.shield+0.5
1564 # Shields fully protect ship
1565 proutn(_("Enemy attack reduces shield strength to "))
1567 # Emit message if starship suffered hit(s)
1569 proutn(_("Energy left %2d shields ") % int(game.energy))
1572 elif not damaged(DSHIELD):
1575 proutn(_("damaged, "))
1576 prout(_("%d%%, torpedoes left %d") % (percent, game.torps))
1577 # Check if anyone was hurt
1578 if hitmax >= 200 or hittot >= 500:
1579 icas = randrange(int(hittot * 0.015))
1582 prout(_("Mc Coy- \"Sickbay to bridge. We suffered %d casualties") % icas)
1583 prout(_(" in that last attack.\""))
1585 game.state.crew -= icas
1586 # After attack, reset average distance to enemies
1587 for enemy in game.enemies:
1588 enemy.kavgd = enemy.kdist
1592 def deadkl(w, etype, mv):
1593 "Kill a Klingon, Tholian, Romulan, or Thingy."
1594 # Added mv to allow enemy to "move" before dying
1595 proutn(crmena(True, etype, "sector", mv))
1596 # Decide what kind of enemy it is and update appropriately
1598 # Chalk up a Romulan
1599 game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans -= 1
1601 game.state.nromrem -= 1
1610 # Killed some type of Klingon
1611 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
1614 game.state.kcmdr.remove(game.quadrant)
1616 if game.state.kcmdr:
1617 schedule(FTBEAM, expran(1.0*game.incom/len(game.state.kcmdr)))
1618 if is_scheduled(FCDBAS) and game.battle == game.quadrant:
1621 game.state.remkl -= 1
1623 game.state.nscrem -= 1
1624 game.state.kscmdr.invalidate()
1629 # For each kind of enemy, finish message to player
1630 prout(_(" destroyed."))
1631 if game.unwon() == 0:
1634 # Remove enemy ship from arrays describing local conditions
1635 for e in game.enemies:
1642 "Return None if target is invalid, otherwise return a course angle."
1643 if not w.valid_sector():
1647 # C code this was translated from is wacky -- why the sign reversal?
1648 delta.j = (w.j - game.sector.j)
1649 delta.i = (game.sector.i - w.i)
1650 if delta == Coord(0, 0):
1652 prout(_("Spock- \"Bridge to sickbay. Dr. McCoy,"))
1653 prout(_(" I recommend an immediate review of"))
1654 prout(_(" the Captain's psychological profile.\""))
1657 return delta.bearing()
1660 "Launch photon torpedo salvo."
1663 if damaged(DPHOTON):
1664 prout(_("Photon tubes damaged."))
1668 prout(_("No torpedoes left."))
1671 # First, get torpedo count
1674 if scanner.token == "IHALPHA":
1677 elif scanner.token == "IHEOL" or not scanner.waiting():
1678 prout(_("%d torpedoes left.") % game.torps)
1680 proutn(_("Number of torpedoes to fire- "))
1681 continue # Go back around to get a number
1682 else: # key == "IHREAL"
1684 if n <= 0: # abort command
1689 prout(_("Maximum of %d torpedoes per burst.") % MAXBURST)
1692 scanner.chew() # User requested more torps than available
1693 continue # Go back around
1694 break # All is good, go to next stage
1698 key = scanner.nexttok()
1699 if i == 0 and key == "IHEOL":
1700 break # no coordinate waiting, we will try prompting
1701 if i == 1 and key == "IHEOL":
1702 # direct all torpedoes at one target
1704 target.append(target[0])
1705 tcourse.append(tcourse[0])
1708 scanner.push(scanner.token)
1709 target.append(scanner.getcoord())
1710 if target[-1] is None:
1712 tcourse.append(targetcheck(target[-1]))
1713 if tcourse[-1] is None:
1716 if len(target) == 0:
1717 # prompt for each one
1719 proutn(_("Target sector for torpedo number %d- ") % (i+1))
1721 target.append(scanner.getcoord())
1722 if target[-1] is None:
1724 tcourse.append(targetcheck(target[-1]))
1725 if tcourse[-1] is None:
1728 # Loop for moving <n> torpedoes
1730 if game.condition != "docked":
1732 dispersion = (randreal()+randreal())*0.5 -0.5
1733 if math.fabs(dispersion) >= 0.47:
1735 dispersion *= randreal(1.2, 2.2)
1737 prouts(_("***TORPEDO NUMBER %d MISFIRES") % (i+1))
1739 prouts(_("***TORPEDO MISFIRES."))
1742 prout(_(" Remainder of burst aborted."))
1744 prout(_("***Photon tubes damaged by misfire."))
1745 game.damage[DPHOTON] = game.damfac * randreal(1.0, 3.0)
1749 elif game.shldup or game.condition == "docked":
1750 dispersion *= 1.0 + 0.0001*game.shield
1751 torpedo(game.sector, tcourse[i], dispersion, number=i, nburst=n)
1752 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
1758 "Check for phasers overheating."
1760 checkburn = (rpow-1500.0)*0.00038
1761 if withprob(checkburn):
1762 prout(_("Weapons officer Sulu- \"Phasers overheated, sir.\""))
1763 game.damage[DPHASER] = game.damfac* randreal(1.0, 2.0) * (1.0+checkburn)
1765 def checkshctrl(rpow):
1766 "Check shield control."
1769 prout(_("Shields lowered."))
1771 # Something bad has happened
1772 prouts(_("***RED ALERT! RED ALERT!"))
1774 hit = rpow*game.shield/game.inshld
1775 game.energy -= rpow+hit*0.8
1776 game.shield -= hit*0.2
1777 if game.energy <= 0.0:
1778 prouts(_("Sulu- \"Captain! Shield malf***********************\""))
1783 prouts(_("Sulu- \"Captain! Shield malfunction! Phaser fire contained!\""))
1785 prout(_("Lt. Uhura- \"Sir, all decks reporting damage.\""))
1786 icas = randrange(int(hit*0.012))
1791 prout(_("McCoy to bridge- \"Severe radiation burns, Jim."))
1792 prout(_(" %d casualties so far.\"") % icas)
1794 game.state.crew -= icas
1796 prout(_("Phaser energy dispersed by shields."))
1797 prout(_("Enemy unaffected."))
1802 "Register a phaser hit on Klingons and Romulans."
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 - start
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 # This is where the ASCII art picture was emitted.
3284 # It got garbled somewhere in the chain of transmission to the Almy version.
3285 # We should restore it if we can find old enough FORTRAN sources.
3287 fp.write(_(" U. S. S. ENTERPRISE\n"))
3288 fp.write("\n\n\n\n")
3289 fp.write(_(" For demonstrating outstanding ability as a starship captain\n"))
3291 fp.write(_(" Starfleet Command bestows to you\n"))
3293 fp.write("%*s%s\n\n" % (nskip, "", winner))
3294 fp.write(_(" the rank of\n\n"))
3295 fp.write(_(" \"Commodore Emeritus\"\n\n"))
3297 if game.skill == SKILL_EXPERT:
3298 fp.write(_(" Expert level\n\n"))
3299 elif game.skill == SKILL_EMERITUS:
3300 fp.write(_("Emeritus level\n\n"))
3302 fp.write(_(" Cheat level\n\n"))
3303 timestring = time.ctime()
3304 fp.write(_(" This day of %.6s %.4s, %.8s\n\n") %
3305 (timestring+4, timestring+20, timestring+11))
3306 fp.write(_(" Your score: %d\n\n") % game.score)
3307 fp.write(_(" Klingons per stardate: %.2f\n") % game.perdate)
3310 # Code from io.c begins here
3312 rows = linecount = 0 # for paging
3315 fullscreen_window = None
3316 srscan_window = None # Short range scan
3317 report_window = None # Report legends for status window
3318 status_window = None # The status window itself
3319 lrscan_window = None # Long range scan
3320 message_window = None # Main window for scrolling text
3321 prompt_window = None # Prompt window at bottom of display
3326 # for some recent versions of python2, the following enables UTF8
3327 # for the older ones we probably need to set C locale, and python3
3328 # has no problems at all
3329 if sys.version_info[0] < 3:
3330 locale.setlocale(locale.LC_ALL, "")
3331 gettext.bindtextdomain("sst", "/usr/local/share/locale")
3332 gettext.textdomain("sst")
3333 if not (game.options & OPTION_CURSES):
3334 ln_env = os.getenv("LINES")
3340 stdscr = curses.initscr()
3344 if game.options & OPTION_COLOR:
3345 curses.start_color()
3346 curses.use_default_colors()
3347 curses.init_pair(curses.COLOR_BLACK, curses.COLOR_BLACK, -1)
3348 curses.init_pair(curses.COLOR_GREEN, curses.COLOR_GREEN, -1)
3349 curses.init_pair(curses.COLOR_RED, curses.COLOR_RED, -1)
3350 curses.init_pair(curses.COLOR_CYAN, curses.COLOR_CYAN, -1)
3351 curses.init_pair(curses.COLOR_WHITE, curses.COLOR_WHITE, -1)
3352 curses.init_pair(curses.COLOR_MAGENTA, curses.COLOR_MAGENTA, -1)
3353 curses.init_pair(curses.COLOR_BLUE, curses.COLOR_BLUE, -1)
3354 curses.init_pair(curses.COLOR_YELLOW, curses.COLOR_YELLOW, -1)
3355 global fullscreen_window, srscan_window, report_window, status_window
3356 global lrscan_window, message_window, prompt_window
3357 (rows, _columns) = stdscr.getmaxyx()
3358 fullscreen_window = stdscr
3359 srscan_window = curses.newwin(12, 25, 0, 0)
3360 report_window = curses.newwin(11, 0, 1, 25)
3361 status_window = curses.newwin(10, 0, 1, 39)
3362 lrscan_window = curses.newwin(5, 0, 0, 64)
3363 message_window = curses.newwin(0, 0, 12, 0)
3364 prompt_window = curses.newwin(1, 0, rows-2, 0)
3365 message_window.scrollok(True)
3366 setwnd(fullscreen_window)
3370 if game.options & OPTION_CURSES:
3371 stdscr.keypad(False)
3377 "Wait for user action -- OK to do nothing if on a TTY"
3378 if game.options & OPTION_CURSES:
3383 prouts(_("[ANNOUNCEMENT ARRIVING...]"))
3387 if game.skill > SKILL_FAIR:
3388 prompt = _("[CONTINUE?]")
3390 prompt = _("[PRESS ENTER TO CONTINUE]")
3392 if game.options & OPTION_CURSES:
3394 setwnd(prompt_window)
3395 prompt_window.clear()
3396 prompt_window.addstr(prompt)
3397 prompt_window.getstr()
3398 prompt_window.clear()
3399 prompt_window.refresh()
3400 setwnd(message_window)
3403 sys.stdout.write('\n')
3407 sys.stdout.write('\n' * rows)
3411 "Skip i lines. Pause game if this would cause a scrolling event."
3412 for _dummy in range(i):
3413 if game.options & OPTION_CURSES:
3414 (y, _x) = curwnd.getyx()
3417 except curses.error:
3422 if rows and linecount >= rows:
3425 sys.stdout.write('\n')
3427 def proutn(proutntline):
3428 "Utter a line with no following line feed."
3429 if game.options & OPTION_CURSES:
3430 (y, x) = curwnd.getyx()
3431 (my, _mx) = curwnd.getmaxyx()
3432 if curwnd == message_window and y >= my - 2:
3435 # Uncomment this to debug curses problems
3437 # logfp.write("#curses: at %s proutn(%s)\n" % ((y, x), repr(proutntline)))
3438 curwnd.addstr(proutntline)
3441 sys.stdout.write(proutntline)
3444 def prout(proutline):
3448 def prouts(proutsline):
3450 for c in proutsline:
3451 if not replayfp or replayfp.closed: # Don't slow down replays
3454 if game.options & OPTION_CURSES:
3458 if not replayfp or replayfp.closed:
3462 "Get a line of input."
3463 if game.options & OPTION_CURSES:
3464 linein = curwnd.getstr() + "\n"
3467 if replayfp and not replayfp.closed:
3469 linein = replayfp.readline()
3472 prout("*** Replay finished")
3475 elif linein[0] != "#":
3479 linein = my_input() + "\n"
3488 "Change windows -- OK for this to be a no-op in tty mode."
3490 if game.options & OPTION_CURSES:
3491 # Uncomment this to debug curses problems
3493 if wnd == fullscreen_window:
3494 legend = "fullscreen"
3495 elif wnd == srscan_window:
3497 elif wnd == report_window:
3499 elif wnd == status_window:
3501 elif wnd == lrscan_window:
3503 elif wnd == message_window:
3505 elif wnd == prompt_window:
3509 logfp.write("#curses: setwnd(%s)\n" % legend)
3511 # Some curses implementations get confused when you try this.
3513 curses.curs_set(wnd in (fullscreen_window, message_window, prompt_window))
3514 except curses.error:
3518 "Clear to end of line -- can be a no-op in tty mode"
3519 if game.options & OPTION_CURSES:
3524 "Clear screen -- can be a no-op in tty mode."
3526 if game.options & OPTION_CURSES:
3532 def textcolor(color=DEFAULT):
3533 if (game.options & OPTION_COLOR) and (game.options & OPTION_CURSES):
3534 if color == DEFAULT:
3536 elif color == BLACK:
3537 curwnd.attron(curses.color_pair(curses.COLOR_BLACK))
3539 curwnd.attron(curses.color_pair(curses.COLOR_BLUE))
3540 elif color == GREEN:
3541 curwnd.attron(curses.color_pair(curses.COLOR_GREEN))
3543 curwnd.attron(curses.color_pair(curses.COLOR_CYAN))
3545 curwnd.attron(curses.color_pair(curses.COLOR_RED))
3546 elif color == MAGENTA:
3547 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA))
3548 elif color == BROWN:
3549 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW))
3550 elif color == LIGHTGRAY:
3551 curwnd.attron(curses.color_pair(curses.COLOR_WHITE))
3552 elif color == DARKGRAY:
3553 curwnd.attron(curses.color_pair(curses.COLOR_BLACK) | curses.A_BOLD)
3554 elif color == LIGHTBLUE:
3555 curwnd.attron(curses.color_pair(curses.COLOR_BLUE) | curses.A_BOLD)
3556 elif color == LIGHTGREEN:
3557 curwnd.attron(curses.color_pair(curses.COLOR_GREEN) | curses.A_BOLD)
3558 elif color == LIGHTCYAN:
3559 curwnd.attron(curses.color_pair(curses.COLOR_CYAN) | curses.A_BOLD)
3560 elif color == LIGHTRED:
3561 curwnd.attron(curses.color_pair(curses.COLOR_RED) | curses.A_BOLD)
3562 elif color == LIGHTMAGENTA:
3563 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA) | curses.A_BOLD)
3564 elif color == YELLOW:
3565 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW) | curses.A_BOLD)
3566 elif color == WHITE:
3567 curwnd.attron(curses.color_pair(curses.COLOR_WHITE) | curses.A_BOLD)
3570 if (game.options & OPTION_COLOR) and (game.options & OPTION_CURSES):
3571 curwnd.attron(curses.A_REVERSE)
3574 # Things past this point have policy implications.
3578 "Hook to be called after moving to redraw maps."
3579 if game.options & OPTION_CURSES:
3582 setwnd(srscan_window)
3586 setwnd(status_window)
3587 status_window.clear()
3588 status_window.move(0, 0)
3589 setwnd(report_window)
3590 report_window.clear()
3591 report_window.move(0, 0)
3593 setwnd(lrscan_window)
3594 lrscan_window.clear()
3595 lrscan_window.move(0, 0)
3596 lrscan(silent=False)
3598 def put_srscan_sym(w, sym):
3599 "Emit symbol for short-range scan."
3600 srscan_window.move(w.i+1, w.j*2+2)
3601 srscan_window.addch(sym)
3602 srscan_window.refresh()
3605 "Enemy fall down, go boom."
3606 if game.options & OPTION_CURSES:
3608 setwnd(srscan_window)
3609 srscan_window.attron(curses.A_REVERSE)
3610 put_srscan_sym(w, game.quad[w.i][w.j])
3614 srscan_window.attroff(curses.A_REVERSE)
3615 put_srscan_sym(w, game.quad[w.i][w.j])
3616 curses.delay_output(500)
3617 setwnd(message_window)
3620 "Sound and visual effects for teleportation."
3621 if game.options & OPTION_CURSES:
3623 setwnd(message_window)
3625 prouts(" . . . . . ")
3626 if game.options & OPTION_CURSES:
3627 #curses.delay_output(1000)
3631 def tracktorpedo(w, step, i, n, iquad):
3632 "Torpedo-track animation."
3633 if not game.options & OPTION_CURSES:
3637 proutn(_("Track for torpedo number %d- ") % (i+1))
3640 proutn(_("Torpedo track- "))
3641 elif step==4 or step==9:
3645 if not damaged(DSRSENS) or game.condition=="docked":
3646 if i != 0 and step == 1:
3649 if (iquad=='.') or (iquad==' '):
3650 put_srscan_sym(w, '+')
3654 put_srscan_sym(w, iquad)
3656 curwnd.attron(curses.A_REVERSE)
3657 put_srscan_sym(w, iquad)
3661 curwnd.attroff(curses.A_REVERSE)
3662 put_srscan_sym(w, iquad)
3667 "Display the current galaxy chart."
3668 if game.options & OPTION_CURSES:
3669 setwnd(message_window)
3670 message_window.clear()
3672 if game.options & OPTION_TTY:
3677 def prstat(txt, data):
3679 if game.options & OPTION_CURSES:
3681 setwnd(status_window)
3683 proutn(" " * (NSYM - len(txt)))
3686 if game.options & OPTION_CURSES:
3687 setwnd(report_window)
3689 # Code from moving.c begins here
3691 def imove(icourse=None, noattack=False):
3692 "Movement execution for warp, impulse, supernova, and tractor-beam events."
3695 def newquadrant(noattack):
3696 # Leaving quadrant -- allow final enemy attack
3697 # Don't set up attack if being pushed by nova or cloaked
3698 if len(game.enemies) != 0 and not noattack and not game.iscloaked:
3700 for enemy in game.enemies:
3701 finald = (w - enemy.location).distance()
3702 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3703 # Stas Sergeev added the condition
3704 # that attacks only happen if Klingons
3705 # are present and your skill is good.
3706 if game.skill > SKILL_GOOD and game.klhere > 0 and not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3707 attack(torps_ok=False)
3710 # check for edge of galaxy
3716 if icourse.final.i < 0:
3717 icourse.final.i = -icourse.final.i
3719 if icourse.final.j < 0:
3720 icourse.final.j = -icourse.final.j
3722 if icourse.final.i >= GALSIZE*QUADSIZE:
3723 icourse.final.i = (GALSIZE*QUADSIZE*2) - icourse.final.i
3725 if icourse.final.j >= GALSIZE*QUADSIZE:
3726 icourse.final.j = (GALSIZE*QUADSIZE*2) - icourse.final.j
3734 if game.nkinks == 3:
3735 # Three strikes -- you're out!
3739 prout(_("YOU HAVE ATTEMPTED TO CROSS THE NEGATIVE ENERGY BARRIER"))
3740 prout(_("AT THE EDGE OF THE GALAXY. THE THIRD TIME YOU TRY THIS,"))
3741 prout(_("YOU WILL BE DESTROYED."))
3742 # Compute final position in new quadrant
3743 if trbeam: # Don't bother if we are to be beamed
3745 game.quadrant = icourse.final.quadrant()
3746 game.sector = icourse.final.sector()
3748 prout(_("Entering Quadrant %s.") % game.quadrant)
3749 game.quad[game.sector.i][game.sector.j] = game.ship
3751 if game.skill>SKILL_NOVICE:
3752 attack(torps_ok=False)
3754 def check_collision(h):
3755 iquad = game.quad[h.i][h.j]
3757 # object encountered in flight path
3758 stopegy = 50.0*icourse.distance/game.optime
3759 if iquad in ('T', 'K', 'C', 'S', 'R', '?'):
3760 for enemy in game.enemies:
3761 if enemy.location == game.sector:
3762 collision(rammed=False, enemy=enemy)
3764 # This should not happen
3765 prout(_("Which way did he go?"))
3769 prouts(_("***RED ALERT! RED ALERT!"))
3771 proutn("***" + crmshp())
3772 proutn(_(" pulled into black hole at Sector %s") % h)
3773 # Getting pulled into a black hole was certain
3774 # death in Almy's original. Stas Sergeev added a
3775 # possibility that you'll get timewarped instead.
3777 for m in range(NDEVICES):
3778 if game.damage[m]>0:
3780 probf=math.pow(1.4,(game.energy+game.shield)/5000.0-1.0)*math.pow(1.3,1.0/(n+1)-1.0)
3781 if (game.options & OPTION_BLKHOLE) and withprob(1-probf):
3791 prout(_(" encounters Tholian web at %s;") % h)
3793 prout(_(" blocked by object at %s;") % h)
3794 proutn(_("Emergency stop required "))
3795 prout(_("%2d units of energy.") % int(stopegy))
3796 game.energy -= stopegy
3797 if game.energy <= 0:
3804 prout(_("Helmsman Sulu- \"Leaving standard orbit.\""))
3805 game.inorbit = False
3806 # If tractor beam is to occur, don't move full distance
3807 if game.state.date+game.optime >= scheduled(FTBEAM):
3809 # We can't be tractor beamed if cloaked,
3810 # so move the event into the future
3811 postpone(FTBEAM, game.optime + expran(1.5*game.intime/len(game.kcmdr)))
3815 game.condition = "red"
3816 icourse.distance = icourse.distance*(scheduled(FTBEAM)-game.state.date)/game.optime + 0.1
3817 game.optime = scheduled(FTBEAM) - game.state.date + 1e-5
3819 game.quad[game.sector.i][game.sector.j] = '.'
3820 for _m in range(icourse.moves):
3822 w = icourse.sector()
3823 if icourse.origin.quadrant() != icourse.location.quadrant():
3824 newquadrant(noattack)
3826 elif check_collision(w):
3827 print("Collision detected")
3831 # We're in destination quadrant -- compute new average enemy distances
3832 game.quad[game.sector.i][game.sector.j] = game.ship
3834 for enemy in game.enemies:
3835 finald = (w-enemy.location).distance()
3836 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3837 enemy.kdist = finald
3839 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3840 attack(torps_ok=False)
3841 for enemy in game.enemies:
3842 enemy.kavgd = enemy.kdist
3845 setwnd(message_window)
3849 "Dock our ship at a starbase."
3851 if game.condition == "docked" and verbose:
3852 prout(_("Already docked."))
3855 prout(_("You must first leave standard orbit."))
3857 if not game.base.is_valid() or abs(game.sector.i-game.base.i) > 1 or abs(game.sector.j-game.base.j) > 1:
3858 prout(crmshp() + _(" not adjacent to base."))
3861 prout(_("You cannot dock while cloaked."))
3863 game.condition = "docked"
3867 if game.energy < game.inenrg:
3868 game.energy = game.inenrg
3869 game.shield = game.inshld
3870 game.torps = game.intorps
3871 game.lsupres = game.inlsr
3872 game.state.crew = FULLCREW
3873 if game.brigcapacity-game.brigfree > 0:
3874 prout(_("%d captured Klingons transferred to base") % (game.brigcapacity-game.brigfree))
3875 game.kcaptured += game.brigcapacity-game.brigfree
3876 game.brigfree = game.brigcapacity
3877 if communicating() and \
3878 ((is_scheduled(FCDBAS) or game.isatb == 1) and not game.iseenit):
3879 # get attack report from base
3880 prout(_("Lt. Uhura- \"Captain, an important message from the starbase:\""))
3884 def cartesian(loc1=None, loc2=None):
3886 return game.quadrant * QUADSIZE + game.sector
3888 return game.quadrant * QUADSIZE + loc1
3890 return loc1 * QUADSIZE + loc2
3892 def getcourse(isprobe):
3893 "Get a course and distance from the user."
3895 dquad = copy.copy(game.quadrant)
3896 navmode = "unspecified"
3900 if game.landed and not isprobe:
3901 prout(_("Dummy! You can't leave standard orbit until you"))
3902 proutn(_("are back aboard the ship."))
3905 while navmode == "unspecified":
3906 if damaged(DNAVSYS):
3908 prout(_("Computer damaged; manual navigation only"))
3910 prout(_("Computer damaged; manual movement only"))
3915 key = scanner.nexttok()
3917 proutn(_("Manual or automatic- "))
3920 elif key == "IHALPHA":
3921 if scanner.sees("manual"):
3923 key = scanner.nexttok()
3925 elif scanner.sees("automatic"):
3926 navmode = "automatic"
3927 key = scanner.nexttok()
3935 prout(_("(Manual navigation assumed.)"))
3937 prout(_("(Manual movement assumed.)"))
3941 if navmode == "automatic":
3942 while key == "IHEOL":
3944 proutn(_("Target quadrant or quadrant§or- "))
3946 proutn(_("Destination sector or quadrant§or- "))
3949 key = scanner.nexttok()
3953 xi = int(round(scanner.real))-1
3954 key = scanner.nexttok()
3958 xj = int(round(scanner.real))-1
3959 key = scanner.nexttok()
3961 # both quadrant and sector specified
3962 xk = int(round(scanner.real))-1
3963 key = scanner.nexttok()
3967 xl = int(round(scanner.real))-1
3973 # only one pair of numbers was specified
3975 # only quadrant specified -- go to center of dest quad
3978 dsect.j = dsect.i = 4 # preserves 1-origin behavior
3980 # only sector specified
3984 if not dquad.valid_quadrant() or not dsect.valid_sector():
3991 prout(_("Helmsman Sulu- \"Course locked in for Sector %s.\"") % dsect)
3993 prout(_("Ensign Chekov- \"Course laid in, Captain.\""))
3994 # the actual deltas get computed here
3995 delta.j = dquad.j-game.quadrant.j + (dsect.j-game.sector.j)/(QUADSIZE*1.0)
3996 delta.i = game.quadrant.i-dquad.i + (game.sector.i-dsect.i)/(QUADSIZE*1.0)
3998 while key == "IHEOL":
3999 proutn(_("X and Y displacements- "))
4002 key = scanner.nexttok()
4005 delta.j = scanner.real
4009 key = scanner.nexttok()
4011 delta.i = scanner.real
4012 elif key == "IHEOL":
4018 # Check for zero movement
4019 if delta.i == 0 and delta.j == 0:
4022 if itemp == "verbose" and not isprobe:
4024 prout(_("Helmsman Sulu- \"Aye, Sir.\""))
4026 return course(bearing=delta.bearing(), distance=delta.distance())
4029 def __init__(self, bearing, distance, origin=None):
4030 self.distance = distance
4031 self.bearing = bearing
4033 self.origin = cartesian(game.quadrant, game.sector)
4035 self.origin = origin
4036 # The bearing() code we inherited from FORTRAN is actually computing
4037 # clockface directions!
4038 if self.bearing < 0.0:
4039 self.bearing += 12.0
4040 self.angle = ((15.0 - self.bearing) * 0.5235988)
4041 self.increment = Coord(-math.sin(self.angle), math.cos(self.angle))
4042 bigger = max(abs(self.increment.i), abs(self.increment.j))
4043 self.increment /= bigger
4044 self.moves = int(round(10*self.distance*bigger))
4046 self.final = (self.location + self.moves*self.increment).roundtogrid()
4047 self.location = self.origin
4048 self.nextlocation = None
4050 self.location = self.origin
4053 return self.location.roundtogrid() == self.final
4055 "Next step on course."
4057 self.nextlocation = self.location + self.increment
4058 samequad = (self.location.quadrant() == self.nextlocation.quadrant())
4059 self.location = self.nextlocation
4062 return self.location.quadrant()
4064 return self.location.sector()
4066 return self.distance*(w**3)*(game.shldup+1)
4068 return 10.0*self.distance/w**2
4071 "Move under impulse power."
4073 if damaged(DIMPULS):
4076 prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
4078 if game.energy > 30.0:
4080 icourse = getcourse(isprobe=False)
4083 power = 20.0 + 100.0*icourse.distance
4086 if power >= game.energy:
4087 # Insufficient power for trip
4089 prout(_("First Officer Spock- \"Captain, the impulse engines"))
4090 prout(_("require 20.0 units to engage, plus 100.0 units per"))
4091 if game.energy > 30:
4092 proutn(_("quadrant. We can go, therefore, a maximum of %d") %
4093 int(0.01 * (game.energy-20.0)-0.05))
4094 prout(_(" quadrants.\""))
4096 prout(_("quadrant. They are, therefore, useless.\""))
4099 # Make sure enough time is left for the trip
4100 game.optime = icourse.distance/0.095
4101 if game.optime >= game.state.remtime:
4102 prout(_("First Officer Spock- \"Captain, our speed under impulse"))
4103 prout(_("power is only 0.95 sectors per stardate. Are you sure"))
4104 proutn(_("we dare spend the time?\" "))
4107 # Activate impulse engines and pay the cost
4108 imove(icourse, noattack=False)
4112 power = 20.0 + 100.0*icourse.distance
4113 game.energy -= power
4114 game.optime = icourse.distance/0.095
4115 if game.energy <= 0:
4119 def warp(wcourse, involuntary):
4120 "ove under warp drive."
4121 blooey = False; twarp = False
4122 if not involuntary: # Not WARPX entry
4127 prout(_("Engineer Scott- \"The warp engines can not be used while cloaked, Sir.\""))
4129 if game.damage[DWARPEN] > 10.0:
4132 prout(_("Engineer Scott- \"The warp engines are damaged, Sir.\""))
4134 if damaged(DWARPEN) and game.warpfac > 4.0:
4137 prout(_("Engineer Scott- \"Sorry, Captain. Until this damage"))
4138 prout(_(" is repaired, I can only give you warp 4.\""))
4140 # Read in course and distance
4143 wcourse = getcourse(isprobe=False)
4146 # Make sure starship has enough energy for the trip
4147 # Note: this formula is slightly different from the C version,
4148 # and lets you skate a bit closer to the edge.
4149 if wcourse.power(game.warpfac) >= game.energy:
4150 # Insufficient power for trip
4153 prout(_("Engineering to bridge--"))
4154 if not game.shldup or 0.5*wcourse.power(game.warpfac) > game.energy:
4155 iwarp = (game.energy/(wcourse.distance+0.05)) ** 0.333333333
4157 prout(_("We can't do it, Captain. We don't have enough energy."))
4159 proutn(_("We don't have enough energy, but we could do it at warp %d") % iwarp)
4162 prout(_("if you'll lower the shields."))
4166 prout(_("We haven't the energy to go that far with the shields up."))
4168 # Make sure enough time is left for the trip
4169 game.optime = wcourse.time(game.warpfac)
4170 if game.optime >= 0.8*game.state.remtime:
4172 prout(_("First Officer Spock- \"Captain, I compute that such"))
4173 proutn(_(" a trip would require approximately %2.0f") %
4174 (100.0*game.optime/game.state.remtime))
4175 prout(_(" percent of our"))
4176 proutn(_(" remaining time. Are you sure this is wise?\" "))
4182 if game.warpfac > 6.0:
4183 # Decide if engine damage will occur
4184 # ESR: Seems wrong. Probability of damage goes *down* with distance?
4185 prob = wcourse.distance*(6.0-game.warpfac)**2/66.666666666
4186 if prob > randreal():
4188 wcourse.distance = randreal(wcourse.distance)
4189 # Decide if time warp will occur
4190 if 0.5*wcourse.distance*math.pow(7.0,game.warpfac-10.0) > randreal():
4192 if game.idebug and game.warpfac==10 and not twarp:
4194 proutn("=== Force time warp? ")
4198 # If time warp or engine damage, check path
4199 # If it is obstructed, don't do warp or damage
4200 look = wcourse.moves
4204 w = wcourse.sector()
4205 if not w.valid_sector():
4207 if game.quad[w.i][w.j] != '.':
4211 # Activate Warp Engines and pay the cost
4212 imove(wcourse, noattack=False)
4215 game.energy -= wcourse.power(game.warpfac)
4216 if game.energy <= 0:
4218 game.optime = wcourse.time(game.warpfac)
4222 game.damage[DWARPEN] = game.damfac * randreal(1.0, 4.0)
4224 prout(_("Engineering to bridge--"))
4225 prout(_(" Scott here. The warp engines are damaged."))
4226 prout(_(" We'll have to reduce speed to warp 4."))
4231 "Change the warp factor."
4233 key=scanner.nexttok()
4237 proutn(_("Warp factor- "))
4241 if game.damage[DWARPEN] > 10.0:
4242 prout(_("Warp engines inoperative."))
4244 if damaged(DWARPEN) and scanner.real > 4.0:
4245 prout(_("Engineer Scott- \"I'm doing my best, Captain,"))
4246 prout(_(" but right now we can only go warp 4.\""))
4248 if scanner.real > 10.0:
4249 prout(_("Helmsman Sulu- \"Our top speed is warp 10, Captain.\""))
4251 if scanner.real < 1.0:
4252 prout(_("Helmsman Sulu- \"We can't go below warp 1, Captain.\""))
4254 oldfac = game.warpfac
4255 game.warpfac = scanner.real
4256 if game.warpfac <= oldfac or game.warpfac <= 6.0:
4257 prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\"") %
4260 if game.warpfac < 8.00:
4261 prout(_("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\""))
4263 if game.warpfac == 10.0:
4264 prout(_("Engineer Scott- \"Aye, Captain, we'll try it.\""))
4266 prout(_("Engineer Scott- \"Aye, Captain, but our engines may not take it.\""))
4270 "Cope with being tossed out of quadrant by supernova or yanked by beam."
4272 # is captain on planet?
4274 if damaged(DTRANSP):
4277 prout(_("Scotty rushes to the transporter controls."))
4279 prout(_("But with the shields up it's hopeless."))
4281 prouts(_("His desperate attempt to rescue you . . ."))
4286 prout(_("SUCCEEDS!"))
4289 proutn(_("The crystals mined were "))
4297 # Check to see if captain in shuttle craft
4302 # Inform captain of attempt to reach safety
4306 prouts(_("***RED ALERT! RED ALERT!"))
4308 proutn(_("The %s has stopped in a quadrant containing") % crmshp())
4309 prouts(_(" a supernova."))
4311 prout(_("***Emergency automatic override attempts to hurl ")+crmshp())
4312 prout(_("safely out of quadrant."))
4313 if not damaged(DRADIO):
4314 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
4315 # Try to use warp engines
4316 if damaged(DWARPEN):
4318 prout(_("Warp engines damaged."))
4321 game.warpfac = randreal(6.0, 8.0)
4322 prout(_("Warp factor set to %d") % int(game.warpfac))
4323 power = 0.75*game.energy
4324 dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1))
4325 dist = max(dist, randreal(math.sqrt(2)))
4326 bugout = course(bearing=randreal(12), distance=dist) # How dumb!
4327 game.optime = bugout.time(game.warpfac)
4329 game.inorbit = False
4330 warp(bugout, involuntary=True)
4332 # This is bad news, we didn't leave quadrant.
4336 prout(_("Insufficient energy to leave quadrant."))
4339 # Repeat if another snova
4340 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
4343 finish(FWON) # Snova killed remaining enemy.
4346 "Let's do the time warp again."
4347 prout(_("***TIME WARP ENTERED."))
4348 if game.state.snap and withprob(0.5):
4350 prout(_("You are traveling backwards in time %d stardates.") %
4351 int(game.state.date-game.snapsht.date))
4352 game.state = game.snapsht
4353 game.state.snap = False
4354 if len(game.state.kcmdr):
4355 schedule(FTBEAM, expran(game.intime/len(game.state.kcmdr)))
4356 schedule(FBATTAK, expran(0.3*game.intime))
4357 schedule(FSNOVA, expran(0.5*game.intime))
4358 # next snapshot will be sooner
4359 schedule(FSNAP, expran(0.25*game.state.remtime))
4361 if game.state.nscrem:
4362 schedule(FSCMOVE, 0.2777)
4366 game.battle.invalidate()
4367 # Make sure Galileo is consistant -- Snapshot may have been taken
4368 # when on planet, which would give us two Galileos!
4370 for l in range(game.inplan):
4371 if game.state.planets[l].known == "shuttle_down":
4373 if game.iscraft == "onship" and game.ship=='E':
4374 prout(_("Chekov- \"Security reports the Galileo has disappeared, Sir!"))
4375 game.iscraft = "offship"
4376 # Likewise, if in the original time the Galileo was abandoned, but
4377 # was on ship earlier, it would have vanished -- let's restore it.
4378 if game.iscraft == "offship" and not gotit and game.damage[DSHUTTL] >= 0.0:
4379 prout(_("Chekov- \"Security reports the Galileo has reappeared in the dock!\""))
4380 game.iscraft = "onship"
4381 # There used to be code to do the actual reconstrction here,
4382 # but the starchart is now part of the snapshotted galaxy state.
4383 prout(_("Spock has reconstructed a correct star chart from memory"))
4385 # Go forward in time
4386 game.optime = expran(0.5*game.intime)
4387 prout(_("You are traveling forward in time %d stardates.") % int(game.optime))
4388 # cheat to make sure no tractor beams occur during time warp
4389 postpone(FTBEAM, game.optime)
4390 game.damage[DRADIO] += game.optime
4392 events() # Stas Sergeev added this -- do pending events
4395 "Launch deep-space probe."
4396 # New code to launch a deep space probe
4397 if game.nprobes == 0:
4400 if game.ship == 'E':
4401 prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\""))
4403 prout(_("Ye Faerie Queene has no deep space probes."))
4408 prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\""))
4410 if is_scheduled(FDSPROB):
4413 if damaged(DRADIO) and game.condition != "docked":
4414 prout(_("Spock- \"Records show the previous probe has not yet"))
4415 prout(_(" reached its destination.\""))
4417 prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""))
4419 key = scanner.nexttok()
4421 if game.nprobes == 1:
4422 prout(_("1 probe left."))
4424 prout(_("%d probes left") % game.nprobes)
4425 proutn(_("Are you sure you want to fire a probe? "))
4428 game.isarmed = False
4429 if key == "IHALPHA" and scanner.token == "armed":
4431 key = scanner.nexttok()
4432 elif key == "IHEOL":
4433 proutn(_("Arm NOVAMAX warhead? "))
4435 elif key == "IHREAL": # first element of course
4436 scanner.push(scanner.token)
4438 game.probe = getcourse(isprobe=True)
4442 schedule(FDSPROB, 0.01) # Time to move one sector
4443 prout(_("Ensign Chekov- \"The deep space probe is launched, Captain.\""))
4448 "Yell for help from nearest starbase."
4449 # There's more than one way to move in this game!
4451 # Test for conditions which prevent calling for help
4452 if game.condition == "docked":
4453 prout(_("Lt. Uhura- \"But Captain, we're already docked.\""))
4456 prout(_("Subspace radio damaged."))
4458 if not game.state.baseq:
4459 prout(_("Lt. Uhura- \"Captain, I'm not getting any response from Starbase.\""))
4462 prout(_("You must be aboard the %s.") % crmshp())
4464 # OK -- call for help from nearest starbase
4467 # There's one in this quadrant
4468 ddist = (game.base - game.sector).distance()
4470 ibq = None # Force base-quadrant game to persist past loop
4472 for ibq in game.state.baseq:
4473 xdist = QUADSIZE * (ibq - game.quadrant).distance()
4477 prout(_("No starbases remain. You are alone in a hostile galaxy."))
4479 # Since starbase not in quadrant, set up new quadrant
4482 # dematerialize starship
4483 game.quad[game.sector.i][game.sector.j]='.'
4484 proutn(_("Starbase in Quadrant %s responds--%s dematerializes") \
4485 % (game.quadrant, crmshp()))
4486 game.sector.invalidate()
4487 for m in range(1, 5+1):
4488 w = game.base.scatter()
4489 if w.valid_sector() and game.quad[w.i][w.j]=='.':
4490 # found one -- finish up
4493 if not game.sector.is_valid():
4494 prout(_("You have been lost in space..."))
4495 finish(FMATERIALIZE)
4497 # Give starbase three chances to rematerialize starship
4498 probf = math.pow((1.0 - math.pow(0.98,ddist)), 0.33333333)
4499 for m in range(1, 3+1):
4500 if m == 1: proutn(_("1st"))
4501 elif m == 2: proutn(_("2nd"))
4502 elif m == 3: proutn(_("3rd"))
4503 proutn(_(" attempt to re-materialize ") + crmshp())
4504 game.quad[game.sector.i][game.sector.j]=('-','o','O')[m-1]
4507 if randreal() > probf:
4511 curses.delay_output(500)
4513 game.quad[game.sector.i][game.sector.j]='?'
4516 setwnd(message_window)
4517 finish(FMATERIALIZE)
4519 game.quad[game.sector.i][game.sector.j]=game.ship
4521 prout(_("succeeds."))
4525 prout(_("Lt. Uhura- \"Captain, we made it!\""))
4530 if game.condition=="docked":
4532 prout(_("You cannot abandon Ye Faerie Queene."))
4535 # Must take shuttle craft to exit
4536 if game.damage[DSHUTTL]==-1:
4537 prout(_("Ye Faerie Queene has no shuttle craft."))
4539 if game.damage[DSHUTTL]<0:
4540 prout(_("Shuttle craft now serving Big Macs."))
4542 if game.damage[DSHUTTL]>0:
4543 prout(_("Shuttle craft damaged."))
4546 prout(_("You must be aboard the ship."))
4548 if game.iscraft != "onship":
4549 prout(_("Shuttle craft not currently available."))
4551 # Emit abandon ship messages
4553 prouts(_("***ABANDON SHIP! ABANDON SHIP!"))
4555 prouts(_("***ALL HANDS ABANDON SHIP!"))
4557 prout(_("Captain and crew escape in shuttle craft."))
4558 if not game.state.baseq:
4559 # Oops! no place to go...
4562 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
4564 if not (game.options & OPTION_WORLDS) and not damaged(DTRANSP):
4565 prout(_("Remainder of ship's complement beam down"))
4566 prout(_("to nearest habitable planet."))
4567 elif q.planet != None and not damaged(DTRANSP):
4568 prout(_("Remainder of ship's complement beam down to %s.") %
4571 prout(_("Entire crew of %d left to die in outer space.") %
4573 game.casual += game.state.crew
4574 game.abandoned += game.state.crew
4575 # If at least one base left, give 'em the Faerie Queene
4577 game.icrystl = False # crystals are lost
4578 game.nprobes = 0 # No probes
4579 prout(_("You are captured by Klingons and released to"))
4580 prout(_("the Federation in a prisoner-of-war exchange."))
4581 nb = randrange(len(game.state.baseq))
4582 # Set up quadrant and position FQ adjacient to base
4583 if not game.quadrant == game.state.baseq[nb]:
4584 game.quadrant = game.state.baseq[nb]
4585 game.sector.i = game.sector.j = 5
4588 # position next to base by trial and error
4589 game.quad[game.sector.i][game.sector.j] = '.'
4591 for l in range(QUADSIZE):
4592 game.sector = game.base.scatter()
4593 if game.sector.valid_sector() and \
4594 game.quad[game.sector.i][game.sector.j] == '.':
4597 break # found a spot
4598 game.sector.i=QUADSIZE/2
4599 game.sector.j=QUADSIZE/2
4601 # Get new commission
4602 game.quad[game.sector.i][game.sector.j] = game.ship = 'F'
4603 game.state.crew = FULLCREW
4604 prout(_("Starfleet puts you in command of another ship,"))
4605 prout(_("the Faerie Queene, which is antiquated but,"))
4606 prout(_("still useable."))
4608 prout(_("The dilithium crystals have been moved."))
4610 game.iscraft = "offship" # Galileo disappears
4612 game.condition="docked"
4613 for l in range(NDEVICES):
4614 game.damage[l] = 0.0
4615 game.damage[DSHUTTL] = -1
4616 game.energy = game.inenrg = 3000.0
4617 game.shield = game.inshld = 1250.0
4618 game.torps = game.intorps = 6
4619 game.lsupres=game.inlsr=3.0
4622 game.brigfree = game.brigcapacity = 300
4625 # Code from planets.c begins here.
4628 "Abort a lengthy operation if an event interrupts it."
4631 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.justin:
4636 "Report on (uninhabited) planets in the galaxy."
4640 prout(_("Spock- \"Planet report follows, Captain.\""))
4642 for i in range(game.inplan):
4643 if game.state.planets[i].pclass == "destroyed":
4645 if (game.state.planets[i].known != "unknown" \
4646 and not game.state.planets[i].inhabited) \
4649 if game.idebug and game.state.planets[i].known=="unknown":
4650 proutn("(Unknown) ")
4651 proutn(_("Quadrant %s") % game.state.planets[i].quadrant)
4652 proutn(_(" class "))
4653 proutn(game.state.planets[i].pclass)
4655 if game.state.planets[i].crystals != "present":
4657 prout(_("dilithium crystals present."))
4658 if game.state.planets[i].known=="shuttle_down":
4659 prout(_(" Shuttle Craft Galileo on surface."))
4661 prout(_("No information available."))
4664 "Enter standard orbit."
4668 prout(_("Already in standard orbit."))
4670 if damaged(DWARPEN) and damaged(DIMPULS):
4671 prout(_("Both warp and impulse engines damaged."))
4673 if not game.plnet.is_valid():
4674 prout("There is no planet in this sector.")
4676 if abs(game.sector.i-game.plnet.i)>1 or abs(game.sector.j-game.plnet.j)>1:
4677 prout(crmshp() + _(" not adjacent to planet."))
4680 game.optime = randreal(0.02, 0.05)
4681 prout(_("Helmsman Sulu- \"Entering standard orbit, Sir.\""))
4685 game.height = randreal(1400, 8600)
4686 prout(_("Sulu- \"Entered orbit at altitude %.2f kilometers.\"") % game.height)
4691 "Examine planets in this quadrant."
4692 if damaged(DSRSENS):
4693 if game.options & OPTION_TTY:
4694 prout(_("Short range sensors damaged."))
4696 if game.iplnet is None:
4697 if game.options & OPTION_TTY:
4698 prout(_("Spock- \"No planet in this quadrant, Captain.\""))
4700 if game.iplnet.known == "unknown":
4701 prout(_("Spock- \"Sensor scan for Quadrant %s-") % game.quadrant)
4703 prout(_(" Planet at Sector %s is of class %s.") %
4704 (game.plnet, game.iplnet.pclass))
4705 if game.iplnet.known=="shuttle_down":
4706 prout(_(" Sensors show Galileo still on surface."))
4707 proutn(_(" Readings indicate"))
4708 if game.iplnet.crystals != "present":
4710 prout(_(" dilithium crystals present.\""))
4711 if game.iplnet.known == "unknown":
4712 game.iplnet.known = "known"
4713 elif game.iplnet.inhabited:
4714 prout(_("Spock- \"The inhabited planet %s ") % game.iplnet.name)
4715 prout(_(" is located at Sector %s, Captain.\"") % game.plnet)
4718 "Use the transporter."
4722 if damaged(DTRANSP):
4723 prout(_("Transporter damaged."))
4724 if not damaged(DSHUTTL) and (game.iplnet.known=="shuttle_down" or game.iscraft == "onship"):
4726 proutn(_("Spock- \"May I suggest the shuttle craft, Sir?\" "))
4730 if not game.inorbit:
4731 prout(crmshp() + _(" not in standard orbit."))
4734 prout(_("Impossible to transport through shields."))
4736 if game.iplnet.known=="unknown":
4737 prout(_("Spock- \"Captain, we have no information on this planet"))
4738 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4739 prout(_(" you may not go down.\""))
4741 if not game.landed and game.iplnet.crystals=="absent":
4742 prout(_("Spock- \"Captain, I fail to see the logic in"))
4743 prout(_(" exploring a planet with no dilithium crystals."))
4744 proutn(_(" Are you sure this is wise?\" "))
4748 if not (game.options & OPTION_PLAIN):
4749 nrgneed = 50 * game.skill + game.height / 100.0
4750 if nrgneed > game.energy:
4751 prout(_("Engineering to bridge--"))
4752 prout(_(" Captain, we don't have enough energy for transportation."))
4754 if not game.landed and nrgneed * 2 > game.energy:
4755 prout(_("Engineering to bridge--"))
4756 prout(_(" Captain, we have enough energy only to transport you down to"))
4757 prout(_(" the planet, but there wouldn't be an energy for the trip back."))
4758 if game.iplnet.known == "shuttle_down":
4759 prout(_(" Although the Galileo shuttle craft may still be on a surface."))
4760 proutn(_(" Are you sure this is wise?\" "))
4765 # Coming from planet
4766 if game.iplnet.known=="shuttle_down":
4767 proutn(_("Spock- \"Wouldn't you rather take the Galileo?\" "))
4771 prout(_("Your crew hides the Galileo to prevent capture by aliens."))
4772 prout(_("Landing party assembled, ready to beam up."))
4774 prout(_("Kirk whips out communicator..."))
4775 prouts(_("BEEP BEEP BEEP"))
4777 prout(_("\"Kirk to enterprise- Lock on coordinates...energize.\""))
4780 prout(_("Scotty- \"Transporter room ready, Sir.\""))
4782 prout(_("Kirk and landing party prepare to beam down to planet surface."))
4784 prout(_("Kirk- \"Energize.\""))
4787 prouts("WWHOOOIIIIIRRRRREEEE.E.E. . . . . . .")
4789 if not withprob(0.98):
4790 prouts("BOOOIIIOOOIIOOOOIIIOIING . . .")
4792 prout(_("Scotty- \"Oh my God! I've lost them.\""))
4795 prouts(". . . . . . .E.E.EEEERRRRRIIIIIOOOHWW")
4796 game.landed = not game.landed
4797 game.energy -= nrgneed
4799 prout(_("Transport complete."))
4800 if game.landed and game.iplnet.known=="shuttle_down":
4801 prout(_("The shuttle craft Galileo is here!"))
4802 if not game.landed and game.imine:
4809 "Strip-mine a world for dilithium."
4813 prout(_("Mining party not on planet."))
4815 if game.iplnet.crystals == "mined":
4816 prout(_("This planet has already been strip-mined for dilithium."))
4818 elif game.iplnet.crystals == "absent":
4819 prout(_("No dilithium crystals on this planet."))
4822 prout(_("You've already mined enough crystals for this trip."))
4824 if game.icrystl and game.cryprob == 0.05:
4825 prout(_("With all those fresh crystals aboard the ") + crmshp())
4826 prout(_("there's no reason to mine more at this time."))
4828 game.optime = randreal(0.1, 0.3)*(ord(game.iplnet.pclass)-ord("L"))
4831 prout(_("Mining operation complete."))
4832 game.iplnet.crystals = "mined"
4833 game.imine = game.ididit = True
4836 "Use dilithium crystals."
4840 if not game.icrystl:
4841 prout(_("No dilithium crystals available."))
4843 if game.energy >= 1000:
4844 prout(_("Spock- \"Captain, Starfleet Regulations prohibit such an operation"))
4845 prout(_(" except when Condition Yellow exists."))
4847 prout(_("Spock- \"Captain, I must warn you that loading"))
4848 prout(_(" raw dilithium crystals into the ship's power"))
4849 prout(_(" system may risk a severe explosion."))
4850 proutn(_(" Are you sure this is wise?\" "))
4855 prout(_("Engineering Officer Scott- \"(GULP) Aye Sir."))
4856 prout(_(" Mr. Spock and I will try it.\""))
4858 prout(_("Spock- \"Crystals in place, Sir."))
4859 prout(_(" Ready to activate circuit.\""))
4861 prouts(_("Scotty- \"Keep your fingers crossed, Sir!\""))
4863 if withprob(game.cryprob):
4864 prouts(_(" \"Activating now! - - No good! It's***"))
4866 prouts(_("***RED ALERT! RED A*L********************************"))
4869 prouts(_("****************** KA-BOOM!!!! *******************"))
4873 game.energy += randreal(5000.0, 5500.0)
4874 prouts(_(" \"Activating now! - - "))
4875 prout(_("The instruments"))
4876 prout(_(" are going crazy, but I think it's"))
4877 prout(_(" going to work!! Congratulations, Sir!\""))
4882 "Use shuttlecraft for planetary jaunt."
4885 if damaged(DSHUTTL):
4886 if game.damage[DSHUTTL] == -1.0:
4887 if game.inorbit and game.iplnet.known == "shuttle_down":
4888 prout(_("Ye Faerie Queene has no shuttle craft bay to dock it at."))
4890 prout(_("Ye Faerie Queene had no shuttle craft."))
4891 elif game.damage[DSHUTTL] > 0:
4892 prout(_("The Galileo is damaged."))
4893 else: # game.damage[DSHUTTL] < 0
4894 prout(_("Shuttle craft is now serving Big Macs."))
4896 if not game.inorbit:
4897 prout(crmshp() + _(" not in standard orbit."))
4899 if (game.iplnet.known != "shuttle_down") and game.iscraft != "onship":
4900 prout(_("Shuttle craft not currently available."))
4902 if not game.landed and game.iplnet.known=="shuttle_down":
4903 prout(_("You will have to beam down to retrieve the shuttle craft."))
4905 if game.shldup or game.condition == "docked":
4906 prout(_("Shuttle craft cannot pass through shields."))
4908 if game.iplnet.known=="unknown":
4909 prout(_("Spock- \"Captain, we have no information on this planet"))
4910 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4911 prout(_(" you may not fly down.\""))
4913 game.optime = 3.0e-5*game.height
4914 if game.optime >= 0.8*game.state.remtime:
4915 prout(_("First Officer Spock- \"Captain, I compute that such"))
4916 proutn(_(" a maneuver would require approximately %2d%% of our") % \
4917 int(100*game.optime/game.state.remtime))
4918 prout(_("remaining time."))
4919 proutn(_("Are you sure this is wise?\" "))
4925 if game.iscraft == "onship":
4927 if not damaged(DTRANSP):
4928 proutn(_("Spock- \"Would you rather use the transporter?\" "))
4932 proutn(_("Shuttle crew"))
4934 proutn(_("Rescue party"))
4935 prout(_(" boards Galileo and swoops toward planet surface."))
4936 game.iscraft = "offship"
4940 game.iplnet.known="shuttle_down"
4941 prout(_("Trip complete."))
4944 # Ready to go back to ship
4945 prout(_("You and your mining party board the"))
4946 prout(_("shuttle craft for the trip back to the Enterprise."))
4948 prouts(_("The short hop begins . . ."))
4950 game.iplnet.known="known"
4956 game.iscraft = "onship"
4962 prout(_("Trip complete."))
4965 # Kirk on ship and so is Galileo
4966 prout(_("Mining party assembles in the hangar deck,"))
4967 prout(_("ready to board the shuttle craft \"Galileo\"."))
4969 prouts(_("The hangar doors open; the trip begins."))
4972 game.iscraft = "offship"
4975 game.iplnet.known = "shuttle_down"
4978 prout(_("Trip complete."))
4982 "Use the big zapper."
4986 if game.ship != 'E':
4987 prout(_("Ye Faerie Queene has no death ray."))
4989 if len(game.enemies)==0:
4990 prout(_("Sulu- \"But Sir, there are no enemies in this quadrant.\""))
4993 prout(_("Death Ray is damaged."))
4995 prout(_("Spock- \"Captain, the 'Experimental Death Ray'"))
4996 prout(_(" is highly unpredictible. Considering the alternatives,"))
4997 proutn(_(" are you sure this is wise?\" "))
5000 prout(_("Spock- \"Acknowledged.\""))
5003 prouts(_("WHOOEE ... WHOOEE ... WHOOEE ... WHOOEE"))
5005 prout(_("Crew scrambles in emergency preparation."))
5006 prout(_("Spock and Scotty ready the death ray and"))
5007 prout(_("prepare to channel all ship's power to the device."))
5009 prout(_("Spock- \"Preparations complete, sir.\""))
5010 prout(_("Kirk- \"Engage!\""))
5012 prouts(_("WHIRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"))
5015 if game.options & OPTION_PLAIN:
5019 prouts(_("Sulu- \"Captain! It's working!\""))
5021 while len(game.enemies) > 0:
5022 deadkl(game.enemies[1].location, game.quad[game.enemies[1].location.i][game.enemies[1].location.j],game.enemies[1].location)
5023 prout(_("Ensign Chekov- \"Congratulations, Captain!\""))
5024 if game.unwon() == 0:
5026 if (game.options & OPTION_PLAIN) == 0:
5027 prout(_("Spock- \"Captain, I believe the `Experimental Death Ray'"))
5029 prout(_(" is still operational.\""))
5031 prout(_(" has been rendered nonfunctional.\""))
5032 game.damage[DDRAY] = 39.95
5034 r = randreal() # Pick failure method
5036 prouts(_("Sulu- \"Captain! It's working!\""))
5038 prouts(_("***RED ALERT! RED ALERT!"))
5040 prout(_("***MATTER-ANTIMATTER IMPLOSION IMMINENT!"))
5042 prouts(_("***RED ALERT! RED A*L********************************"))
5045 prouts(_("****************** KA-BOOM!!!! *******************"))
5050 prouts(_("Sulu- \"Captain! Yagabandaghangrapl, brachriigringlanbla!\""))
5052 prout(_("Lt. Uhura- \"Graaeek! Graaeek!\""))
5054 prout(_("Spock- \"Fascinating! . . . All humans aboard"))
5055 prout(_(" have apparently been transformed into strange mutations."))
5056 prout(_(" Vulcans do not seem to be affected."))
5058 prout(_("Kirk- \"Raauch! Raauch!\""))
5062 prouts(_("Sulu- \"Captain! It's --WHAT?!?!\""))
5064 proutn(_("Spock- \"I believe the word is"))
5065 prouts(_(" *ASTONISHING*"))
5066 prout(_(" Mr. Sulu."))
5067 for i in range(QUADSIZE):
5068 for j in range(QUADSIZE):
5069 if game.quad[i][j] == '.':
5070 game.quad[i][j] = '?'
5071 prout(_(" Captain, our quadrant is now infested with"))
5072 prouts(_(" - - - - - - *THINGS*."))
5074 prout(_(" I have no logical explanation.\""))
5076 prouts(_("Sulu- \"Captain! The Death Ray is creating tribbles!\""))
5078 prout(_("Scotty- \"There are so many tribbles down here"))
5079 prout(_(" in Engineering, we can't move for 'em, Captain.\""))
5083 # Code from reports.c begins here
5085 def attackreport(curt):
5086 "eport status of bases under attack."
5088 if is_scheduled(FCDBAS):
5089 prout(_("Starbase in Quadrant %s is currently under Commander attack.") % game.battle)
5090 prout(_("It can hold out until Stardate %d.") % int(scheduled(FCDBAS)))
5091 elif game.isatb == 1:
5092 prout(_("Starbase in Quadrant %s is under Super-commander attack.") % game.state.kscmdr)
5093 prout(_("It can hold out until Stardate %d.") % int(scheduled(FSCDBAS)))
5095 prout(_("No Starbase is currently under attack."))
5097 if is_scheduled(FCDBAS):
5098 proutn(_("Base in %s attacked by C. Alive until %.1f") % (game.battle, scheduled(FCDBAS)))
5100 proutn(_("Base in %s attacked by S. Alive until %.1f") % (game.state.kscmdr, scheduled(FSCDBAS)))
5104 # report on general game status
5106 s1 = (game.thawed and _("thawed ")) or ""
5107 s2 = {1:"short", 2:"medium", 4:"long"}[game.length]
5108 s3 = (None, _("novice"), _("fair"),
5109 _("good"), _("expert"), _("emeritus"))[game.skill]
5110 prout(_("You %s a %s%s %s game.") % ((_("were playing"), _("are playing"))[game.alldone], s1, s2, s3))
5111 if game.skill>SKILL_GOOD and game.thawed and not game.alldone:
5112 prout(_("No plaque is allowed."))
5114 prout(_("This is tournament game %d.") % game.tourn)
5115 prout(_("Your secret password is \"%s\"") % game.passwd)
5116 proutn(_("%d of %d Klingons have been killed") % (((game.inkling + game.incom + game.inscom) - game.unwon()),
5117 (game.inkling + game.incom + game.inscom)))
5118 if game.incom - len(game.state.kcmdr):
5119 prout(_(", including %d Commander%s.") % (game.incom - len(game.state.kcmdr), (_("s"), "")[(game.incom - len(game.state.kcmdr))==1]))
5120 elif game.inkling - game.state.remkl + (game.inscom - game.state.nscrem) > 0:
5121 prout(_(", but no Commanders."))
5124 if game.skill > SKILL_FAIR:
5125 prout(_("The Super Commander has %sbeen destroyed.") % ("", _("not "))[game.state.nscrem])
5126 if len(game.state.baseq) != game.inbase:
5128 if game.inbase-len(game.state.baseq)==1:
5129 proutn(_("has been 1 base"))
5131 proutn(_("have been %d bases") % (game.inbase-len(game.state.baseq)))
5132 prout(_(" destroyed, %d remaining.") % len(game.state.baseq))
5134 prout(_("There are %d bases.") % game.inbase)
5135 if communicating() or game.iseenit:
5136 # Don't report this if not seen and
5137 # either the radio is dead or not at base!
5141 prout(_("%d casualt%s suffered so far.") % (game.casual, ("y", "ies")[game.casual!=1]))
5142 if game.brigcapacity != game.brigfree:
5143 embriggened = brigcapacity-brigfree
5144 if embriggened == 1:
5145 prout(_("1 Klingon in brig"))
5147 prout(_("%d Klingons in brig.") % embriggened)
5148 if game.kcaptured == 0:
5150 elif game.kcaptured == 1:
5151 prout(_("1 captured Klingon turned in to Starfleet."))
5153 prout(_("%d captured Klingons turned in to Star Fleet.") % game.kcaptured)
5155 prout(_("There were %d call%s for help.") % (game.nhelp, ("" , _("s"))[game.nhelp!=1]))
5156 if game.ship == 'E':
5157 proutn(_("You have "))
5159 proutn("%d" % (game.nprobes))
5162 proutn(_(" deep space probe"))
5166 if communicating() and is_scheduled(FDSPROB):
5168 proutn(_("An armed deep space probe is in "))
5170 proutn(_("A deep space probe is in "))
5171 prout("Quadrant %s." % game.probe.quadrant())
5173 if game.cryprob <= .05:
5174 prout(_("Dilithium crystals aboard ship... not yet used."))
5178 while game.cryprob > ai:
5181 prout(_("Dilithium crystals have been used %d time%s.") % \
5182 (i, (_("s"), "")[i==1]))
5186 "Long-range sensor scan."
5187 if damaged(DLRSENS):
5188 # Now allow base's sensors if docked
5189 if game.condition != "docked":
5191 prout(_("LONG-RANGE SENSORS DAMAGED."))
5194 prout(_("Starbase's long-range scan"))
5196 prout(_("Long-range scan"))
5197 for x in range(game.quadrant.i-1, game.quadrant.i+2):
5200 for y in range(game.quadrant.j-1, game.quadrant.j+2):
5201 if not Coord(x, y).valid_quadrant():
5205 if not damaged(DRADIO):
5206 game.state.galaxy[x][y].charted = True
5207 game.state.chart[x][y].klingons = game.state.galaxy[x][y].klingons
5208 game.state.chart[x][y].starbase = game.state.galaxy[x][y].starbase
5209 game.state.chart[x][y].stars = game.state.galaxy[x][y].stars
5210 if not silent and game.state.galaxy[x][y].supernova:
5213 proutn(" %3d" % (game.state.chart[x][y].klingons*100 + game.state.chart[x][y].starbase * 10 + game.state.chart[x][y].stars))
5221 for i in range(NDEVICES):
5224 prout(_("\tDEVICE\t\t\t-REPAIR TIMES-"))
5225 prout(_("\t\t\tIN FLIGHT\t\tDOCKED"))
5227 prout(" %-26s\t%8.2f\t\t%8.2f" % (device[i],
5228 game.damage[i]+0.05,
5229 DOCKFAC*game.damage[i]+0.005))
5231 prout(_("All devices functional."))
5234 "Update the chart in the Enterprise's computer from galaxy data."
5235 game.lastchart = game.state.date
5236 for i in range(GALSIZE):
5237 for j in range(GALSIZE):
5238 if game.state.galaxy[i][j].charted:
5239 game.state.chart[i][j].klingons = game.state.galaxy[i][j].klingons
5240 game.state.chart[i][j].starbase = game.state.galaxy[i][j].starbase
5241 game.state.chart[i][j].stars = game.state.galaxy[i][j].stars
5244 "Display the star chart."
5246 if (game.options & OPTION_AUTOSCAN):
5250 if game.lastchart < game.state.date and game.condition == "docked":
5251 prout(_("Spock- \"I revised the Star Chart from the starbase's records.\""))
5253 prout(_(" STAR CHART FOR THE KNOWN GALAXY"))
5254 if game.state.date > game.lastchart:
5255 prout(_("(Last surveillance update %d stardates ago).") % ((int)(game.state.date-game.lastchart)))
5256 prout(" 1 2 3 4 5 6 7 8")
5257 for i in range(GALSIZE):
5258 proutn("%d |" % (i+1))
5259 for j in range(GALSIZE):
5260 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5264 if game.state.galaxy[i][j].supernova:
5266 elif not game.state.galaxy[i][j].charted and game.state.galaxy[i][j].starbase:
5268 elif game.state.galaxy[i][j].charted:
5269 show = "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars)
5273 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5281 def sectscan(goodScan, i, j):
5282 "Light up an individual dot in a sector."
5283 if goodScan or (abs(i-game.sector.i)<= 1 and abs(j-game.sector.j) <= 1):
5284 if game.quad[i][j] in ('E', 'F'):
5287 textcolor({"green":GREEN,
5291 "dead":BROWN}[game.condition])
5293 textcolor({'?':LIGHTMAGENTA,
5299 }.get(game.quad[i][j], DEFAULT))
5300 proutn("%c " % game.quad[i][j])
5306 "Emit status report lines"
5307 if not req or req == 1:
5308 prstat(_("Stardate"), _("%.1f, Time Left %.2f") \
5309 % (game.state.date, game.state.remtime))
5310 if not req or req == 2:
5311 if game.condition != "docked":
5313 prstat(_("Condition"), _("%s, %i DAMAGES") % \
5314 (game.condition.upper(), sum([x > 0 for x in game.damage])))
5316 prout(_(", CLOAKED"))
5317 if not req or req == 3:
5318 prstat(_("Position"), "%s , %s" % (game.quadrant, game.sector))
5319 if not req or req == 4:
5320 if damaged(DLIFSUP):
5321 if game.condition == "docked":
5322 s = _("DAMAGED, Base provides")
5324 s = _("DAMAGED, reserves=%4.2f") % game.lsupres
5327 prstat(_("Life Support"), s)
5328 if not req or req == 5:
5329 prstat(_("Warp Factor"), "%.1f" % game.warpfac)
5330 if not req or req == 6:
5332 if game.icrystl and (game.options & OPTION_SHOWME):
5333 extra = _(" (have crystals)")
5334 prstat(_("Energy"), "%.2f%s" % (game.energy, extra))
5335 if not req or req == 7:
5336 prstat(_("Torpedoes"), "%d" % (game.torps))
5337 if not req or req == 8:
5338 if damaged(DSHIELD):
5344 data = _(" %d%% %.1f units") \
5345 % (int((100.0*game.shield)/game.inshld + 0.5), game.shield)
5346 prstat(_("Shields"), s+data)
5347 if not req or req == 9:
5348 prstat(_("Klingons Left"), "%d" % game.unwon())
5349 if not req or req == 10:
5350 if game.options & OPTION_WORLDS:
5351 plnet = game.state.galaxy[game.quadrant.i][game.quadrant.j].planet
5352 if plnet and plnet.inhabited:
5353 prstat(_("Major system"), plnet.name)
5355 prout(_("Sector is uninhabited"))
5356 elif not req or req == 11:
5357 attackreport(not req)
5360 "Request specified status data, a historical relic from slow TTYs."
5361 requests = ("da","co","po","ls","wa","en","to","sh","kl","sy", "ti")
5362 while scanner.nexttok() == "IHEOL":
5363 proutn(_("Information desired? "))
5365 if scanner.token in requests:
5366 status(requests.index(scanner.token))
5368 prout(_("UNRECOGNIZED REQUEST. Legal requests are:"))
5369 prout((" date, condition, position, lsupport, warpfactor,"))
5370 prout((" energy, torpedoes, shields, klingons, system, time."))
5375 if damaged(DSRSENS):
5376 # Allow base's sensors if docked
5377 if game.condition != "docked":
5378 prout(_(" S.R. SENSORS DAMAGED!"))
5381 prout(_(" [Using Base's sensors]"))
5383 prout(_(" Short-range scan"))
5384 if goodScan and communicating():
5385 game.state.chart[game.quadrant.i][game.quadrant.j].klingons = game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons
5386 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase
5387 game.state.chart[game.quadrant.i][game.quadrant.j].stars = game.state.galaxy[game.quadrant.i][game.quadrant.j].stars
5388 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
5389 prout(" 1 2 3 4 5 6 7 8 9 10")
5390 if game.condition != "docked":
5392 for i in range(QUADSIZE):
5393 proutn("%2d " % (i+1))
5394 for j in range(QUADSIZE):
5395 sectscan(goodScan, i, j)
5399 "Use computer to get estimated time of arrival for a warp jump."
5400 w1 = Coord(); w2 = Coord()
5402 if damaged(DCOMPTR):
5403 prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR."))
5406 if scanner.nexttok() != "IHREAL":
5409 proutn(_("Destination quadrant and/or sector? "))
5410 if scanner.nexttok()!="IHREAL":
5413 w1.j = int(scanner.real-0.5)
5414 if scanner.nexttok() != "IHREAL":
5417 w1.i = int(scanner.real-0.5)
5418 if scanner.nexttok() == "IHREAL":
5419 w2.j = int(scanner.real-0.5)
5420 if scanner.nexttok() != "IHREAL":
5423 w2.i = int(scanner.real-0.5)
5425 if game.quadrant.j>w1.i:
5429 if game.quadrant.i>w1.j:
5433 if not w1.valid_quadrant() or not w2.valid_sector():
5436 dist = math.sqrt((w1.j-game.quadrant.j+(w2.j-game.sector.j)/(QUADSIZE*1.0))**2+
5437 (w1.i-game.quadrant.i+(w2.i-game.sector.i)/(QUADSIZE*1.0))**2)
5440 prout(_("Answer \"no\" if you don't know the value:"))
5443 proutn(_("Time or arrival date? "))
5444 if scanner.nexttok()=="IHREAL":
5445 ttime = scanner.real
5446 if ttime > game.state.date:
5447 ttime -= game.state.date # Actually a star date
5448 twarp=(math.floor(math.sqrt((10.0*dist)/ttime)*10.0)+1.0)/10.0
5449 if ttime <= 1e-10 or twarp > 10:
5450 prout(_("We'll never make it, sir."))
5457 proutn(_("Warp factor? "))
5458 if scanner.nexttok()== "IHREAL":
5460 twarp = scanner.real
5461 if twarp<1.0 or twarp > 10.0:
5465 prout(_("Captain, certainly you can give me one of these."))
5468 ttime = (10.0*dist)/twarp**2
5469 tpower = dist*twarp*twarp*twarp*(game.shldup+1)
5470 if tpower >= game.energy:
5471 prout(_("Insufficient energy, sir."))
5472 if not game.shldup or tpower > game.energy*2.0:
5475 proutn(_("New warp factor to try? "))
5476 if scanner.nexttok() == "IHREAL":
5478 twarp = scanner.real
5479 if twarp<1.0 or twarp > 10.0:
5487 prout(_("But if you lower your shields,"))
5488 proutn(_("remaining"))
5491 proutn(_("Remaining"))
5492 prout(_(" energy will be %.2f.") % (game.energy-tpower))
5494 prout(_("And we will arrive at stardate %.2f.") % (game.state.date+ttime))
5496 prout(_("Any warp speed is adequate."))
5498 prout(_("Minimum warp needed is %.2f,") % (twarp))
5499 prout(_("and we will arrive at stardate %.2f.") % (game.state.date+ttime))
5500 if game.state.remtime < ttime:
5501 prout(_("Unfortunately, the Federation will be destroyed by then."))
5503 prout(_("You'll be taking risks at that speed, Captain"))
5504 if (game.isatb==1 and game.state.kscmdr == w1 and \
5505 scheduled(FSCDBAS)< ttime+game.state.date) or \
5506 (scheduled(FCDBAS)<ttime+game.state.date and game.battle == w1):
5507 prout(_("The starbase there will be destroyed by then."))
5508 proutn(_("New warp factor to try? "))
5509 if scanner.nexttok() == "IHREAL":
5511 twarp = scanner.real
5512 if twarp<1.0 or twarp > 10.0:
5520 # Code from setup.c begins here
5523 "Issue a historically correct banner."
5525 prout(_("-SUPER- STAR TREK"))
5527 # From the FORTRAN original
5528 # prout(_("Latest update-21 Sept 78"))
5534 scanner.push("emsave.trk")
5535 key = scanner.nexttok()
5537 proutn(_("File name: "))
5538 key = scanner.nexttok()
5539 if key != "IHALPHA":
5542 if '.' not in scanner.token:
5543 scanner.token += ".trk"
5545 fp = open(scanner.token, "wb")
5547 prout(_("Can't freeze game as file %s") % scanner.token)
5549 pickle.dump(game, fp)
5554 "Retrieve saved game."
5557 key = scanner.nexttok()
5559 proutn(_("File name: "))
5560 key = scanner.nexttok()
5561 if key != "IHALPHA":
5564 if '.' not in scanner.token:
5565 scanner.token += ".trk"
5567 fp = open(scanner.token, "rb")
5569 prout(_("Can't thaw game in %s") % scanner.token)
5571 game = pickle.load(fp)
5576 # I used <http://www.memory-alpha.org> to find planets
5577 # with references in ST:TOS. Earth and the Alpha Centauri
5578 # Colony have been omitted.
5580 # Some planets marked Class G and P here will be displayed as class M
5581 # because of the way planets are generated. This is a known bug.
5584 _("Andoria (Fesoan)"), # several episodes
5585 _("Tellar Prime (Miracht)"), # TOS: "Journey to Babel"
5586 _("Vulcan (T'Khasi)"), # many episodes
5587 _("Medusa"), # TOS: "Is There in Truth No Beauty?"
5588 _("Argelius II (Nelphia)"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5589 _("Ardana"), # TOS: "The Cloud Minders"
5590 _("Catulla (Cendo-Prae)"), # TOS: "The Way to Eden"
5591 _("Gideon"), # TOS: "The Mark of Gideon"
5592 _("Aldebaran III"), # TOS: "The Deadly Years"
5593 _("Alpha Majoris I"), # TOS: "Wolf in the Fold"
5594 _("Altair IV"), # TOS: "Amok Time
5595 _("Ariannus"), # TOS: "Let That Be Your Last Battlefield"
5596 _("Benecia"), # TOS: "The Conscience of the King"
5597 _("Beta Niobe I (Sarpeidon)"), # TOS: "All Our Yesterdays"
5598 _("Alpha Carinae II"), # TOS: "The Ultimate Computer"
5599 _("Capella IV (Kohath)"), # TOS: "Friday's Child" (Class G)
5600 _("Daran V"), # TOS: "For the World is Hollow and I Have Touched the Sky"
5601 _("Deneb II"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5602 _("Eminiar VII"), # TOS: "A Taste of Armageddon"
5603 _("Gamma Canaris IV"), # TOS: "Metamorphosis"
5604 _("Gamma Tranguli VI (Vaalel)"), # TOS: "The Apple"
5605 _("Ingraham B"), # TOS: "Operation: Annihilate"
5606 _("Janus IV"), # TOS: "The Devil in the Dark"
5607 _("Makus III"), # TOS: "The Galileo Seven"
5608 _("Marcos XII"), # TOS: "And the Children Shall Lead",
5609 _("Omega IV"), # TOS: "The Omega Glory"
5610 _("Regulus V"), # TOS: "Amok Time
5611 _("Deneva"), # TOS: "Operation -- Annihilate!"
5612 # Worlds from BSD Trek
5613 _("Rigel II"), # TOS: "Shore Leave" ("III" in BSD)
5614 _("Beta III"), # TOS: "The Return of the Archons"
5615 _("Triacus"), # TOS: "And the Children Shall Lead",
5616 _("Exo III"), # TOS: "What Are Little Girls Made Of?" (Class P)
5618 # _("Hansen's Planet"), # TOS: "The Galileo Seven"
5619 # _("Taurus IV"), # TOS: "The Galileo Seven" (class G)
5620 # _("Antos IV (Doraphane)"), # TOS: "Whom Gods Destroy", "Who Mourns for Adonais?"
5621 # _("Izar"), # TOS: "Whom Gods Destroy"
5622 # _("Tiburon"), # TOS: "The Way to Eden"
5623 # _("Merak II"), # TOS: "The Cloud Minders"
5624 # _("Coridan (Desotriana)"), # TOS: "Journey to Babel"
5625 # _("Iotia"), # TOS: "A Piece of the Action"
5629 _("S. R. Sensors"), \
5630 _("L. R. Sensors"), \
5632 _("Photon Tubes"), \
5633 _("Life Support"), \
5634 _("Warp Engines"), \
5635 _("Impulse Engines"), \
5637 _("Subspace Radio"), \
5638 _("Shuttle Craft"), \
5640 _("Navigation System"), \
5642 _("Shield Control"), \
5645 _("Cloaking Device"), \
5649 "Prepare to play, set up cosmos."
5651 # Decide how many of everything
5653 return # frozen game
5654 # Prepare the Enterprise
5655 game.alldone = game.gamewon = game.shldchg = game.shldup = False
5657 game.state.crew = FULLCREW
5658 game.energy = game.inenrg = 5000.0
5659 game.shield = game.inshld = 2500.0
5662 game.quadrant = randplace(GALSIZE)
5663 game.sector = randplace(QUADSIZE)
5664 game.torps = game.intorps = 10
5665 game.nprobes = randrange(2, 5)
5667 for i in range(NDEVICES):
5668 game.damage[i] = 0.0
5669 # Set up assorted game parameters
5670 game.battle = Coord()
5671 game.state.date = game.indate = 100.0 * randreal(20, 51)
5672 game.nkinks = game.nhelp = game.casual = game.abandoned = 0
5673 game.iscate = game.resting = game.imine = game.icrystl = game.icraft = False
5674 game.isatb = game.state.nplankl = 0
5675 game.state.starkl = game.state.basekl = game.state.nworldkl = 0
5676 game.iscraft = "onship"
5681 game.state.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
5683 game.state.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
5685 game.state.planets = [] # Planet information
5686 game.state.baseq = [] # Base quadrant coordinates
5687 game.state.kcmdr = [] # Commander quadrant coordinates
5688 game.statekscmdr = Coord() # Supercommander quadrant coordinates
5690 # Starchart is functional but we've never seen it
5691 game.lastchart = FOREVER
5692 # Put stars in the galaxy
5694 for i in range(GALSIZE):
5695 for j in range(GALSIZE):
5696 # Can't have more stars per quadrant than fit in one decimal digit,
5697 # if we do the chart representation will break.
5698 k = randrange(1, min(10, QUADSIZE**2/10))
5700 game.state.galaxy[i][j].stars = k
5701 # Locate star bases in galaxy
5703 prout("=== Allocating %d bases" % game.inbase)
5704 for i in range(game.inbase):
5707 w = randplace(GALSIZE)
5708 if not game.state.galaxy[w.i][w.j].starbase:
5711 # C version: for (j = i-1; j > 0; j--)
5712 # so it did them in the opposite order.
5713 for j in range(1, i):
5714 # Improved placement algorithm to spread out bases
5715 distq = (w - game.state.baseq[j]).distance()
5716 if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75):
5719 prout("=== Abandoning base #%d at %s" % (i, w))
5721 elif distq < 6.0 * (BASEMAX+1-game.inbase):
5723 prout("=== Saving base #%d, close to #%d" % (i, j))
5727 prout("=== Placing base #%d in quadrant %s" % (i, w))
5728 game.state.baseq.append(w)
5729 game.state.galaxy[w.i][w.j].starbase = game.state.chart[w.i][w.j].starbase = True
5730 # Position ordinary Klingon Battle Cruisers
5732 klumper = 0.25*game.skill*(9.0-game.length)+1.0
5733 if klumper > MAXKLQUAD:
5737 klump = (1.0 - r*r)*klumper
5742 w = randplace(GALSIZE)
5743 if not game.state.galaxy[w.i][w.j].supernova and \
5744 game.state.galaxy[w.i][w.j].klingons + klump <= MAXKLQUAD:
5746 game.state.galaxy[w.i][w.j].klingons += int(klump)
5749 # Position Klingon Commander Ships
5750 for i in range(game.incom):
5752 w = randplace(GALSIZE)
5753 if not welcoming(w) or w in game.state.kcmdr:
5755 if (game.state.galaxy[w.i][w.j].klingons or withprob(0.25)):
5757 game.state.galaxy[w.i][w.j].klingons += 1
5758 game.state.kcmdr.append(w)
5759 # Locate planets in galaxy
5760 for i in range(game.inplan):
5762 w = randplace(GALSIZE)
5763 if game.state.galaxy[w.i][w.j].planet is None:
5767 new.crystals = "absent"
5768 if (game.options & OPTION_WORLDS) and i < NINHAB:
5769 new.pclass = "M" # All inhabited planets are class M
5770 new.crystals = "absent"
5772 new.name = systnames[i]
5773 new.inhabited = True
5775 new.pclass = ("M", "N", "O")[randrange(0, 3)]
5777 new.crystals = "present"
5778 new.known = "unknown"
5779 new.inhabited = False
5780 game.state.galaxy[w.i][w.j].planet = new
5781 game.state.planets.append(new)
5783 for i in range(game.state.nromrem):
5784 w = randplace(GALSIZE)
5785 game.state.galaxy[w.i][w.j].romulans += 1
5786 # Place the Super-Commander if needed
5787 if game.state.nscrem > 0:
5789 w = randplace(GALSIZE)
5792 game.state.kscmdr = w
5793 game.state.galaxy[w.i][w.j].klingons += 1
5794 # Initialize times for extraneous events
5795 schedule(FSNOVA, expran(0.5 * game.intime))
5796 schedule(FTBEAM, expran(1.5 * (game.intime / len(game.state.kcmdr))))
5797 schedule(FSNAP, randreal(1.0, 2.0)) # Force an early snapshot
5798 schedule(FBATTAK, expran(0.3*game.intime))
5800 if game.state.nscrem:
5801 schedule(FSCMOVE, 0.2777)
5806 if (game.options & OPTION_WORLDS) and game.skill >= SKILL_GOOD:
5807 schedule(FDISTR, expran(1.0 + game.intime))
5812 # Place thing (in tournament game, we don't want one!)
5813 # New in SST2K: never place the Thing near a starbase.
5814 # This makes sense and avoids a special case in the old code.
5816 if game.tourn is None:
5818 thing = randplace(GALSIZE)
5819 if thing not in game.state.baseq:
5822 game.state.snap = False
5823 if game.skill == SKILL_NOVICE:
5824 prout(_("It is stardate %d. The Federation is being attacked by") % int(game.state.date))
5825 prout(_("a deadly Klingon invasion force. As captain of the United"))
5826 prout(_("Starship U.S.S. Enterprise, it is your mission to seek out"))
5827 prout(_("and destroy this invasion force of %d battle cruisers.") % ((game.inkling + game.incom + game.inscom)))
5828 prout(_("You have an initial allotment of %d stardates to complete") % int(game.intime))
5829 prout(_("your mission. As you proceed you may be given more time."))
5831 prout(_("You will have %d supporting starbases.") % (game.inbase))
5832 proutn(_("Starbase locations- "))
5834 prout(_("Stardate %d.") % int(game.state.date))
5836 prout(_("%d Klingons.") % (game.inkling + game.incom + game.inscom))
5837 prout(_("An unknown number of Romulans."))
5838 if game.state.nscrem:
5839 prout(_("And one (GULP) Super-Commander."))
5840 prout(_("%d stardates.") % int(game.intime))
5841 proutn(_("%d starbases in ") % game.inbase)
5842 for i in range(game.inbase):
5843 proutn(repr(game.state.baseq[i]))
5846 proutn(_("The Enterprise is currently in Quadrant %s") % game.quadrant)
5847 proutn(_(" Sector %s") % game.sector)
5849 prout(_("Good Luck!"))
5850 if game.state.nscrem:
5851 prout(_(" YOU'LL NEED IT."))
5854 setwnd(message_window)
5856 if len(game.enemies) - (thing == game.quadrant) - (game.tholian != None):
5858 if game.neutz: # bad luck to start in a Romulan Neutral Zone
5859 attack(torps_ok=False)
5862 "Choose your game type."
5864 game.tourn = game.length = 0
5866 game.skill = SKILL_NONE
5867 # Do not chew here, we want to use command-line tokens
5868 if not scanner.inqueue: # Can start with command line options
5869 proutn(_("Would you like a regular, tournament, or saved game? "))
5871 if scanner.sees("tournament"):
5872 while scanner.nexttok() == "IHEOL":
5873 proutn(_("Type in tournament number-"))
5874 if scanner.real == 0:
5876 continue # We don't want a blank entry
5877 game.tourn = int(round(scanner.real))
5878 random.seed(scanner.real)
5880 logfp.write("# random.seed(%d)\n" % scanner.real)
5882 if scanner.sees("saved") or scanner.sees("frozen"):
5886 if game.passwd is None:
5888 if not game.alldone:
5889 game.thawed = True # No plaque if not finished
5893 if scanner.sees("regular"):
5895 proutn(_("What is \"%s\"? ") % scanner.token)
5897 while game.length==0 or game.skill==SKILL_NONE:
5898 if scanner.nexttok() == "IHALPHA":
5899 if scanner.sees("short"):
5901 elif scanner.sees("medium"):
5903 elif scanner.sees("long"):
5905 elif scanner.sees("novice"):
5906 game.skill = SKILL_NOVICE
5907 elif scanner.sees("fair"):
5908 game.skill = SKILL_FAIR
5909 elif scanner.sees("good"):
5910 game.skill = SKILL_GOOD
5911 elif scanner.sees("expert"):
5912 game.skill = SKILL_EXPERT
5913 elif scanner.sees("emeritus"):
5914 game.skill = SKILL_EMERITUS
5916 proutn(_("What is \""))
5917 proutn(scanner.token)
5922 proutn(_("Would you like a Short, Medium, or Long game? "))
5923 elif game.skill == SKILL_NONE:
5924 proutn(_("Are you a Novice, Fair, Good, Expert, or Emeritus player? "))
5925 # Choose game options -- added by ESR for SST2K
5926 if scanner.nexttok() != "IHALPHA":
5928 proutn(_("Choose your game style (plain, almy, fancy or just press enter): "))
5930 if scanner.sees("plain"):
5931 # Approximates the UT FORTRAN version.
5932 game.options &=~ (OPTION_THOLIAN | OPTION_PLANETS | OPTION_THINGY | OPTION_PROBE | OPTION_RAMMING | OPTION_MVBADDY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS | OPTION_COLOR | OPTION_CAPTURE | OPTION_CLOAK)
5933 game.options |= OPTION_PLAIN
5934 elif scanner.sees("almy"):
5935 # Approximates Tom Almy's version.
5936 game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS | OPTION_COLOR)
5937 game.options |= OPTION_ALMY
5938 elif scanner.sees("fancy") or scanner.sees("\n"):
5940 elif len(scanner.token):
5941 proutn(_("What is \"%s\"?") % scanner.token)
5943 if game.passwd == "debug":
5945 prout("=== Debug mode enabled.")
5946 # Use parameters to generate initial values of things
5947 game.damfac = 0.5 * game.skill
5948 game.inbase = randrange(BASEMIN, BASEMAX+1)
5950 if game.options & OPTION_PLANETS:
5951 game.inplan += randrange(MAXUNINHAB/2, MAXUNINHAB+1)
5952 if game.options & OPTION_WORLDS:
5953 game.inplan += int(NINHAB)
5954 game.state.nromrem = game.inrom = randrange(2 * game.skill)
5955 game.state.nscrem = game.inscom = (game.skill > SKILL_FAIR)
5956 game.state.remtime = 7.0 * game.length
5957 game.intime = game.state.remtime
5958 game.state.remkl = game.inkling = int(2.0*game.intime*((game.skill+1 - 2*randreal())*game.skill*0.1+.15))
5959 game.incom = min(MINCMDR, int(game.skill + 0.0625*game.inkling*randreal()))
5960 game.state.remres = (game.inkling+4*game.incom)*game.intime
5961 game.inresor = game.state.remres
5962 if game.inkling > 50:
5966 def dropin(iquad=None):
5967 "Drop a feature on a random dot in the current quadrant."
5969 w = randplace(QUADSIZE)
5970 if game.quad[w.i][w.j] == '.':
5972 if iquad is not None:
5973 game.quad[w.i][w.j] = iquad
5977 "Update our alert status."
5978 game.condition = "green"
5979 if game.energy < 1000.0:
5980 game.condition = "yellow"
5981 if game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons or game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans:
5982 game.condition = "red"
5984 game.condition="dead"
5987 "Drop new Klingon into current quadrant."
5988 return Enemy('K', loc=dropin(), power=randreal(300,450)+25.0*game.skill)
5991 "Sort enemies by distance so 'nearest' is meaningful."
5992 game.enemies.sort(key=lambda x: x.kdist)
5995 "Set up a new state of quadrant, for when we enter or re-enter it."
5998 game.neutz = game.inorbit = game.landed = False
5999 game.ientesc = game.iseenit = game.isviolreported = False
6000 # Create a blank quadrant
6001 game.quad = fill2d(QUADSIZE, lambda i, j: '.')
6003 # Attempt to escape Super-commander, so tbeam back!
6006 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
6007 # cope with supernova
6010 game.klhere = q.klingons
6011 game.irhere = q.romulans
6013 game.quad[game.sector.i][game.sector.j] = game.ship
6016 # Position ordinary Klingons
6017 for _i in range(game.klhere):
6019 # If we need a commander, promote a Klingon
6020 for cmdr in game.state.kcmdr:
6021 if cmdr == game.quadrant:
6022 e = game.enemies[game.klhere-1]
6023 game.quad[e.location.i][e.location.j] = 'C'
6024 e.power = randreal(950,1350) + 50.0*game.skill
6026 # If we need a super-commander, promote a Klingon
6027 if game.quadrant == game.state.kscmdr:
6029 game.quad[e.location.i][e.location.j] = 'S'
6030 e.power = randreal(1175.0, 1575.0) + 125.0*game.skill
6031 game.iscate = (game.state.remkl > 1)
6032 # Put in Romulans if needed
6033 for _i in range(q.romulans):
6034 Enemy('R', loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill)
6035 # If quadrant needs a starbase, put it in
6037 game.base = dropin('B')
6038 # If quadrant needs a planet, put it in
6040 game.iplnet = q.planet
6041 if not q.planet.inhabited:
6042 game.plnet = dropin('P')
6044 game.plnet = dropin('@')
6045 # Check for condition
6048 if game.irhere > 0 and game.klhere == 0:
6050 if not damaged(DRADIO):
6052 prout(_("LT. Uhura- \"Captain, an urgent message."))
6053 prout(_(" I'll put it on audio.\" CLICK"))
6055 prout(_("INTRUDER! YOU HAVE VIOLATED THE ROMULAN NEUTRAL ZONE."))
6056 prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!"))
6057 # Put in THING if needed
6058 if thing == game.quadrant:
6059 Enemy(etype='?', loc=dropin(),
6060 power=randreal(6000,6500.0)+250.0*game.skill)
6061 if not damaged(DSRSENS):
6063 prout(_("Mr. Spock- \"Captain, this is most unusual."))
6064 prout(_(" Please examine your short-range scan.\""))
6065 # Decide if quadrant needs a Tholian; lighten up if skill is low
6066 if game.options & OPTION_THOLIAN:
6067 if (game.skill < SKILL_GOOD and withprob(0.02)) or \
6068 (game.skill == SKILL_GOOD and withprob(0.05)) or \
6069 (game.skill > SKILL_GOOD and withprob(0.08)):
6072 w.i = withprob(0.5) * (QUADSIZE-1)
6073 w.j = withprob(0.5) * (QUADSIZE-1)
6074 if game.quad[w.i][w.j] == '.':
6076 game.tholian = Enemy(etype='T', loc=w,
6077 power=randrange(100, 500) + 25.0*game.skill)
6078 # Reserve unoccupied corners
6079 if game.quad[0][0]=='.':
6080 game.quad[0][0] = 'X'
6081 if game.quad[0][QUADSIZE-1]=='.':
6082 game.quad[0][QUADSIZE-1] = 'X'
6083 if game.quad[QUADSIZE-1][0]=='.':
6084 game.quad[QUADSIZE-1][0] = 'X'
6085 if game.quad[QUADSIZE-1][QUADSIZE-1]=='.':
6086 game.quad[QUADSIZE-1][QUADSIZE-1] = 'X'
6088 # And finally the stars
6089 for _i in range(q.stars):
6091 # Put in a few black holes
6092 for _i in range(1, 3+1):
6095 # Take out X's in corners if Tholian present
6097 if game.quad[0][0]=='X':
6098 game.quad[0][0] = '.'
6099 if game.quad[0][QUADSIZE-1]=='X':
6100 game.quad[0][QUADSIZE-1] = '.'
6101 if game.quad[QUADSIZE-1][0]=='X':
6102 game.quad[QUADSIZE-1][0] = '.'
6103 if game.quad[QUADSIZE-1][QUADSIZE-1]=='X':
6104 game.quad[QUADSIZE-1][QUADSIZE-1] = '.'
6107 "Set the self-destruct password."
6108 if game.options & OPTION_PLAIN:
6111 proutn(_("Please type in a secret password- "))
6113 game.passwd = scanner.token
6114 if game.passwd != None:
6118 game.passwd += chr(ord('a')+randrange(26))
6119 game.passwd += chr(ord('a')+randrange(26))
6120 game.passwd += chr(ord('a')+randrange(26))
6122 # Code from sst.c begins here
6125 ("SRSCAN", OPTION_TTY),
6126 ("STATUS", OPTION_TTY),
6127 ("REQUEST", OPTION_TTY),
6128 ("LRSCAN", OPTION_TTY),
6140 ("SENSORS", OPTION_PLANETS),
6141 ("ORBIT", OPTION_PLANETS),
6142 ("TRANSPORT", OPTION_PLANETS),
6143 ("MINE", OPTION_PLANETS),
6144 ("CRYSTALS", OPTION_PLANETS),
6145 ("SHUTTLE", OPTION_PLANETS),
6146 ("PLANETS", OPTION_PLANETS),
6151 ("PROBE", OPTION_PROBE),
6153 ("FREEZE", 0), # Synonym for SAVE
6157 ("CAPTURE", OPTION_CAPTURE),
6158 ("CLOAK", OPTION_CLOAK),
6161 ("SOS", 0), # Synonym for MAYDAY
6162 ("CALL", 0), # Synonym for MAYDAY
6171 "Generate a list of legal commands."
6172 prout(_("LEGAL COMMANDS ARE:"))
6174 for (key, opt) in commands:
6175 if not opt or (opt & game.options):
6176 proutn("%-12s " % key)
6178 if emitted % 5 == 4:
6183 "Browse on-line help."
6184 key = scanner.nexttok()
6187 setwnd(prompt_window)
6188 proutn(_("Help on what command? "))
6189 key = scanner.nexttok()
6190 setwnd(message_window)
6193 cmds = [x[0] for x in commands]
6194 if scanner.token.upper() in cmds or scanner.token.upper() == "ABBREV":
6201 cmd = scanner.token.upper()
6202 for directory in docpath:
6204 fp = open(os.path.join(directory, "sst.doc"), "r")
6209 prout(_("Spock- \"Captain, that information is missing from the"))
6210 prout(_(" computer. You need to find sst.doc and put it somewhere"))
6211 proutn(_(" in these directories: %s") % ":".join(docpath))
6213 # This used to continue: "You need to find SST.DOC and put
6214 # it in the current directory."
6217 linebuf = fp.readline()
6219 prout(_("Spock- \"Captain, there is no information on that command.\""))
6222 if linebuf[0] == '%' and linebuf[1] == '%' and linebuf[2] == ' ':
6223 linebuf = linebuf[3:].strip()
6224 if cmd.upper() == linebuf:
6227 prout(_("Spock- \"Captain, I've found the following information:\""))
6230 linebuf = fp.readline()
6231 if "******" in linebuf:
6237 "Command-interpretation loop."
6239 if game.irhere and game.state.date >= ALGERON and not game.isviolreported and game.iscloaked:
6240 prout(_("The Romulan ship discovers you are breaking the Treaty of Algeron!"))
6242 game.isviolreported = True
6243 while True: # command loop
6245 while True: # get a command
6247 game.optime = game.justin = False
6249 setwnd(prompt_window)
6252 if scanner.nexttok() == "IHEOL":
6253 if game.options & OPTION_CURSES:
6256 elif scanner.token == "":
6260 setwnd(message_window)
6262 abandon_passed = False
6263 cmd = "" # Force cmd to persist after loop
6264 opt = 0 # Force opt to persist after loop
6265 for (cmd, opt) in commands:
6266 # commands after ABANDON cannot be abbreviated
6267 if cmd == "ABANDON":
6268 abandon_passed = True
6269 if cmd == scanner.token.upper() or (not abandon_passed \
6270 and cmd.startswith(scanner.token.upper())):
6275 elif opt and not (opt & game.options):
6279 if game.options & OPTION_CURSES:
6280 prout("COMMAND> %s" % cmd)
6281 if cmd == "SRSCAN": # srscan
6283 elif cmd == "STATUS": # status
6285 elif cmd == "REQUEST": # status request
6287 elif cmd == "LRSCAN": # long range scan
6288 lrscan(silent=False)
6289 elif cmd == "PHASERS": # phasers
6294 elif cmd in ("TORPEDO", "PHOTONS"): # photon torpedos
6299 elif cmd == "MOVE": # move under warp
6300 warp(wcourse=None, involuntary=False)
6301 elif cmd == "SHIELDS": # shields
6302 doshield(shraise=False)
6305 game.shldchg = False
6306 elif cmd == "DOCK": # dock at starbase
6309 attack(torps_ok=False)
6310 elif cmd == "DAMAGES": # damage reports
6312 elif cmd == "CHART": # chart
6314 elif cmd == "IMPULSE": # impulse
6316 elif cmd == "REST": # rest
6320 elif cmd == "WARP": # warp
6322 elif cmd == "SENSORS": # sensors
6324 elif cmd == "ORBIT": # orbit
6328 elif cmd == "TRANSPORT": # transport "beam"
6330 elif cmd == "MINE": # mine
6334 elif cmd == "CRYSTALS": # crystals
6338 elif cmd == "SHUTTLE": # shuttle
6342 elif cmd == "PLANETS": # Planet list
6344 elif cmd == "REPORT": # Game Report
6346 elif cmd == "COMPUTER": # use COMPUTER!
6348 elif cmd == "COMMANDS":
6350 elif cmd == "EMEXIT": # Emergency exit
6351 clrscr() # Hide screen
6352 freeze(True) # forced save
6353 raise SystemExit(1) # And quick exit
6354 elif cmd == "PROBE":
6355 probe() # Launch probe
6358 elif cmd == "ABANDON": # Abandon Ship
6360 elif cmd == "DESTRUCT": # Self Destruct
6362 elif cmd == "SAVE": # Save Game
6365 if game.skill > SKILL_GOOD:
6366 prout(_("WARNING--Saved games produce no plaques!"))
6367 elif cmd == "DEATHRAY": # Try a desparation measure
6371 elif cmd == "CAPTURE":
6373 elif cmd == "CLOAK":
6375 elif cmd == "DEBUGCMD": # What do we want for debug???
6377 elif cmd == "MAYDAY": # Call for help
6382 game.alldone = True # quit the game
6385 elif cmd == "SCORE":
6386 score() # see current score
6387 elif cmd == "CURSES":
6388 game.options |= (OPTION_CURSES | OPTION_COLOR)
6392 break # Game has ended
6393 if game.optime != 0.0:
6396 break # Events did us in
6397 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6400 if hitme and not game.justin:
6401 attack(torps_ok=True)
6404 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6415 "Emit the name of an enemy or feature."
6416 if ch == 'R': s = _("Romulan")
6417 elif ch == 'K': s = _("Klingon")
6418 elif ch == 'C': s = _("Commander")
6419 elif ch == 'S': s = _("Super-commander")
6420 elif ch == '*': s = _("Star")
6421 elif ch == 'P': s = _("Planet")
6422 elif ch == 'B': s = _("Starbase")
6423 elif ch == ' ': s = _("Black hole")
6424 elif ch == 'T': s = _("Tholian")
6425 elif ch == '#': s = _("Tholian web")
6426 elif ch == '?': s = _("Stranger")
6427 elif ch == '@': s = _("Inhabited World")
6428 else: s = "Unknown??"
6431 def crmena(loud, enemy, loctype, w):
6432 "Emit the name of an enemy and his location."
6436 buf += cramen(enemy) + _(" at ")
6437 if loctype == "quadrant":
6438 buf += _("Quadrant ")
6439 elif loctype == "sector":
6441 return buf + repr(w)
6444 "Emit our ship name."
6445 return{'E':_("Enterprise"),'F':_("Faerie Queene")}.get(game.ship,"Ship???")
6448 "Emit a line of stars"
6449 prouts("******************************************************")
6453 return -avrage*math.log(1e-7 + randreal())
6455 def randplace(size):
6456 "Choose a random location."
6458 w.i = randrange(size)
6459 w.j = randrange(size)
6469 # Get a token from the user
6472 # Fill the token quue if nothing here
6473 while not self.inqueue:
6475 if curwnd==prompt_window:
6477 setwnd(message_window)
6484 self.inqueue = sline.lstrip().split() + ["\n"]
6485 # From here on in it's all looking at the queue
6486 self.token = self.inqueue.pop(0)
6487 if self.token == "\n":
6491 self.real = float(self.token)
6492 self.type = "IHREAL"
6497 self.token = self.token.lower()
6498 self.type = "IHALPHA"
6501 def append(self, tok):
6502 self.inqueue.append(tok)
6503 def push(self, tok):
6504 self.inqueue.insert(0, tok)
6508 # Demand input for next scan
6510 self.real = self.token = None
6512 # compares s to item and returns true if it matches to the length of s
6513 return s.startswith(self.token)
6515 # Round token value to nearest integer
6516 return int(round(self.real))
6520 if self.type != "IHREAL":
6525 if self.type != "IHREAL":
6531 return "<sstcanner: token=%s, type=%s, queue=%s>" % (self.token, self.type, self.inqueue)
6534 "Yes-or-no confirmation."
6538 if scanner.token == 'y':
6540 if scanner.token == 'n':
6543 proutn(_("Please answer with \"y\" or \"n\": "))
6546 "Complain about unparseable input."
6549 prout(_("Beg your pardon, Captain?"))
6552 "Access to the internals for debugging."
6553 proutn("Reset levels? ")
6555 if game.energy < game.inenrg:
6556 game.energy = game.inenrg
6557 game.shield = game.inshld
6558 game.torps = game.intorps
6559 game.lsupres = game.inlsr
6560 proutn("Reset damage? ")
6562 for i in range(NDEVICES):
6563 if game.damage[i] > 0.0:
6564 game.damage[i] = 0.0
6565 proutn("Toggle debug flag? ")
6567 game.idebug = not game.idebug
6569 prout("Debug output ON")
6571 prout("Debug output OFF")
6572 proutn("Cause selective damage? ")
6574 for i in range(NDEVICES):
6575 proutn("Kill %s?" % device[i])
6577 key = scanner.nexttok()
6578 if key == "IHALPHA" and scanner.sees("y"):
6579 game.damage[i] = 10.0
6580 proutn("Examine/change events? ")
6585 FSNOVA: "Supernova ",
6588 FBATTAK: "Base Attack ",
6589 FCDBAS: "Base Destroy ",
6590 FSCMOVE: "SC Move ",
6591 FSCDBAS: "SC Base Destroy ",
6592 FDSPROB: "Probe Move ",
6593 FDISTR: "Distress Call ",
6594 FENSLV: "Enslavement ",
6595 FREPRO: "Klingon Build ",
6597 for i in range(1, NEVENTS):
6600 proutn("%.2f" % (scheduled(i)-game.state.date))
6601 if i == FENSLV or i == FREPRO:
6603 proutn(" in %s" % ev.quadrant)
6608 key = scanner.nexttok()
6612 elif key == "IHREAL":
6613 ev = schedule(i, scanner.real)
6614 if i == FENSLV or i == FREPRO:
6616 proutn("In quadrant- ")
6617 key = scanner.nexttok()
6618 # "IHEOL" says to leave coordinates as they are
6621 prout("Event %d canceled, no x coordinate." % (i))
6624 w.i = int(round(scanner.real))
6625 key = scanner.nexttok()
6627 prout("Event %d canceled, no y coordinate." % (i))
6630 w.j = int(round(scanner.real))
6633 proutn("Induce supernova here? ")
6635 game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova = True
6638 if __name__ == '__main__':
6640 #global line, thing, game
6644 game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY)
6645 if os.getenv("TERM"):
6646 game.options |= OPTION_CURSES
6648 game.options |= OPTION_TTY
6649 seed = int(time.time())
6650 (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:txV")
6652 for (switch, val) in options:
6655 replayfp = open(val, "r")
6657 sys.stderr.write("sst: can't open replay file %s\n" % val)
6660 line = replayfp.readline().strip()
6661 (leader, __, seed) = line.split()
6663 sys.stderr.write("sst2k: seed set to %s\n" % seed)
6664 line = replayfp.readline().strip()
6665 arguments += line.split()[2:]
6668 sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
6670 game.options |= OPTION_TTY
6671 game.options &=~ OPTION_CURSES
6672 elif switch == '-s':
6674 elif switch == '-t':
6675 game.options |= OPTION_TTY
6676 game.options &=~ OPTION_CURSES
6677 elif switch == '-x':
6679 elif switch == '-V':
6680 print("SST2K", version)
6683 sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n")
6685 # where to save the input in case of bugs
6686 if "TMPDIR" in os.environ:
6687 tmpdir = os.environ['TMPDIR']
6691 logfp = open(os.path.join(tmpdir, "sst-input.log"), "w")
6693 sys.stderr.write("sst: warning, can't open logfile\n")
6696 logfp.write("# seed %s\n" % seed)
6697 logfp.write("# options %s\n" % " ".join(arguments))
6698 logfp.write("# SST2K version %s\n" % version)
6699 logfp.write("# recorded by %s@%s on %s\n" % \
6700 (getpass.getuser(),socket.gethostname(),time.ctime()))
6702 scanner = sstscanner()
6703 for arg in arguments:
6707 while True: # Play a game
6708 setwnd(fullscreen_window)
6714 game.alldone = False
6722 if game.tourn and game.alldone:
6723 proutn(_("Do you want your score recorded?"))
6729 proutn(_("Do you want to play again? "))
6733 prout(_("May the Great Bird of the Galaxy roost upon your home planet."))
6737 except KeyboardInterrupt: