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
3714 if icourse.final.i < 0:
3715 icourse.final.i = -icourse.final.i
3717 if icourse.final.j < 0:
3718 icourse.final.j = -icourse.final.j
3720 if icourse.final.i >= GALSIZE*QUADSIZE:
3721 icourse.final.i = (GALSIZE*QUADSIZE*2) - icourse.final.i
3723 if icourse.final.j >= GALSIZE*QUADSIZE:
3724 icourse.final.j = (GALSIZE*QUADSIZE*2) - icourse.final.j
3732 if game.nkinks == 3:
3733 # Three strikes -- you're out!
3737 prout(_("YOU HAVE ATTEMPTED TO CROSS THE NEGATIVE ENERGY BARRIER"))
3738 prout(_("AT THE EDGE OF THE GALAXY. THE THIRD TIME YOU TRY THIS,"))
3739 prout(_("YOU WILL BE DESTROYED."))
3740 # Compute final position in new quadrant
3741 if trbeam: # Don't bother if we are to be beamed
3743 game.quadrant = icourse.final.quadrant()
3744 game.sector = icourse.final.sector()
3746 prout(_("Entering Quadrant %s.") % game.quadrant)
3747 game.quad[game.sector.i][game.sector.j] = game.ship
3749 if game.skill>SKILL_NOVICE:
3750 attack(torps_ok=False)
3752 def check_collision(h):
3753 iquad = game.quad[h.i][h.j]
3755 # object encountered in flight path
3756 stopegy = 50.0*icourse.distance/game.optime
3757 if iquad in ('T', 'K', 'C', 'S', 'R', '?'):
3758 for enemy in game.enemies:
3759 if enemy.location == game.sector:
3760 collision(rammed=False, enemy=enemy)
3762 # This should not happen
3763 prout(_("Which way did he go?"))
3767 prouts(_("***RED ALERT! RED ALERT!"))
3769 proutn("***" + crmshp())
3770 proutn(_(" pulled into black hole at Sector %s") % h)
3771 # Getting pulled into a black hole was certain
3772 # death in Almy's original. Stas Sergeev added a
3773 # possibility that you'll get timewarped instead.
3775 for m in range(NDEVICES):
3776 if game.damage[m]>0:
3778 probf=math.pow(1.4,(game.energy+game.shield)/5000.0-1.0)*math.pow(1.3,1.0/(n+1)-1.0)
3779 if (game.options & OPTION_BLKHOLE) and withprob(1-probf):
3789 prout(_(" encounters Tholian web at %s;") % h)
3791 prout(_(" blocked by object at %s;") % h)
3792 proutn(_("Emergency stop required "))
3793 prout(_("%2d units of energy.") % int(stopegy))
3794 game.energy -= stopegy
3795 if game.energy <= 0:
3802 prout(_("Helmsman Sulu- \"Leaving standard orbit.\""))
3803 game.inorbit = False
3804 # If tractor beam is to occur, don't move full distance
3805 if game.state.date+game.optime >= scheduled(FTBEAM):
3807 # We can't be tractor beamed if cloaked,
3808 # so move the event into the future
3809 postpone(FTBEAM, game.optime + expran(1.5*game.intime/len(game.kcmdr)))
3813 game.condition = "red"
3814 icourse.distance = icourse.distance*(scheduled(FTBEAM)-game.state.date)/game.optime + 0.1
3815 game.optime = scheduled(FTBEAM) - game.state.date + 1e-5
3817 game.quad[game.sector.i][game.sector.j] = '.'
3818 for _m in range(icourse.moves):
3820 w = icourse.sector()
3821 if icourse.origin.quadrant() != icourse.location.quadrant():
3822 newquadrant(noattack)
3824 elif check_collision(w):
3825 print("Collision detected")
3829 # We're in destination quadrant -- compute new average enemy distances
3830 game.quad[game.sector.i][game.sector.j] = game.ship
3832 for enemy in game.enemies:
3833 finald = (w-enemy.location).distance()
3834 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3835 enemy.kdist = finald
3837 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3838 attack(torps_ok=False)
3839 for enemy in game.enemies:
3840 enemy.kavgd = enemy.kdist
3843 setwnd(message_window)
3847 "Dock our ship at a starbase."
3849 if game.condition == "docked" and verbose:
3850 prout(_("Already docked."))
3853 prout(_("You must first leave standard orbit."))
3855 if not game.base.is_valid() or abs(game.sector.i-game.base.i) > 1 or abs(game.sector.j-game.base.j) > 1:
3856 prout(crmshp() + _(" not adjacent to base."))
3859 prout(_("You cannot dock while cloaked."))
3861 game.condition = "docked"
3865 if game.energy < game.inenrg:
3866 game.energy = game.inenrg
3867 game.shield = game.inshld
3868 game.torps = game.intorps
3869 game.lsupres = game.inlsr
3870 game.state.crew = FULLCREW
3871 if game.brigcapacity-game.brigfree > 0:
3872 prout(_("%d captured Klingons transferred to base") % (game.brigcapacity-game.brigfree))
3873 game.kcaptured += game.brigcapacity-game.brigfree
3874 game.brigfree = game.brigcapacity
3875 if communicating() and \
3876 ((is_scheduled(FCDBAS) or game.isatb == 1) and not game.iseenit):
3877 # get attack report from base
3878 prout(_("Lt. Uhura- \"Captain, an important message from the starbase:\""))
3882 def cartesian(loc1=None, loc2=None):
3884 return game.quadrant * QUADSIZE + game.sector
3886 return game.quadrant * QUADSIZE + loc1
3888 return loc1 * QUADSIZE + loc2
3890 def getcourse(isprobe):
3891 "Get a course and distance from the user."
3893 dquad = copy.copy(game.quadrant)
3894 navmode = "unspecified"
3898 if game.landed and not isprobe:
3899 prout(_("Dummy! You can't leave standard orbit until you"))
3900 proutn(_("are back aboard the ship."))
3903 while navmode == "unspecified":
3904 if damaged(DNAVSYS):
3906 prout(_("Computer damaged; manual navigation only"))
3908 prout(_("Computer damaged; manual movement only"))
3913 key = scanner.nexttok()
3915 proutn(_("Manual or automatic- "))
3918 elif key == "IHALPHA":
3919 if scanner.sees("manual"):
3921 key = scanner.nexttok()
3923 elif scanner.sees("automatic"):
3924 navmode = "automatic"
3925 key = scanner.nexttok()
3933 prout(_("(Manual navigation assumed.)"))
3935 prout(_("(Manual movement assumed.)"))
3939 if navmode == "automatic":
3940 while key == "IHEOL":
3942 proutn(_("Target quadrant or quadrant§or- "))
3944 proutn(_("Destination sector or quadrant§or- "))
3947 key = scanner.nexttok()
3951 xi = int(round(scanner.real))-1
3952 key = scanner.nexttok()
3956 xj = int(round(scanner.real))-1
3957 key = scanner.nexttok()
3959 # both quadrant and sector specified
3960 xk = int(round(scanner.real))-1
3961 key = scanner.nexttok()
3965 xl = int(round(scanner.real))-1
3971 # only one pair of numbers was specified
3973 # only quadrant specified -- go to center of dest quad
3976 dsect.j = dsect.i = 4 # preserves 1-origin behavior
3978 # only sector specified
3982 if not dquad.valid_quadrant() or not dsect.valid_sector():
3989 prout(_("Helmsman Sulu- \"Course locked in for Sector %s.\"") % dsect)
3991 prout(_("Ensign Chekov- \"Course laid in, Captain.\""))
3992 # the actual deltas get computed here
3993 delta.j = dquad.j-game.quadrant.j + (dsect.j-game.sector.j)/(QUADSIZE*1.0)
3994 delta.i = game.quadrant.i-dquad.i + (game.sector.i-dsect.i)/(QUADSIZE*1.0)
3996 while key == "IHEOL":
3997 proutn(_("X and Y displacements- "))
4000 key = scanner.nexttok()
4003 delta.j = scanner.real
4007 key = scanner.nexttok()
4009 delta.i = scanner.real
4010 elif key == "IHEOL":
4016 # Check for zero movement
4017 if delta.i == 0 and delta.j == 0:
4020 if itemp == "verbose" and not isprobe:
4022 prout(_("Helmsman Sulu- \"Aye, Sir.\""))
4024 return course(bearing=delta.bearing(), distance=delta.distance())
4027 def __init__(self, bearing, distance, origin=None):
4028 self.distance = distance
4029 self.bearing = bearing
4031 self.origin = cartesian(game.quadrant, game.sector)
4033 self.origin = origin
4034 # The bearing() code we inherited from FORTRAN is actually computing
4035 # clockface directions!
4036 if self.bearing < 0.0:
4037 self.bearing += 12.0
4038 self.angle = ((15.0 - self.bearing) * 0.5235988)
4039 self.increment = Coord(-math.sin(self.angle), math.cos(self.angle))
4040 bigger = max(abs(self.increment.i), abs(self.increment.j))
4041 self.increment /= bigger
4042 self.moves = int(round(10*self.distance*bigger))
4044 self.final = (self.location + self.moves*self.increment).roundtogrid()
4045 self.location = self.origin
4046 self.nextlocation = None
4048 self.location = self.origin
4051 return self.location.roundtogrid() == self.final
4053 "Next step on course."
4055 self.nextlocation = self.location + self.increment
4056 samequad = (self.location.quadrant() == self.nextlocation.quadrant())
4057 self.location = self.nextlocation
4060 return self.location.quadrant()
4062 return self.location.sector()
4064 return self.distance*(w**3)*(game.shldup+1)
4066 return 10.0*self.distance/w**2
4069 "Move under impulse power."
4071 if damaged(DIMPULS):
4074 prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
4076 if game.energy > 30.0:
4078 icourse = getcourse(isprobe=False)
4081 power = 20.0 + 100.0*icourse.distance
4084 if power >= game.energy:
4085 # Insufficient power for trip
4087 prout(_("First Officer Spock- \"Captain, the impulse engines"))
4088 prout(_("require 20.0 units to engage, plus 100.0 units per"))
4089 if game.energy > 30:
4090 proutn(_("quadrant. We can go, therefore, a maximum of %d") %
4091 int(0.01 * (game.energy-20.0)-0.05))
4092 prout(_(" quadrants.\""))
4094 prout(_("quadrant. They are, therefore, useless.\""))
4097 # Make sure enough time is left for the trip
4098 game.optime = icourse.distance/0.095
4099 if game.optime >= game.state.remtime:
4100 prout(_("First Officer Spock- \"Captain, our speed under impulse"))
4101 prout(_("power is only 0.95 sectors per stardate. Are you sure"))
4102 proutn(_("we dare spend the time?\" "))
4105 # Activate impulse engines and pay the cost
4106 imove(icourse, noattack=False)
4110 power = 20.0 + 100.0*icourse.distance
4111 game.energy -= power
4112 game.optime = icourse.distance/0.095
4113 if game.energy <= 0:
4117 def warp(wcourse, involuntary):
4118 "ove under warp drive."
4119 blooey = False; twarp = False
4120 if not involuntary: # Not WARPX entry
4125 prout(_("Engineer Scott- \"The warp engines can not be used while cloaked, Sir.\""))
4127 if game.damage[DWARPEN] > 10.0:
4130 prout(_("Engineer Scott- \"The warp engines are damaged, Sir.\""))
4132 if damaged(DWARPEN) and game.warpfac > 4.0:
4135 prout(_("Engineer Scott- \"Sorry, Captain. Until this damage"))
4136 prout(_(" is repaired, I can only give you warp 4.\""))
4138 # Read in course and distance
4141 wcourse = getcourse(isprobe=False)
4144 # Make sure starship has enough energy for the trip
4145 # Note: this formula is slightly different from the C version,
4146 # and lets you skate a bit closer to the edge.
4147 if wcourse.power(game.warpfac) >= game.energy:
4148 # Insufficient power for trip
4151 prout(_("Engineering to bridge--"))
4152 if not game.shldup or 0.5*wcourse.power(game.warpfac) > game.energy:
4153 iwarp = (game.energy/(wcourse.distance+0.05)) ** 0.333333333
4155 prout(_("We can't do it, Captain. We don't have enough energy."))
4157 proutn(_("We don't have enough energy, but we could do it at warp %d") % iwarp)
4160 prout(_("if you'll lower the shields."))
4164 prout(_("We haven't the energy to go that far with the shields up."))
4166 # Make sure enough time is left for the trip
4167 game.optime = wcourse.time(game.warpfac)
4168 if game.optime >= 0.8*game.state.remtime:
4170 prout(_("First Officer Spock- \"Captain, I compute that such"))
4171 proutn(_(" a trip would require approximately %2.0f") %
4172 (100.0*game.optime/game.state.remtime))
4173 prout(_(" percent of our"))
4174 proutn(_(" remaining time. Are you sure this is wise?\" "))
4180 if game.warpfac > 6.0:
4181 # Decide if engine damage will occur
4182 # ESR: Seems wrong. Probability of damage goes *down* with distance?
4183 prob = wcourse.distance*(6.0-game.warpfac)**2/66.666666666
4184 if prob > randreal():
4186 wcourse.distance = randreal(wcourse.distance)
4187 # Decide if time warp will occur
4188 if 0.5*wcourse.distance*math.pow(7.0,game.warpfac-10.0) > randreal():
4190 if game.idebug and game.warpfac==10 and not twarp:
4192 proutn("=== Force time warp? ")
4196 # If time warp or engine damage, check path
4197 # If it is obstructed, don't do warp or damage
4198 look = wcourse.moves
4202 w = wcourse.sector()
4203 if not w.valid_sector():
4205 if game.quad[w.i][w.j] != '.':
4209 # Activate Warp Engines and pay the cost
4210 imove(wcourse, noattack=False)
4213 game.energy -= wcourse.power(game.warpfac)
4214 if game.energy <= 0:
4216 game.optime = wcourse.time(game.warpfac)
4220 game.damage[DWARPEN] = game.damfac * randreal(1.0, 4.0)
4222 prout(_("Engineering to bridge--"))
4223 prout(_(" Scott here. The warp engines are damaged."))
4224 prout(_(" We'll have to reduce speed to warp 4."))
4229 "Change the warp factor."
4231 key=scanner.nexttok()
4235 proutn(_("Warp factor- "))
4239 if game.damage[DWARPEN] > 10.0:
4240 prout(_("Warp engines inoperative."))
4242 if damaged(DWARPEN) and scanner.real > 4.0:
4243 prout(_("Engineer Scott- \"I'm doing my best, Captain,"))
4244 prout(_(" but right now we can only go warp 4.\""))
4246 if scanner.real > 10.0:
4247 prout(_("Helmsman Sulu- \"Our top speed is warp 10, Captain.\""))
4249 if scanner.real < 1.0:
4250 prout(_("Helmsman Sulu- \"We can't go below warp 1, Captain.\""))
4252 oldfac = game.warpfac
4253 game.warpfac = scanner.real
4254 if game.warpfac <= oldfac or game.warpfac <= 6.0:
4255 prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\"") %
4258 if game.warpfac < 8.00:
4259 prout(_("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\""))
4261 if game.warpfac == 10.0:
4262 prout(_("Engineer Scott- \"Aye, Captain, we'll try it.\""))
4264 prout(_("Engineer Scott- \"Aye, Captain, but our engines may not take it.\""))
4268 "Cope with being tossed out of quadrant by supernova or yanked by beam."
4270 # is captain on planet?
4272 if damaged(DTRANSP):
4275 prout(_("Scotty rushes to the transporter controls."))
4277 prout(_("But with the shields up it's hopeless."))
4279 prouts(_("His desperate attempt to rescue you . . ."))
4284 prout(_("SUCCEEDS!"))
4287 proutn(_("The crystals mined were "))
4295 # Check to see if captain in shuttle craft
4300 # Inform captain of attempt to reach safety
4304 prouts(_("***RED ALERT! RED ALERT!"))
4306 proutn(_("The %s has stopped in a quadrant containing") % crmshp())
4307 prouts(_(" a supernova."))
4309 prout(_("***Emergency automatic override attempts to hurl ")+crmshp())
4310 prout(_("safely out of quadrant."))
4311 if not damaged(DRADIO):
4312 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
4313 # Try to use warp engines
4314 if damaged(DWARPEN):
4316 prout(_("Warp engines damaged."))
4319 game.warpfac = randreal(6.0, 8.0)
4320 prout(_("Warp factor set to %d") % int(game.warpfac))
4321 power = 0.75*game.energy
4322 dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1))
4323 dist = max(dist, randreal(math.sqrt(2)))
4324 bugout = course(bearing=randreal(12), distance=dist) # How dumb!
4325 game.optime = bugout.time(game.warpfac)
4327 game.inorbit = False
4328 warp(bugout, involuntary=True)
4330 # This is bad news, we didn't leave quadrant.
4334 prout(_("Insufficient energy to leave quadrant."))
4337 # Repeat if another snova
4338 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
4341 finish(FWON) # Snova killed remaining enemy.
4344 "Let's do the time warp again."
4345 prout(_("***TIME WARP ENTERED."))
4346 if game.state.snap and withprob(0.5):
4348 prout(_("You are traveling backwards in time %d stardates.") %
4349 int(game.state.date-game.snapsht.date))
4350 game.state = game.snapsht
4351 game.state.snap = False
4352 if len(game.state.kcmdr):
4353 schedule(FTBEAM, expran(game.intime/len(game.state.kcmdr)))
4354 schedule(FBATTAK, expran(0.3*game.intime))
4355 schedule(FSNOVA, expran(0.5*game.intime))
4356 # next snapshot will be sooner
4357 schedule(FSNAP, expran(0.25*game.state.remtime))
4359 if game.state.nscrem:
4360 schedule(FSCMOVE, 0.2777)
4364 game.battle.invalidate()
4365 # Make sure Galileo is consistant -- Snapshot may have been taken
4366 # when on planet, which would give us two Galileos!
4368 for l in range(game.inplan):
4369 if game.state.planets[l].known == "shuttle_down":
4371 if game.iscraft == "onship" and game.ship=='E':
4372 prout(_("Chekov- \"Security reports the Galileo has disappeared, Sir!"))
4373 game.iscraft = "offship"
4374 # Likewise, if in the original time the Galileo was abandoned, but
4375 # was on ship earlier, it would have vanished -- let's restore it.
4376 if game.iscraft == "offship" and not gotit and game.damage[DSHUTTL] >= 0.0:
4377 prout(_("Chekov- \"Security reports the Galileo has reappeared in the dock!\""))
4378 game.iscraft = "onship"
4379 # There used to be code to do the actual reconstrction here,
4380 # but the starchart is now part of the snapshotted galaxy state.
4381 prout(_("Spock has reconstructed a correct star chart from memory"))
4383 # Go forward in time
4384 game.optime = expran(0.5*game.intime)
4385 prout(_("You are traveling forward in time %d stardates.") % int(game.optime))
4386 # cheat to make sure no tractor beams occur during time warp
4387 postpone(FTBEAM, game.optime)
4388 game.damage[DRADIO] += game.optime
4390 events() # Stas Sergeev added this -- do pending events
4393 "Launch deep-space probe."
4394 # New code to launch a deep space probe
4395 if game.nprobes == 0:
4398 if game.ship == 'E':
4399 prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\""))
4401 prout(_("Ye Faerie Queene has no deep space probes."))
4406 prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\""))
4408 if is_scheduled(FDSPROB):
4411 if damaged(DRADIO) and game.condition != "docked":
4412 prout(_("Spock- \"Records show the previous probe has not yet"))
4413 prout(_(" reached its destination.\""))
4415 prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""))
4417 key = scanner.nexttok()
4419 if game.nprobes == 1:
4420 prout(_("1 probe left."))
4422 prout(_("%d probes left") % game.nprobes)
4423 proutn(_("Are you sure you want to fire a probe? "))
4426 game.isarmed = False
4427 if key == "IHALPHA" and scanner.token == "armed":
4429 key = scanner.nexttok()
4430 elif key == "IHEOL":
4431 proutn(_("Arm NOVAMAX warhead? "))
4433 elif key == "IHREAL": # first element of course
4434 scanner.push(scanner.token)
4436 game.probe = getcourse(isprobe=True)
4440 schedule(FDSPROB, 0.01) # Time to move one sector
4441 prout(_("Ensign Chekov- \"The deep space probe is launched, Captain.\""))
4446 "Yell for help from nearest starbase."
4447 # There's more than one way to move in this game!
4449 # Test for conditions which prevent calling for help
4450 if game.condition == "docked":
4451 prout(_("Lt. Uhura- \"But Captain, we're already docked.\""))
4454 prout(_("Subspace radio damaged."))
4456 if not game.state.baseq:
4457 prout(_("Lt. Uhura- \"Captain, I'm not getting any response from Starbase.\""))
4460 prout(_("You must be aboard the %s.") % crmshp())
4462 # OK -- call for help from nearest starbase
4465 # There's one in this quadrant
4466 ddist = (game.base - game.sector).distance()
4468 ibq = None # Force base-quadrant game to persist past loop
4470 for ibq in game.state.baseq:
4471 xdist = QUADSIZE * (ibq - game.quadrant).distance()
4475 prout(_("No starbases remain. You are alone in a hostile galaxy."))
4477 # Since starbase not in quadrant, set up new quadrant
4480 # dematerialize starship
4481 game.quad[game.sector.i][game.sector.j]='.'
4482 proutn(_("Starbase in Quadrant %s responds--%s dematerializes") \
4483 % (game.quadrant, crmshp()))
4484 game.sector.invalidate()
4485 for m in range(1, 5+1):
4486 w = game.base.scatter()
4487 if w.valid_sector() and game.quad[w.i][w.j]=='.':
4488 # found one -- finish up
4491 if not game.sector.is_valid():
4492 prout(_("You have been lost in space..."))
4493 finish(FMATERIALIZE)
4495 # Give starbase three chances to rematerialize starship
4496 probf = math.pow((1.0 - math.pow(0.98,ddist)), 0.33333333)
4497 for m in range(1, 3+1):
4498 if m == 1: proutn(_("1st"))
4499 elif m == 2: proutn(_("2nd"))
4500 elif m == 3: proutn(_("3rd"))
4501 proutn(_(" attempt to re-materialize ") + crmshp())
4502 game.quad[game.sector.i][game.sector.j]=('-','o','O')[m-1]
4505 if randreal() > probf:
4509 curses.delay_output(500)
4511 game.quad[game.sector.i][game.sector.j]='?'
4514 setwnd(message_window)
4515 finish(FMATERIALIZE)
4517 game.quad[game.sector.i][game.sector.j]=game.ship
4519 prout(_("succeeds."))
4523 prout(_("Lt. Uhura- \"Captain, we made it!\""))
4528 if game.condition=="docked":
4530 prout(_("You cannot abandon Ye Faerie Queene."))
4533 # Must take shuttle craft to exit
4534 if game.damage[DSHUTTL]==-1:
4535 prout(_("Ye Faerie Queene has no shuttle craft."))
4537 if game.damage[DSHUTTL]<0:
4538 prout(_("Shuttle craft now serving Big Macs."))
4540 if game.damage[DSHUTTL]>0:
4541 prout(_("Shuttle craft damaged."))
4544 prout(_("You must be aboard the ship."))
4546 if game.iscraft != "onship":
4547 prout(_("Shuttle craft not currently available."))
4549 # Emit abandon ship messages
4551 prouts(_("***ABANDON SHIP! ABANDON SHIP!"))
4553 prouts(_("***ALL HANDS ABANDON SHIP!"))
4555 prout(_("Captain and crew escape in shuttle craft."))
4556 if not game.state.baseq:
4557 # Oops! no place to go...
4560 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
4562 if not (game.options & OPTION_WORLDS) and not damaged(DTRANSP):
4563 prout(_("Remainder of ship's complement beam down"))
4564 prout(_("to nearest habitable planet."))
4565 elif q.planet != None and not damaged(DTRANSP):
4566 prout(_("Remainder of ship's complement beam down to %s.") %
4569 prout(_("Entire crew of %d left to die in outer space.") %
4571 game.casual += game.state.crew
4572 game.abandoned += game.state.crew
4573 # If at least one base left, give 'em the Faerie Queene
4575 game.icrystl = False # crystals are lost
4576 game.nprobes = 0 # No probes
4577 prout(_("You are captured by Klingons and released to"))
4578 prout(_("the Federation in a prisoner-of-war exchange."))
4579 nb = randrange(len(game.state.baseq))
4580 # Set up quadrant and position FQ adjacient to base
4581 if not game.quadrant == game.state.baseq[nb]:
4582 game.quadrant = game.state.baseq[nb]
4583 game.sector.i = game.sector.j = 5
4586 # position next to base by trial and error
4587 game.quad[game.sector.i][game.sector.j] = '.'
4589 for l in range(QUADSIZE):
4590 game.sector = game.base.scatter()
4591 if game.sector.valid_sector() and \
4592 game.quad[game.sector.i][game.sector.j] == '.':
4595 break # found a spot
4596 game.sector.i=QUADSIZE/2
4597 game.sector.j=QUADSIZE/2
4599 # Get new commission
4600 game.quad[game.sector.i][game.sector.j] = game.ship = 'F'
4601 game.state.crew = FULLCREW
4602 prout(_("Starfleet puts you in command of another ship,"))
4603 prout(_("the Faerie Queene, which is antiquated but,"))
4604 prout(_("still useable."))
4606 prout(_("The dilithium crystals have been moved."))
4608 game.iscraft = "offship" # Galileo disappears
4610 game.condition="docked"
4611 for l in range(NDEVICES):
4612 game.damage[l] = 0.0
4613 game.damage[DSHUTTL] = -1
4614 game.energy = game.inenrg = 3000.0
4615 game.shield = game.inshld = 1250.0
4616 game.torps = game.intorps = 6
4617 game.lsupres=game.inlsr=3.0
4620 game.brigfree = game.brigcapacity = 300
4623 # Code from planets.c begins here.
4626 "Abort a lengthy operation if an event interrupts it."
4629 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.justin:
4634 "Report on (uninhabited) planets in the galaxy."
4638 prout(_("Spock- \"Planet report follows, Captain.\""))
4640 for i in range(game.inplan):
4641 if game.state.planets[i].pclass == "destroyed":
4643 if (game.state.planets[i].known != "unknown" \
4644 and not game.state.planets[i].inhabited) \
4647 if game.idebug and game.state.planets[i].known=="unknown":
4648 proutn("(Unknown) ")
4649 proutn(_("Quadrant %s") % game.state.planets[i].quadrant)
4650 proutn(_(" class "))
4651 proutn(game.state.planets[i].pclass)
4653 if game.state.planets[i].crystals != "present":
4655 prout(_("dilithium crystals present."))
4656 if game.state.planets[i].known=="shuttle_down":
4657 prout(_(" Shuttle Craft Galileo on surface."))
4659 prout(_("No information available."))
4662 "Enter standard orbit."
4666 prout(_("Already in standard orbit."))
4668 if damaged(DWARPEN) and damaged(DIMPULS):
4669 prout(_("Both warp and impulse engines damaged."))
4671 if not game.plnet.is_valid():
4672 prout("There is no planet in this sector.")
4674 if abs(game.sector.i-game.plnet.i)>1 or abs(game.sector.j-game.plnet.j)>1:
4675 prout(crmshp() + _(" not adjacent to planet."))
4678 game.optime = randreal(0.02, 0.05)
4679 prout(_("Helmsman Sulu- \"Entering standard orbit, Sir.\""))
4683 game.height = randreal(1400, 8600)
4684 prout(_("Sulu- \"Entered orbit at altitude %.2f kilometers.\"") % game.height)
4689 "Examine planets in this quadrant."
4690 if damaged(DSRSENS):
4691 if game.options & OPTION_TTY:
4692 prout(_("Short range sensors damaged."))
4694 if game.iplnet is None:
4695 if game.options & OPTION_TTY:
4696 prout(_("Spock- \"No planet in this quadrant, Captain.\""))
4698 if game.iplnet.known == "unknown":
4699 prout(_("Spock- \"Sensor scan for Quadrant %s-") % game.quadrant)
4701 prout(_(" Planet at Sector %s is of class %s.") %
4702 (game.plnet, game.iplnet.pclass))
4703 if game.iplnet.known=="shuttle_down":
4704 prout(_(" Sensors show Galileo still on surface."))
4705 proutn(_(" Readings indicate"))
4706 if game.iplnet.crystals != "present":
4708 prout(_(" dilithium crystals present.\""))
4709 if game.iplnet.known == "unknown":
4710 game.iplnet.known = "known"
4711 elif game.iplnet.inhabited:
4712 prout(_("Spock- \"The inhabited planet %s ") % game.iplnet.name)
4713 prout(_(" is located at Sector %s, Captain.\"") % game.plnet)
4716 "Use the transporter."
4720 if damaged(DTRANSP):
4721 prout(_("Transporter damaged."))
4722 if not damaged(DSHUTTL) and (game.iplnet.known=="shuttle_down" or game.iscraft == "onship"):
4724 proutn(_("Spock- \"May I suggest the shuttle craft, Sir?\" "))
4728 if not game.inorbit:
4729 prout(crmshp() + _(" not in standard orbit."))
4732 prout(_("Impossible to transport through shields."))
4734 if game.iplnet.known=="unknown":
4735 prout(_("Spock- \"Captain, we have no information on this planet"))
4736 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4737 prout(_(" you may not go down.\""))
4739 if not game.landed and game.iplnet.crystals=="absent":
4740 prout(_("Spock- \"Captain, I fail to see the logic in"))
4741 prout(_(" exploring a planet with no dilithium crystals."))
4742 proutn(_(" Are you sure this is wise?\" "))
4746 if not (game.options & OPTION_PLAIN):
4747 nrgneed = 50 * game.skill + game.height / 100.0
4748 if nrgneed > game.energy:
4749 prout(_("Engineering to bridge--"))
4750 prout(_(" Captain, we don't have enough energy for transportation."))
4752 if not game.landed and nrgneed * 2 > game.energy:
4753 prout(_("Engineering to bridge--"))
4754 prout(_(" Captain, we have enough energy only to transport you down to"))
4755 prout(_(" the planet, but there wouldn't be an energy for the trip back."))
4756 if game.iplnet.known == "shuttle_down":
4757 prout(_(" Although the Galileo shuttle craft may still be on a surface."))
4758 proutn(_(" Are you sure this is wise?\" "))
4763 # Coming from planet
4764 if game.iplnet.known=="shuttle_down":
4765 proutn(_("Spock- \"Wouldn't you rather take the Galileo?\" "))
4769 prout(_("Your crew hides the Galileo to prevent capture by aliens."))
4770 prout(_("Landing party assembled, ready to beam up."))
4772 prout(_("Kirk whips out communicator..."))
4773 prouts(_("BEEP BEEP BEEP"))
4775 prout(_("\"Kirk to enterprise- Lock on coordinates...energize.\""))
4778 prout(_("Scotty- \"Transporter room ready, Sir.\""))
4780 prout(_("Kirk and landing party prepare to beam down to planet surface."))
4782 prout(_("Kirk- \"Energize.\""))
4785 prouts("WWHOOOIIIIIRRRRREEEE.E.E. . . . . . .")
4787 if not withprob(0.98):
4788 prouts("BOOOIIIOOOIIOOOOIIIOIING . . .")
4790 prout(_("Scotty- \"Oh my God! I've lost them.\""))
4793 prouts(". . . . . . .E.E.EEEERRRRRIIIIIOOOHWW")
4794 game.landed = not game.landed
4795 game.energy -= nrgneed
4797 prout(_("Transport complete."))
4798 if game.landed and game.iplnet.known=="shuttle_down":
4799 prout(_("The shuttle craft Galileo is here!"))
4800 if not game.landed and game.imine:
4807 "Strip-mine a world for dilithium."
4811 prout(_("Mining party not on planet."))
4813 if game.iplnet.crystals == "mined":
4814 prout(_("This planet has already been strip-mined for dilithium."))
4816 elif game.iplnet.crystals == "absent":
4817 prout(_("No dilithium crystals on this planet."))
4820 prout(_("You've already mined enough crystals for this trip."))
4822 if game.icrystl and game.cryprob == 0.05:
4823 prout(_("With all those fresh crystals aboard the ") + crmshp())
4824 prout(_("there's no reason to mine more at this time."))
4826 game.optime = randreal(0.1, 0.3)*(ord(game.iplnet.pclass)-ord("L"))
4829 prout(_("Mining operation complete."))
4830 game.iplnet.crystals = "mined"
4831 game.imine = game.ididit = True
4834 "Use dilithium crystals."
4838 if not game.icrystl:
4839 prout(_("No dilithium crystals available."))
4841 if game.energy >= 1000:
4842 prout(_("Spock- \"Captain, Starfleet Regulations prohibit such an operation"))
4843 prout(_(" except when Condition Yellow exists."))
4845 prout(_("Spock- \"Captain, I must warn you that loading"))
4846 prout(_(" raw dilithium crystals into the ship's power"))
4847 prout(_(" system may risk a severe explosion."))
4848 proutn(_(" Are you sure this is wise?\" "))
4853 prout(_("Engineering Officer Scott- \"(GULP) Aye Sir."))
4854 prout(_(" Mr. Spock and I will try it.\""))
4856 prout(_("Spock- \"Crystals in place, Sir."))
4857 prout(_(" Ready to activate circuit.\""))
4859 prouts(_("Scotty- \"Keep your fingers crossed, Sir!\""))
4861 if withprob(game.cryprob):
4862 prouts(_(" \"Activating now! - - No good! It's***"))
4864 prouts(_("***RED ALERT! RED A*L********************************"))
4867 prouts(_("****************** KA-BOOM!!!! *******************"))
4871 game.energy += randreal(5000.0, 5500.0)
4872 prouts(_(" \"Activating now! - - "))
4873 prout(_("The instruments"))
4874 prout(_(" are going crazy, but I think it's"))
4875 prout(_(" going to work!! Congratulations, Sir!\""))
4880 "Use shuttlecraft for planetary jaunt."
4883 if damaged(DSHUTTL):
4884 if game.damage[DSHUTTL] == -1.0:
4885 if game.inorbit and game.iplnet.known == "shuttle_down":
4886 prout(_("Ye Faerie Queene has no shuttle craft bay to dock it at."))
4888 prout(_("Ye Faerie Queene had no shuttle craft."))
4889 elif game.damage[DSHUTTL] > 0:
4890 prout(_("The Galileo is damaged."))
4891 else: # game.damage[DSHUTTL] < 0
4892 prout(_("Shuttle craft is now serving Big Macs."))
4894 if not game.inorbit:
4895 prout(crmshp() + _(" not in standard orbit."))
4897 if (game.iplnet.known != "shuttle_down") and game.iscraft != "onship":
4898 prout(_("Shuttle craft not currently available."))
4900 if not game.landed and game.iplnet.known=="shuttle_down":
4901 prout(_("You will have to beam down to retrieve the shuttle craft."))
4903 if game.shldup or game.condition == "docked":
4904 prout(_("Shuttle craft cannot pass through shields."))
4906 if game.iplnet.known=="unknown":
4907 prout(_("Spock- \"Captain, we have no information on this planet"))
4908 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4909 prout(_(" you may not fly down.\""))
4911 game.optime = 3.0e-5*game.height
4912 if game.optime >= 0.8*game.state.remtime:
4913 prout(_("First Officer Spock- \"Captain, I compute that such"))
4914 proutn(_(" a maneuver would require approximately %2d%% of our") % \
4915 int(100*game.optime/game.state.remtime))
4916 prout(_("remaining time."))
4917 proutn(_("Are you sure this is wise?\" "))
4923 if game.iscraft == "onship":
4925 if not damaged(DTRANSP):
4926 proutn(_("Spock- \"Would you rather use the transporter?\" "))
4930 proutn(_("Shuttle crew"))
4932 proutn(_("Rescue party"))
4933 prout(_(" boards Galileo and swoops toward planet surface."))
4934 game.iscraft = "offship"
4938 game.iplnet.known="shuttle_down"
4939 prout(_("Trip complete."))
4942 # Ready to go back to ship
4943 prout(_("You and your mining party board the"))
4944 prout(_("shuttle craft for the trip back to the Enterprise."))
4946 prouts(_("The short hop begins . . ."))
4948 game.iplnet.known="known"
4954 game.iscraft = "onship"
4960 prout(_("Trip complete."))
4963 # Kirk on ship and so is Galileo
4964 prout(_("Mining party assembles in the hangar deck,"))
4965 prout(_("ready to board the shuttle craft \"Galileo\"."))
4967 prouts(_("The hangar doors open; the trip begins."))
4970 game.iscraft = "offship"
4973 game.iplnet.known = "shuttle_down"
4976 prout(_("Trip complete."))
4980 "Use the big zapper."
4984 if game.ship != 'E':
4985 prout(_("Ye Faerie Queene has no death ray."))
4987 if len(game.enemies)==0:
4988 prout(_("Sulu- \"But Sir, there are no enemies in this quadrant.\""))
4991 prout(_("Death Ray is damaged."))
4993 prout(_("Spock- \"Captain, the 'Experimental Death Ray'"))
4994 prout(_(" is highly unpredictible. Considering the alternatives,"))
4995 proutn(_(" are you sure this is wise?\" "))
4998 prout(_("Spock- \"Acknowledged.\""))
5001 prouts(_("WHOOEE ... WHOOEE ... WHOOEE ... WHOOEE"))
5003 prout(_("Crew scrambles in emergency preparation."))
5004 prout(_("Spock and Scotty ready the death ray and"))
5005 prout(_("prepare to channel all ship's power to the device."))
5007 prout(_("Spock- \"Preparations complete, sir.\""))
5008 prout(_("Kirk- \"Engage!\""))
5010 prouts(_("WHIRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"))
5013 if game.options & OPTION_PLAIN:
5017 prouts(_("Sulu- \"Captain! It's working!\""))
5019 while len(game.enemies) > 0:
5020 deadkl(game.enemies[1].location, game.quad[game.enemies[1].location.i][game.enemies[1].location.j],game.enemies[1].location)
5021 prout(_("Ensign Chekov- \"Congratulations, Captain!\""))
5022 if game.unwon() == 0:
5024 if (game.options & OPTION_PLAIN) == 0:
5025 prout(_("Spock- \"Captain, I believe the `Experimental Death Ray'"))
5027 prout(_(" is still operational.\""))
5029 prout(_(" has been rendered nonfunctional.\""))
5030 game.damage[DDRAY] = 39.95
5032 r = randreal() # Pick failure method
5034 prouts(_("Sulu- \"Captain! It's working!\""))
5036 prouts(_("***RED ALERT! RED ALERT!"))
5038 prout(_("***MATTER-ANTIMATTER IMPLOSION IMMINENT!"))
5040 prouts(_("***RED ALERT! RED A*L********************************"))
5043 prouts(_("****************** KA-BOOM!!!! *******************"))
5048 prouts(_("Sulu- \"Captain! Yagabandaghangrapl, brachriigringlanbla!\""))
5050 prout(_("Lt. Uhura- \"Graaeek! Graaeek!\""))
5052 prout(_("Spock- \"Fascinating! . . . All humans aboard"))
5053 prout(_(" have apparently been transformed into strange mutations."))
5054 prout(_(" Vulcans do not seem to be affected."))
5056 prout(_("Kirk- \"Raauch! Raauch!\""))
5060 prouts(_("Sulu- \"Captain! It's --WHAT?!?!\""))
5062 proutn(_("Spock- \"I believe the word is"))
5063 prouts(_(" *ASTONISHING*"))
5064 prout(_(" Mr. Sulu."))
5065 for i in range(QUADSIZE):
5066 for j in range(QUADSIZE):
5067 if game.quad[i][j] == '.':
5068 game.quad[i][j] = '?'
5069 prout(_(" Captain, our quadrant is now infested with"))
5070 prouts(_(" - - - - - - *THINGS*."))
5072 prout(_(" I have no logical explanation.\""))
5074 prouts(_("Sulu- \"Captain! The Death Ray is creating tribbles!\""))
5076 prout(_("Scotty- \"There are so many tribbles down here"))
5077 prout(_(" in Engineering, we can't move for 'em, Captain.\""))
5081 # Code from reports.c begins here
5083 def attackreport(curt):
5084 "eport status of bases under attack."
5086 if is_scheduled(FCDBAS):
5087 prout(_("Starbase in Quadrant %s is currently under Commander attack.") % game.battle)
5088 prout(_("It can hold out until Stardate %d.") % int(scheduled(FCDBAS)))
5089 elif game.isatb == 1:
5090 prout(_("Starbase in Quadrant %s is under Super-commander attack.") % game.state.kscmdr)
5091 prout(_("It can hold out until Stardate %d.") % int(scheduled(FSCDBAS)))
5093 prout(_("No Starbase is currently under attack."))
5095 if is_scheduled(FCDBAS):
5096 proutn(_("Base in %s attacked by C. Alive until %.1f") % (game.battle, scheduled(FCDBAS)))
5098 proutn(_("Base in %s attacked by S. Alive until %.1f") % (game.state.kscmdr, scheduled(FSCDBAS)))
5102 # report on general game status
5104 s1 = (game.thawed and _("thawed ")) or ""
5105 s2 = {1:"short", 2:"medium", 4:"long"}[game.length]
5106 s3 = (None, _("novice"), _("fair"),
5107 _("good"), _("expert"), _("emeritus"))[game.skill]
5108 prout(_("You %s a %s%s %s game.") % ((_("were playing"), _("are playing"))[game.alldone], s1, s2, s3))
5109 if game.skill>SKILL_GOOD and game.thawed and not game.alldone:
5110 prout(_("No plaque is allowed."))
5112 prout(_("This is tournament game %d.") % game.tourn)
5113 prout(_("Your secret password is \"%s\"") % game.passwd)
5114 proutn(_("%d of %d Klingons have been killed") % (((game.inkling + game.incom + game.inscom) - game.unwon()),
5115 (game.inkling + game.incom + game.inscom)))
5116 if game.incom - len(game.state.kcmdr):
5117 prout(_(", including %d Commander%s.") % (game.incom - len(game.state.kcmdr), (_("s"), "")[(game.incom - len(game.state.kcmdr))==1]))
5118 elif game.inkling - game.state.remkl + (game.inscom - game.state.nscrem) > 0:
5119 prout(_(", but no Commanders."))
5122 if game.skill > SKILL_FAIR:
5123 prout(_("The Super Commander has %sbeen destroyed.") % ("", _("not "))[game.state.nscrem])
5124 if len(game.state.baseq) != game.inbase:
5126 if game.inbase-len(game.state.baseq)==1:
5127 proutn(_("has been 1 base"))
5129 proutn(_("have been %d bases") % (game.inbase-len(game.state.baseq)))
5130 prout(_(" destroyed, %d remaining.") % len(game.state.baseq))
5132 prout(_("There are %d bases.") % game.inbase)
5133 if communicating() or game.iseenit:
5134 # Don't report this if not seen and
5135 # either the radio is dead or not at base!
5139 prout(_("%d casualt%s suffered so far.") % (game.casual, ("y", "ies")[game.casual!=1]))
5140 if game.brigcapacity != game.brigfree:
5141 embriggened = brigcapacity-brigfree
5142 if embriggened == 1:
5143 prout(_("1 Klingon in brig"))
5145 prout(_("%d Klingons in brig.") % embriggened)
5146 if game.kcaptured == 0:
5148 elif game.kcaptured == 1:
5149 prout(_("1 captured Klingon turned in to Starfleet."))
5151 prout(_("%d captured Klingons turned in to Star Fleet.") % game.kcaptured)
5153 prout(_("There were %d call%s for help.") % (game.nhelp, ("" , _("s"))[game.nhelp!=1]))
5154 if game.ship == 'E':
5155 proutn(_("You have "))
5157 proutn("%d" % (game.nprobes))
5160 proutn(_(" deep space probe"))
5164 if communicating() and is_scheduled(FDSPROB):
5166 proutn(_("An armed deep space probe is in "))
5168 proutn(_("A deep space probe is in "))
5169 prout("Quadrant %s." % game.probe.quadrant())
5171 if game.cryprob <= .05:
5172 prout(_("Dilithium crystals aboard ship... not yet used."))
5176 while game.cryprob > ai:
5179 prout(_("Dilithium crystals have been used %d time%s.") % \
5180 (i, (_("s"), "")[i==1]))
5184 "Long-range sensor scan."
5185 if damaged(DLRSENS):
5186 # Now allow base's sensors if docked
5187 if game.condition != "docked":
5189 prout(_("LONG-RANGE SENSORS DAMAGED."))
5192 prout(_("Starbase's long-range scan"))
5194 prout(_("Long-range scan"))
5195 for x in range(game.quadrant.i-1, game.quadrant.i+2):
5198 for y in range(game.quadrant.j-1, game.quadrant.j+2):
5199 if not Coord(x, y).valid_quadrant():
5203 if not damaged(DRADIO):
5204 game.state.galaxy[x][y].charted = True
5205 game.state.chart[x][y].klingons = game.state.galaxy[x][y].klingons
5206 game.state.chart[x][y].starbase = game.state.galaxy[x][y].starbase
5207 game.state.chart[x][y].stars = game.state.galaxy[x][y].stars
5208 if not silent and game.state.galaxy[x][y].supernova:
5211 cn = " %3d" % (game.state.chart[x][y].klingons*100 + game.state.chart[x][y].starbase * 10 + game.state.chart[x][y].stars)
5212 proutn(((3 - len(cn)) * '.') + cn)
5220 for i in range(NDEVICES):
5223 prout(_("\tDEVICE\t\t\t-REPAIR TIMES-"))
5224 prout(_("\t\t\tIN FLIGHT\t\tDOCKED"))
5226 prout(" %-26s\t%8.2f\t\t%8.2f" % (device[i],
5227 game.damage[i]+0.05,
5228 DOCKFAC*game.damage[i]+0.005))
5230 prout(_("All devices functional."))
5233 "Update the chart in the Enterprise's computer from galaxy data."
5234 game.lastchart = game.state.date
5235 for i in range(GALSIZE):
5236 for j in range(GALSIZE):
5237 if game.state.galaxy[i][j].charted:
5238 game.state.chart[i][j].klingons = game.state.galaxy[i][j].klingons
5239 game.state.chart[i][j].starbase = game.state.galaxy[i][j].starbase
5240 game.state.chart[i][j].stars = game.state.galaxy[i][j].stars
5243 "Display the star chart."
5245 if (game.options & OPTION_AUTOSCAN):
5249 if game.lastchart < game.state.date and game.condition == "docked":
5250 prout(_("Spock- \"I revised the Star Chart from the starbase's records.\""))
5252 prout(_(" STAR CHART FOR THE KNOWN GALAXY"))
5253 if game.state.date > game.lastchart:
5254 prout(_("(Last surveillance update %d stardates ago).") % ((int)(game.state.date-game.lastchart)))
5255 prout(" 1 2 3 4 5 6 7 8")
5256 for i in range(GALSIZE):
5257 proutn("%d |" % (i+1))
5258 for j in range(GALSIZE):
5259 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5263 if game.state.galaxy[i][j].supernova:
5265 elif not game.state.galaxy[i][j].charted and game.state.galaxy[i][j].starbase:
5267 elif game.state.galaxy[i][j].charted:
5268 show = "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars)
5272 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5280 def sectscan(goodScan, i, j):
5281 "Light up an individual dot in a sector."
5282 if goodScan or (abs(i-game.sector.i)<= 1 and abs(j-game.sector.j) <= 1):
5283 if game.quad[i][j] in ('E', 'F'):
5286 textcolor({"green":GREEN,
5290 "dead":BROWN}[game.condition])
5292 textcolor({'?':LIGHTMAGENTA,
5298 }.get(game.quad[i][j], DEFAULT))
5299 proutn("%c " % game.quad[i][j])
5305 "Emit status report lines"
5306 if not req or req == 1:
5307 prstat(_("Stardate"), _("%.1f, Time Left %.2f") \
5308 % (game.state.date, game.state.remtime))
5309 if not req or req == 2:
5310 if game.condition != "docked":
5312 prstat(_("Condition"), _("%s, %i DAMAGES") % \
5313 (game.condition.upper(), sum([x > 0 for x in game.damage])))
5315 prout(_(", CLOAKED"))
5316 if not req or req == 3:
5317 prstat(_("Position"), "%s , %s" % (game.quadrant, game.sector))
5318 if not req or req == 4:
5319 if damaged(DLIFSUP):
5320 if game.condition == "docked":
5321 s = _("DAMAGED, Base provides")
5323 s = _("DAMAGED, reserves=%4.2f") % game.lsupres
5326 prstat(_("Life Support"), s)
5327 if not req or req == 5:
5328 prstat(_("Warp Factor"), "%.1f" % game.warpfac)
5329 if not req or req == 6:
5331 if game.icrystl and (game.options & OPTION_SHOWME):
5332 extra = _(" (have crystals)")
5333 prstat(_("Energy"), "%.2f%s" % (game.energy, extra))
5334 if not req or req == 7:
5335 prstat(_("Torpedoes"), "%d" % (game.torps))
5336 if not req or req == 8:
5337 if damaged(DSHIELD):
5343 data = _(" %d%% %.1f units") \
5344 % (int((100.0*game.shield)/game.inshld + 0.5), game.shield)
5345 prstat(_("Shields"), s+data)
5346 if not req or req == 9:
5347 prstat(_("Klingons Left"), "%d" % game.unwon())
5348 if not req or req == 10:
5349 if game.options & OPTION_WORLDS:
5350 plnet = game.state.galaxy[game.quadrant.i][game.quadrant.j].planet
5351 if plnet and plnet.inhabited:
5352 prstat(_("Major system"), plnet.name)
5354 prout(_("Sector is uninhabited"))
5355 elif not req or req == 11:
5356 attackreport(not req)
5359 "Request specified status data, a historical relic from slow TTYs."
5360 requests = ("da","co","po","ls","wa","en","to","sh","kl","sy", "ti")
5361 while scanner.nexttok() == "IHEOL":
5362 proutn(_("Information desired? "))
5364 if scanner.token in requests:
5365 status(requests.index(scanner.token))
5367 prout(_("UNRECOGNIZED REQUEST. Legal requests are:"))
5368 prout((" date, condition, position, lsupport, warpfactor,"))
5369 prout((" energy, torpedoes, shields, klingons, system, time."))
5374 if damaged(DSRSENS):
5375 # Allow base's sensors if docked
5376 if game.condition != "docked":
5377 prout(_(" S.R. SENSORS DAMAGED!"))
5380 prout(_(" [Using Base's sensors]"))
5382 prout(_(" Short-range scan"))
5383 if goodScan and communicating():
5384 game.state.chart[game.quadrant.i][game.quadrant.j].klingons = game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons
5385 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase
5386 game.state.chart[game.quadrant.i][game.quadrant.j].stars = game.state.galaxy[game.quadrant.i][game.quadrant.j].stars
5387 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
5388 prout(" 1 2 3 4 5 6 7 8 9 10")
5389 if game.condition != "docked":
5391 for i in range(QUADSIZE):
5392 proutn("%2d " % (i+1))
5393 for j in range(QUADSIZE):
5394 sectscan(goodScan, i, j)
5398 "Use computer to get estimated time of arrival for a warp jump."
5399 w1 = Coord(); w2 = Coord()
5401 if damaged(DCOMPTR):
5402 prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR."))
5405 if scanner.nexttok() != "IHREAL":
5408 proutn(_("Destination quadrant and/or sector? "))
5409 if scanner.nexttok()!="IHREAL":
5412 w1.j = int(scanner.real-0.5)
5413 if scanner.nexttok() != "IHREAL":
5416 w1.i = int(scanner.real-0.5)
5417 if scanner.nexttok() == "IHREAL":
5418 w2.j = int(scanner.real-0.5)
5419 if scanner.nexttok() != "IHREAL":
5422 w2.i = int(scanner.real-0.5)
5424 if game.quadrant.j>w1.i:
5428 if game.quadrant.i>w1.j:
5432 if not w1.valid_quadrant() or not w2.valid_sector():
5435 dist = math.sqrt((w1.j-game.quadrant.j+(w2.j-game.sector.j)/(QUADSIZE*1.0))**2+
5436 (w1.i-game.quadrant.i+(w2.i-game.sector.i)/(QUADSIZE*1.0))**2)
5439 prout(_("Answer \"no\" if you don't know the value:"))
5442 proutn(_("Time or arrival date? "))
5443 if scanner.nexttok()=="IHREAL":
5444 ttime = scanner.real
5445 if ttime > game.state.date:
5446 ttime -= game.state.date # Actually a star date
5447 twarp=(math.floor(math.sqrt((10.0*dist)/ttime)*10.0)+1.0)/10.0
5448 if ttime <= 1e-10 or twarp > 10:
5449 prout(_("We'll never make it, sir."))
5456 proutn(_("Warp factor? "))
5457 if scanner.nexttok()== "IHREAL":
5459 twarp = scanner.real
5460 if twarp<1.0 or twarp > 10.0:
5464 prout(_("Captain, certainly you can give me one of these."))
5467 ttime = (10.0*dist)/twarp**2
5468 tpower = dist*twarp*twarp*twarp*(game.shldup+1)
5469 if tpower >= game.energy:
5470 prout(_("Insufficient energy, sir."))
5471 if not game.shldup or tpower > game.energy*2.0:
5474 proutn(_("New warp factor to try? "))
5475 if scanner.nexttok() == "IHREAL":
5477 twarp = scanner.real
5478 if twarp<1.0 or twarp > 10.0:
5486 prout(_("But if you lower your shields,"))
5487 proutn(_("remaining"))
5490 proutn(_("Remaining"))
5491 prout(_(" energy will be %.2f.") % (game.energy-tpower))
5493 prout(_("And we will arrive at stardate %.2f.") % (game.state.date+ttime))
5495 prout(_("Any warp speed is adequate."))
5497 prout(_("Minimum warp needed is %.2f,") % (twarp))
5498 prout(_("and we will arrive at stardate %.2f.") % (game.state.date+ttime))
5499 if game.state.remtime < ttime:
5500 prout(_("Unfortunately, the Federation will be destroyed by then."))
5502 prout(_("You'll be taking risks at that speed, Captain"))
5503 if (game.isatb==1 and game.state.kscmdr == w1 and \
5504 scheduled(FSCDBAS)< ttime+game.state.date) or \
5505 (scheduled(FCDBAS)<ttime+game.state.date and game.battle == w1):
5506 prout(_("The starbase there will be destroyed by then."))
5507 proutn(_("New warp factor to try? "))
5508 if scanner.nexttok() == "IHREAL":
5510 twarp = scanner.real
5511 if twarp<1.0 or twarp > 10.0:
5519 # Code from setup.c begins here
5522 "Issue a historically correct banner."
5524 prout(_("-SUPER- STAR TREK"))
5526 # From the FORTRAN original
5527 # prout(_("Latest update-21 Sept 78"))
5533 scanner.push("emsave.trk")
5534 key = scanner.nexttok()
5536 proutn(_("File name: "))
5537 key = scanner.nexttok()
5538 if key != "IHALPHA":
5541 if '.' not in scanner.token:
5542 scanner.token += ".trk"
5544 fp = open(scanner.token, "wb")
5546 prout(_("Can't freeze game as file %s") % scanner.token)
5548 pickle.dump(game, fp)
5553 "Retrieve saved game."
5556 key = scanner.nexttok()
5558 proutn(_("File name: "))
5559 key = scanner.nexttok()
5560 if key != "IHALPHA":
5563 if '.' not in scanner.token:
5564 scanner.token += ".trk"
5566 fp = open(scanner.token, "rb")
5568 prout(_("Can't thaw game in %s") % scanner.token)
5570 game = pickle.load(fp)
5575 # I used <http://www.memory-alpha.org> to find planets
5576 # with references in ST:TOS. Earth and the Alpha Centauri
5577 # Colony have been omitted.
5579 # Some planets marked Class G and P here will be displayed as class M
5580 # because of the way planets are generated. This is a known bug.
5583 _("Andoria (Fesoan)"), # several episodes
5584 _("Tellar Prime (Miracht)"), # TOS: "Journey to Babel"
5585 _("Vulcan (T'Khasi)"), # many episodes
5586 _("Medusa"), # TOS: "Is There in Truth No Beauty?"
5587 _("Argelius II (Nelphia)"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5588 _("Ardana"), # TOS: "The Cloud Minders"
5589 _("Catulla (Cendo-Prae)"), # TOS: "The Way to Eden"
5590 _("Gideon"), # TOS: "The Mark of Gideon"
5591 _("Aldebaran III"), # TOS: "The Deadly Years"
5592 _("Alpha Majoris I"), # TOS: "Wolf in the Fold"
5593 _("Altair IV"), # TOS: "Amok Time
5594 _("Ariannus"), # TOS: "Let That Be Your Last Battlefield"
5595 _("Benecia"), # TOS: "The Conscience of the King"
5596 _("Beta Niobe I (Sarpeidon)"), # TOS: "All Our Yesterdays"
5597 _("Alpha Carinae II"), # TOS: "The Ultimate Computer"
5598 _("Capella IV (Kohath)"), # TOS: "Friday's Child" (Class G)
5599 _("Daran V"), # TOS: "For the World is Hollow and I Have Touched the Sky"
5600 _("Deneb II"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5601 _("Eminiar VII"), # TOS: "A Taste of Armageddon"
5602 _("Gamma Canaris IV"), # TOS: "Metamorphosis"
5603 _("Gamma Tranguli VI (Vaalel)"), # TOS: "The Apple"
5604 _("Ingraham B"), # TOS: "Operation: Annihilate"
5605 _("Janus IV"), # TOS: "The Devil in the Dark"
5606 _("Makus III"), # TOS: "The Galileo Seven"
5607 _("Marcos XII"), # TOS: "And the Children Shall Lead",
5608 _("Omega IV"), # TOS: "The Omega Glory"
5609 _("Regulus V"), # TOS: "Amok Time
5610 _("Deneva"), # TOS: "Operation -- Annihilate!"
5611 # Worlds from BSD Trek
5612 _("Rigel II"), # TOS: "Shore Leave" ("III" in BSD)
5613 _("Beta III"), # TOS: "The Return of the Archons"
5614 _("Triacus"), # TOS: "And the Children Shall Lead",
5615 _("Exo III"), # TOS: "What Are Little Girls Made Of?" (Class P)
5617 # _("Hansen's Planet"), # TOS: "The Galileo Seven"
5618 # _("Taurus IV"), # TOS: "The Galileo Seven" (class G)
5619 # _("Antos IV (Doraphane)"), # TOS: "Whom Gods Destroy", "Who Mourns for Adonais?"
5620 # _("Izar"), # TOS: "Whom Gods Destroy"
5621 # _("Tiburon"), # TOS: "The Way to Eden"
5622 # _("Merak II"), # TOS: "The Cloud Minders"
5623 # _("Coridan (Desotriana)"), # TOS: "Journey to Babel"
5624 # _("Iotia"), # TOS: "A Piece of the Action"
5628 _("S. R. Sensors"), \
5629 _("L. R. Sensors"), \
5631 _("Photon Tubes"), \
5632 _("Life Support"), \
5633 _("Warp Engines"), \
5634 _("Impulse Engines"), \
5636 _("Subspace Radio"), \
5637 _("Shuttle Craft"), \
5639 _("Navigation System"), \
5641 _("Shield Control"), \
5644 _("Cloaking Device"), \
5648 "Prepare to play, set up cosmos."
5650 # Decide how many of everything
5652 return # frozen game
5653 # Prepare the Enterprise
5654 game.alldone = game.gamewon = game.shldchg = game.shldup = False
5656 game.state.crew = FULLCREW
5657 game.energy = game.inenrg = 5000.0
5658 game.shield = game.inshld = 2500.0
5661 game.quadrant = randplace(GALSIZE)
5662 game.sector = randplace(QUADSIZE)
5663 game.torps = game.intorps = 10
5664 game.nprobes = randrange(2, 5)
5666 for i in range(NDEVICES):
5667 game.damage[i] = 0.0
5668 # Set up assorted game parameters
5669 game.battle = Coord()
5670 game.state.date = game.indate = 100.0 * randreal(20, 51)
5671 game.nkinks = game.nhelp = game.casual = game.abandoned = 0
5672 game.iscate = game.resting = game.imine = game.icrystl = game.icraft = False
5673 game.isatb = game.state.nplankl = 0
5674 game.state.starkl = game.state.basekl = game.state.nworldkl = 0
5675 game.iscraft = "onship"
5680 game.state.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
5682 game.state.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
5684 game.state.planets = [] # Planet information
5685 game.state.baseq = [] # Base quadrant coordinates
5686 game.state.kcmdr = [] # Commander quadrant coordinates
5687 game.statekscmdr = Coord() # Supercommander quadrant coordinates
5689 # Starchart is functional but we've never seen it
5690 game.lastchart = FOREVER
5691 # Put stars in the galaxy
5693 for i in range(GALSIZE):
5694 for j in range(GALSIZE):
5695 # Can't have more stars per quadrant than fit in one decimal digit,
5696 # if we do the chart representation will break.
5697 k = randrange(1, min(10, QUADSIZE**2/10))
5699 game.state.galaxy[i][j].stars = k
5700 # Locate star bases in galaxy
5702 prout("=== Allocating %d bases" % game.inbase)
5703 for i in range(game.inbase):
5706 w = randplace(GALSIZE)
5707 if not game.state.galaxy[w.i][w.j].starbase:
5710 # C version: for (j = i-1; j > 0; j--)
5711 # so it did them in the opposite order.
5712 for j in range(1, i):
5713 # Improved placement algorithm to spread out bases
5714 distq = (w - game.state.baseq[j]).distance()
5715 if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75):
5718 prout("=== Abandoning base #%d at %s" % (i, w))
5720 elif distq < 6.0 * (BASEMAX+1-game.inbase):
5722 prout("=== Saving base #%d, close to #%d" % (i, j))
5726 prout("=== Placing base #%d in quadrant %s" % (i, w))
5727 game.state.baseq.append(w)
5728 game.state.galaxy[w.i][w.j].starbase = game.state.chart[w.i][w.j].starbase = True
5729 # Position ordinary Klingon Battle Cruisers
5731 klumper = 0.25*game.skill*(9.0-game.length)+1.0
5732 if klumper > MAXKLQUAD:
5736 klump = (1.0 - r*r)*klumper
5741 w = randplace(GALSIZE)
5742 if not game.state.galaxy[w.i][w.j].supernova and \
5743 game.state.galaxy[w.i][w.j].klingons + klump <= MAXKLQUAD:
5745 game.state.galaxy[w.i][w.j].klingons += int(klump)
5748 # Position Klingon Commander Ships
5749 for i in range(game.incom):
5751 w = randplace(GALSIZE)
5752 if not welcoming(w) or w in game.state.kcmdr:
5754 if (game.state.galaxy[w.i][w.j].klingons or withprob(0.25)):
5756 game.state.galaxy[w.i][w.j].klingons += 1
5757 game.state.kcmdr.append(w)
5758 # Locate planets in galaxy
5759 for i in range(game.inplan):
5761 w = randplace(GALSIZE)
5762 if game.state.galaxy[w.i][w.j].planet is None:
5766 new.crystals = "absent"
5767 if (game.options & OPTION_WORLDS) and i < NINHAB:
5768 new.pclass = "M" # All inhabited planets are class M
5769 new.crystals = "absent"
5771 new.name = systnames[i]
5772 new.inhabited = True
5774 new.pclass = ("M", "N", "O")[randrange(0, 3)]
5776 new.crystals = "present"
5777 new.known = "unknown"
5778 new.inhabited = False
5779 game.state.galaxy[w.i][w.j].planet = new
5780 game.state.planets.append(new)
5782 for i in range(game.state.nromrem):
5783 w = randplace(GALSIZE)
5784 game.state.galaxy[w.i][w.j].romulans += 1
5785 # Place the Super-Commander if needed
5786 if game.state.nscrem > 0:
5788 w = randplace(GALSIZE)
5791 game.state.kscmdr = w
5792 game.state.galaxy[w.i][w.j].klingons += 1
5793 # Initialize times for extraneous events
5794 schedule(FSNOVA, expran(0.5 * game.intime))
5795 schedule(FTBEAM, expran(1.5 * (game.intime / len(game.state.kcmdr))))
5796 schedule(FSNAP, randreal(1.0, 2.0)) # Force an early snapshot
5797 schedule(FBATTAK, expran(0.3*game.intime))
5799 if game.state.nscrem:
5800 schedule(FSCMOVE, 0.2777)
5805 if (game.options & OPTION_WORLDS) and game.skill >= SKILL_GOOD:
5806 schedule(FDISTR, expran(1.0 + game.intime))
5811 # Place thing (in tournament game, we don't want one!)
5812 # New in SST2K: never place the Thing near a starbase.
5813 # This makes sense and avoids a special case in the old code.
5815 if game.tourn is None:
5817 thing = randplace(GALSIZE)
5818 if thing not in game.state.baseq:
5821 game.state.snap = False
5822 if game.skill == SKILL_NOVICE:
5823 prout(_("It is stardate %d. The Federation is being attacked by") % int(game.state.date))
5824 prout(_("a deadly Klingon invasion force. As captain of the United"))
5825 prout(_("Starship U.S.S. Enterprise, it is your mission to seek out"))
5826 prout(_("and destroy this invasion force of %d battle cruisers.") % ((game.inkling + game.incom + game.inscom)))
5827 prout(_("You have an initial allotment of %d stardates to complete") % int(game.intime))
5828 prout(_("your mission. As you proceed you may be given more time."))
5830 prout(_("You will have %d supporting starbases.") % (game.inbase))
5831 proutn(_("Starbase locations- "))
5833 prout(_("Stardate %d.") % int(game.state.date))
5835 prout(_("%d Klingons.") % (game.inkling + game.incom + game.inscom))
5836 prout(_("An unknown number of Romulans."))
5837 if game.state.nscrem:
5838 prout(_("And one (GULP) Super-Commander."))
5839 prout(_("%d stardates.") % int(game.intime))
5840 proutn(_("%d starbases in ") % game.inbase)
5841 for i in range(game.inbase):
5842 proutn(repr(game.state.baseq[i]))
5845 proutn(_("The Enterprise is currently in Quadrant %s") % game.quadrant)
5846 proutn(_(" Sector %s") % game.sector)
5848 prout(_("Good Luck!"))
5849 if game.state.nscrem:
5850 prout(_(" YOU'LL NEED IT."))
5853 setwnd(message_window)
5855 if len(game.enemies) - (thing == game.quadrant) - (game.tholian != None):
5857 if game.neutz: # bad luck to start in a Romulan Neutral Zone
5858 attack(torps_ok=False)
5861 "Choose your game type."
5863 game.tourn = game.length = 0
5865 game.skill = SKILL_NONE
5866 # Do not chew here, we want to use command-line tokens
5867 if not scanner.inqueue: # Can start with command line options
5868 proutn(_("Would you like a regular, tournament, or saved game? "))
5870 if scanner.sees("tournament"):
5871 while scanner.nexttok() == "IHEOL":
5872 proutn(_("Type in tournament number-"))
5873 if scanner.real == 0:
5875 continue # We don't want a blank entry
5876 game.tourn = int(round(scanner.real))
5877 random.seed(scanner.real)
5879 logfp.write("# random.seed(%d)\n" % scanner.real)
5881 if scanner.sees("saved") or scanner.sees("frozen"):
5885 if game.passwd is None:
5887 if not game.alldone:
5888 game.thawed = True # No plaque if not finished
5892 if scanner.sees("regular"):
5894 proutn(_("What is \"%s\"? ") % scanner.token)
5896 while game.length==0 or game.skill==SKILL_NONE:
5897 if scanner.nexttok() == "IHALPHA":
5898 if scanner.sees("short"):
5900 elif scanner.sees("medium"):
5902 elif scanner.sees("long"):
5904 elif scanner.sees("novice"):
5905 game.skill = SKILL_NOVICE
5906 elif scanner.sees("fair"):
5907 game.skill = SKILL_FAIR
5908 elif scanner.sees("good"):
5909 game.skill = SKILL_GOOD
5910 elif scanner.sees("expert"):
5911 game.skill = SKILL_EXPERT
5912 elif scanner.sees("emeritus"):
5913 game.skill = SKILL_EMERITUS
5915 proutn(_("What is \""))
5916 proutn(scanner.token)
5921 proutn(_("Would you like a Short, Medium, or Long game? "))
5922 elif game.skill == SKILL_NONE:
5923 proutn(_("Are you a Novice, Fair, Good, Expert, or Emeritus player? "))
5924 # Choose game options -- added by ESR for SST2K
5925 if scanner.nexttok() != "IHALPHA":
5927 proutn(_("Choose your game style (plain, almy, fancy or just press enter): "))
5929 if scanner.sees("plain"):
5930 # Approximates the UT FORTRAN version.
5931 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)
5932 game.options |= OPTION_PLAIN
5933 elif scanner.sees("almy"):
5934 # Approximates Tom Almy's version.
5935 game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS | OPTION_COLOR)
5936 game.options |= OPTION_ALMY
5937 elif scanner.sees("fancy") or scanner.sees("\n"):
5939 elif len(scanner.token):
5940 proutn(_("What is \"%s\"?") % scanner.token)
5942 if game.passwd == "debug":
5944 prout("=== Debug mode enabled.")
5945 # Use parameters to generate initial values of things
5946 game.damfac = 0.5 * game.skill
5947 game.inbase = randrange(BASEMIN, BASEMAX+1)
5949 if game.options & OPTION_PLANETS:
5950 game.inplan += randrange(MAXUNINHAB/2, MAXUNINHAB+1)
5951 if game.options & OPTION_WORLDS:
5952 game.inplan += int(NINHAB)
5953 game.state.nromrem = game.inrom = randrange(2 * game.skill)
5954 game.state.nscrem = game.inscom = (game.skill > SKILL_FAIR)
5955 game.state.remtime = 7.0 * game.length
5956 game.intime = game.state.remtime
5957 game.state.remkl = game.inkling = int(2.0*game.intime*((game.skill+1 - 2*randreal())*game.skill*0.1+.15))
5958 game.incom = min(MINCMDR, int(game.skill + 0.0625*game.inkling*randreal()))
5959 game.state.remres = (game.inkling+4*game.incom)*game.intime
5960 game.inresor = game.state.remres
5961 if game.inkling > 50:
5965 def dropin(iquad=None):
5966 "Drop a feature on a random dot in the current quadrant."
5968 w = randplace(QUADSIZE)
5969 if game.quad[w.i][w.j] == '.':
5971 if iquad is not None:
5972 game.quad[w.i][w.j] = iquad
5976 "Update our alert status."
5977 game.condition = "green"
5978 if game.energy < 1000.0:
5979 game.condition = "yellow"
5980 if game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons or game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans:
5981 game.condition = "red"
5983 game.condition="dead"
5986 "Drop new Klingon into current quadrant."
5987 return Enemy('K', loc=dropin(), power=randreal(300,450)+25.0*game.skill)
5990 "Sort enemies by distance so 'nearest' is meaningful."
5991 game.enemies.sort(key=lambda x: x.kdist)
5994 "Set up a new state of quadrant, for when we enter or re-enter it."
5997 game.neutz = game.inorbit = game.landed = False
5998 game.ientesc = game.iseenit = game.isviolreported = False
5999 # Create a blank quadrant
6000 game.quad = fill2d(QUADSIZE, lambda i, j: '.')
6002 # Attempt to escape Super-commander, so tbeam back!
6005 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
6006 # cope with supernova
6009 game.klhere = q.klingons
6010 game.irhere = q.romulans
6012 game.quad[game.sector.i][game.sector.j] = game.ship
6015 # Position ordinary Klingons
6016 for _i in range(game.klhere):
6018 # If we need a commander, promote a Klingon
6019 for cmdr in game.state.kcmdr:
6020 if cmdr == game.quadrant:
6021 e = game.enemies[game.klhere-1]
6022 game.quad[e.location.i][e.location.j] = 'C'
6023 e.power = randreal(950,1350) + 50.0*game.skill
6025 # If we need a super-commander, promote a Klingon
6026 if game.quadrant == game.state.kscmdr:
6028 game.quad[e.location.i][e.location.j] = 'S'
6029 e.power = randreal(1175.0, 1575.0) + 125.0*game.skill
6030 game.iscate = (game.state.remkl > 1)
6031 # Put in Romulans if needed
6032 for _i in range(q.romulans):
6033 Enemy('R', loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill)
6034 # If quadrant needs a starbase, put it in
6036 game.base = dropin('B')
6037 # If quadrant needs a planet, put it in
6039 game.iplnet = q.planet
6040 if not q.planet.inhabited:
6041 game.plnet = dropin('P')
6043 game.plnet = dropin('@')
6044 # Check for condition
6047 if game.irhere > 0 and game.klhere == 0:
6049 if not damaged(DRADIO):
6051 prout(_("LT. Uhura- \"Captain, an urgent message."))
6052 prout(_(" I'll put it on audio.\" CLICK"))
6054 prout(_("INTRUDER! YOU HAVE VIOLATED THE ROMULAN NEUTRAL ZONE."))
6055 prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!"))
6056 # Put in THING if needed
6057 if thing == game.quadrant:
6058 Enemy(etype='?', loc=dropin(),
6059 power=randreal(6000,6500.0)+250.0*game.skill)
6060 if not damaged(DSRSENS):
6062 prout(_("Mr. Spock- \"Captain, this is most unusual."))
6063 prout(_(" Please examine your short-range scan.\""))
6064 # Decide if quadrant needs a Tholian; lighten up if skill is low
6065 if game.options & OPTION_THOLIAN:
6066 if (game.skill < SKILL_GOOD and withprob(0.02)) or \
6067 (game.skill == SKILL_GOOD and withprob(0.05)) or \
6068 (game.skill > SKILL_GOOD and withprob(0.08)):
6071 w.i = withprob(0.5) * (QUADSIZE-1)
6072 w.j = withprob(0.5) * (QUADSIZE-1)
6073 if game.quad[w.i][w.j] == '.':
6075 game.tholian = Enemy(etype='T', loc=w,
6076 power=randrange(100, 500) + 25.0*game.skill)
6077 # Reserve unoccupied corners
6078 if game.quad[0][0]=='.':
6079 game.quad[0][0] = 'X'
6080 if game.quad[0][QUADSIZE-1]=='.':
6081 game.quad[0][QUADSIZE-1] = 'X'
6082 if game.quad[QUADSIZE-1][0]=='.':
6083 game.quad[QUADSIZE-1][0] = 'X'
6084 if game.quad[QUADSIZE-1][QUADSIZE-1]=='.':
6085 game.quad[QUADSIZE-1][QUADSIZE-1] = 'X'
6087 # And finally the stars
6088 for _i in range(q.stars):
6090 # Put in a few black holes
6091 for _i in range(1, 3+1):
6094 # Take out X's in corners if Tholian present
6096 if game.quad[0][0]=='X':
6097 game.quad[0][0] = '.'
6098 if game.quad[0][QUADSIZE-1]=='X':
6099 game.quad[0][QUADSIZE-1] = '.'
6100 if game.quad[QUADSIZE-1][0]=='X':
6101 game.quad[QUADSIZE-1][0] = '.'
6102 if game.quad[QUADSIZE-1][QUADSIZE-1]=='X':
6103 game.quad[QUADSIZE-1][QUADSIZE-1] = '.'
6104 # This should guarantee that replay games don't lose info about the chart
6105 if (game.options & OPTION_AUTOSCAN) or replayfp:
6109 "Set the self-destruct password."
6110 if game.options & OPTION_PLAIN:
6113 proutn(_("Please type in a secret password- "))
6115 game.passwd = scanner.token
6116 if game.passwd != None:
6120 game.passwd += chr(ord('a')+randrange(26))
6121 game.passwd += chr(ord('a')+randrange(26))
6122 game.passwd += chr(ord('a')+randrange(26))
6124 # Code from sst.c begins here
6127 ("SRSCAN", OPTION_TTY),
6128 ("STATUS", OPTION_TTY),
6129 ("REQUEST", OPTION_TTY),
6130 ("LRSCAN", OPTION_TTY),
6142 ("SENSORS", OPTION_PLANETS),
6143 ("ORBIT", OPTION_PLANETS),
6144 ("TRANSPORT", OPTION_PLANETS),
6145 ("MINE", OPTION_PLANETS),
6146 ("CRYSTALS", OPTION_PLANETS),
6147 ("SHUTTLE", OPTION_PLANETS),
6148 ("PLANETS", OPTION_PLANETS),
6153 ("PROBE", OPTION_PROBE),
6155 ("FREEZE", 0), # Synonym for SAVE
6159 ("CAPTURE", OPTION_CAPTURE),
6160 ("CLOAK", OPTION_CLOAK),
6163 ("SOS", 0), # Synonym for MAYDAY
6164 ("CALL", 0), # Synonym for MAYDAY
6173 "Generate a list of legal commands."
6174 prout(_("LEGAL COMMANDS ARE:"))
6176 for (key, opt) in commands:
6177 if not opt or (opt & game.options):
6178 proutn("%-12s " % key)
6180 if emitted % 5 == 4:
6185 "Browse on-line help."
6186 key = scanner.nexttok()
6189 setwnd(prompt_window)
6190 proutn(_("Help on what command? "))
6191 key = scanner.nexttok()
6192 setwnd(message_window)
6195 cmds = [x[0] for x in commands]
6196 if scanner.token.upper() in cmds or scanner.token.upper() == "ABBREV":
6203 cmd = scanner.token.upper()
6204 for directory in docpath:
6206 fp = open(os.path.join(directory, "sst.doc"), "r")
6211 prout(_("Spock- \"Captain, that information is missing from the"))
6212 prout(_(" computer. You need to find sst.doc and put it somewhere"))
6213 proutn(_(" in these directories: %s") % ":".join(docpath))
6215 # This used to continue: "You need to find SST.DOC and put
6216 # it in the current directory."
6219 linebuf = fp.readline()
6221 prout(_("Spock- \"Captain, there is no information on that command.\""))
6224 if linebuf[0] == '%' and linebuf[1] == '%' and linebuf[2] == ' ':
6225 linebuf = linebuf[3:].strip()
6226 if cmd.upper() == linebuf:
6229 prout(_("Spock- \"Captain, I've found the following information:\""))
6232 linebuf = fp.readline()
6233 if "******" in linebuf:
6239 "Command-interpretation loop."
6241 if game.irhere and game.state.date >= ALGERON and not game.isviolreported and game.iscloaked:
6242 prout(_("The Romulan ship discovers you are breaking the Treaty of Algeron!"))
6244 game.isviolreported = True
6245 while True: # command loop
6247 while True: # get a command
6249 game.optime = game.justin = False
6251 setwnd(prompt_window)
6254 if scanner.nexttok() == "IHEOL":
6255 if game.options & OPTION_CURSES:
6258 elif scanner.token == "":
6262 setwnd(message_window)
6264 abandon_passed = False
6265 cmd = "" # Force cmd to persist after loop
6266 opt = 0 # Force opt to persist after loop
6267 for (cmd, opt) in commands:
6268 # commands after ABANDON cannot be abbreviated
6269 if cmd == "ABANDON":
6270 abandon_passed = True
6271 if cmd == scanner.token.upper() or (not abandon_passed \
6272 and cmd.startswith(scanner.token.upper())):
6277 elif opt and not (opt & game.options):
6281 if game.options & OPTION_CURSES:
6282 prout("COMMAND> %s" % cmd)
6283 if cmd == "SRSCAN": # srscan
6285 elif cmd == "STATUS": # status
6287 elif cmd == "REQUEST": # status request
6289 elif cmd == "LRSCAN": # long range scan
6290 lrscan(silent=False)
6291 elif cmd == "PHASERS": # phasers
6296 elif cmd in ("TORPEDO", "PHOTONS"): # photon torpedos
6301 elif cmd == "MOVE": # move under warp
6302 warp(wcourse=None, involuntary=False)
6303 elif cmd == "SHIELDS": # shields
6304 doshield(shraise=False)
6307 game.shldchg = False
6308 elif cmd == "DOCK": # dock at starbase
6311 attack(torps_ok=False)
6312 elif cmd == "DAMAGES": # damage reports
6314 elif cmd == "CHART": # chart
6316 elif cmd == "IMPULSE": # impulse
6318 elif cmd == "REST": # rest
6322 elif cmd == "WARP": # warp
6324 elif cmd == "SENSORS": # sensors
6326 elif cmd == "ORBIT": # orbit
6330 elif cmd == "TRANSPORT": # transport "beam"
6332 elif cmd == "MINE": # mine
6336 elif cmd == "CRYSTALS": # crystals
6340 elif cmd == "SHUTTLE": # shuttle
6344 elif cmd == "PLANETS": # Planet list
6346 elif cmd == "REPORT": # Game Report
6348 elif cmd == "COMPUTER": # use COMPUTER!
6350 elif cmd == "COMMANDS":
6352 elif cmd == "EMEXIT": # Emergency exit
6353 clrscr() # Hide screen
6354 freeze(True) # forced save
6355 raise SystemExit(1) # And quick exit
6356 elif cmd == "PROBE":
6357 probe() # Launch probe
6360 elif cmd == "ABANDON": # Abandon Ship
6362 elif cmd == "DESTRUCT": # Self Destruct
6364 elif cmd == "SAVE": # Save Game
6367 if game.skill > SKILL_GOOD:
6368 prout(_("WARNING--Saved games produce no plaques!"))
6369 elif cmd == "DEATHRAY": # Try a desparation measure
6373 elif cmd == "CAPTURE":
6375 elif cmd == "CLOAK":
6377 elif cmd == "DEBUGCMD": # What do we want for debug???
6379 elif cmd == "MAYDAY": # Call for help
6384 game.alldone = True # quit the game
6387 elif cmd == "SCORE":
6388 score() # see current score
6389 elif cmd == "CURSES":
6390 game.options |= (OPTION_CURSES | OPTION_COLOR)
6394 break # Game has ended
6395 if game.optime != 0.0:
6398 break # Events did us in
6399 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6402 if hitme and not game.justin:
6403 attack(torps_ok=True)
6406 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6417 "Emit the name of an enemy or feature."
6418 if ch == 'R': s = _("Romulan")
6419 elif ch == 'K': s = _("Klingon")
6420 elif ch == 'C': s = _("Commander")
6421 elif ch == 'S': s = _("Super-commander")
6422 elif ch == '*': s = _("Star")
6423 elif ch == 'P': s = _("Planet")
6424 elif ch == 'B': s = _("Starbase")
6425 elif ch == ' ': s = _("Black hole")
6426 elif ch == 'T': s = _("Tholian")
6427 elif ch == '#': s = _("Tholian web")
6428 elif ch == '?': s = _("Stranger")
6429 elif ch == '@': s = _("Inhabited World")
6430 else: s = "Unknown??"
6433 def crmena(loud, enemy, loctype, w):
6434 "Emit the name of an enemy and his location."
6438 buf += cramen(enemy) + _(" at ")
6439 if loctype == "quadrant":
6440 buf += _("Quadrant ")
6441 elif loctype == "sector":
6443 return buf + repr(w)
6446 "Emit our ship name."
6447 return{'E':_("Enterprise"),'F':_("Faerie Queene")}.get(game.ship,"Ship???")
6450 "Emit a line of stars"
6451 prouts("******************************************************")
6455 return -avrage*math.log(1e-7 + randreal())
6457 def randplace(size):
6458 "Choose a random location."
6460 w.i = randrange(size)
6461 w.j = randrange(size)
6471 # Get a token from the user
6474 # Fill the token quue if nothing here
6475 while not self.inqueue:
6477 if curwnd==prompt_window:
6479 setwnd(message_window)
6486 self.inqueue = sline.lstrip().split() + ["\n"]
6487 # From here on in it's all looking at the queue
6488 self.token = self.inqueue.pop(0)
6489 if self.token == "\n":
6493 self.real = float(self.token)
6494 self.type = "IHREAL"
6499 self.token = self.token.lower()
6500 self.type = "IHALPHA"
6503 def append(self, tok):
6504 self.inqueue.append(tok)
6505 def push(self, tok):
6506 self.inqueue.insert(0, tok)
6510 # Demand input for next scan
6512 self.real = self.token = None
6514 # compares s to item and returns true if it matches to the length of s
6515 return s.startswith(self.token)
6517 # Round token value to nearest integer
6518 return int(round(self.real))
6522 if self.type != "IHREAL":
6527 if self.type != "IHREAL":
6533 return "<sstcanner: token=%s, type=%s, queue=%s>" % (self.token, self.type, self.inqueue)
6536 "Yes-or-no confirmation."
6540 if scanner.token == 'y':
6542 if scanner.token == 'n':
6545 proutn(_("Please answer with \"y\" or \"n\": "))
6548 "Complain about unparseable input."
6551 prout(_("Beg your pardon, Captain?"))
6554 "Access to the internals for debugging."
6555 proutn("Reset levels? ")
6557 if game.energy < game.inenrg:
6558 game.energy = game.inenrg
6559 game.shield = game.inshld
6560 game.torps = game.intorps
6561 game.lsupres = game.inlsr
6562 proutn("Reset damage? ")
6564 for i in range(NDEVICES):
6565 if game.damage[i] > 0.0:
6566 game.damage[i] = 0.0
6567 proutn("Toggle debug flag? ")
6569 game.idebug = not game.idebug
6571 prout("Debug output ON")
6573 prout("Debug output OFF")
6574 proutn("Cause selective damage? ")
6576 for i in range(NDEVICES):
6577 proutn("Kill %s?" % device[i])
6579 key = scanner.nexttok()
6580 if key == "IHALPHA" and scanner.sees("y"):
6581 game.damage[i] = 10.0
6582 proutn("Examine/change events? ")
6587 FSNOVA: "Supernova ",
6590 FBATTAK: "Base Attack ",
6591 FCDBAS: "Base Destroy ",
6592 FSCMOVE: "SC Move ",
6593 FSCDBAS: "SC Base Destroy ",
6594 FDSPROB: "Probe Move ",
6595 FDISTR: "Distress Call ",
6596 FENSLV: "Enslavement ",
6597 FREPRO: "Klingon Build ",
6599 for i in range(1, NEVENTS):
6602 proutn("%.2f" % (scheduled(i)-game.state.date))
6603 if i == FENSLV or i == FREPRO:
6605 proutn(" in %s" % ev.quadrant)
6610 key = scanner.nexttok()
6614 elif key == "IHREAL":
6615 ev = schedule(i, scanner.real)
6616 if i == FENSLV or i == FREPRO:
6618 proutn("In quadrant- ")
6619 key = scanner.nexttok()
6620 # "IHEOL" says to leave coordinates as they are
6623 prout("Event %d canceled, no x coordinate." % (i))
6626 w.i = int(round(scanner.real))
6627 key = scanner.nexttok()
6629 prout("Event %d canceled, no y coordinate." % (i))
6632 w.j = int(round(scanner.real))
6635 proutn("Induce supernova here? ")
6637 game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova = True
6640 if __name__ == '__main__':
6642 #global line, thing, game
6646 game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY)
6647 if os.getenv("TERM"):
6648 game.options |= OPTION_CURSES
6650 game.options |= OPTION_TTY
6651 seed = int(time.time())
6652 (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:txV")
6654 for (switch, val) in options:
6657 replayfp = open(val, "r")
6659 sys.stderr.write("sst: can't open replay file %s\n" % val)
6662 line = replayfp.readline().strip()
6663 (leader, __, seed) = line.split()
6665 sys.stderr.write("sst2k: seed set to %s\n" % seed)
6666 line = replayfp.readline().strip()
6667 arguments += line.split()[2:]
6670 sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
6672 game.options |= OPTION_TTY
6673 game.options &=~ OPTION_CURSES
6674 elif switch == '-s':
6676 elif switch == '-t':
6677 game.options |= OPTION_TTY
6678 game.options &=~ OPTION_CURSES
6679 elif switch == '-x':
6681 elif switch == '-V':
6682 print("SST2K", version)
6685 sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n")
6687 # where to save the input in case of bugs
6688 if "TMPDIR" in os.environ:
6689 tmpdir = os.environ['TMPDIR']
6693 logfp = open(os.path.join(tmpdir, "sst-input.log"), "w")
6695 sys.stderr.write("sst: warning, can't open logfile\n")
6698 logfp.write("# seed %s\n" % seed)
6699 logfp.write("# options %s\n" % " ".join(arguments))
6700 logfp.write("# SST2K version %s\n" % version)
6701 logfp.write("# recorded by %s@%s on %s\n" % \
6702 (getpass.getuser(),socket.gethostname(),time.ctime()))
6704 scanner = sstscanner()
6705 for arg in arguments:
6709 while True: # Play a game
6710 setwnd(fullscreen_window)
6716 game.alldone = False
6724 if game.tourn and game.alldone:
6725 proutn(_("Do you want your score recorded?"))
6731 proutn(_("Do you want to play again? "))
6735 prout(_("May the Great Bird of the Galaxy roost upon your home planet."))
6739 except KeyboardInterrupt: